diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index dd33535c2562a..fc46fa24f257f 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -272,6 +272,7 @@ enabled: - x-pack/test/functional/config.firefox.js - x-pack/test/functional/config.upgrade_assistant.ts - x-pack/test/functional_cloud/config.ts + - x-pack/test/functional_solution_sidenav/config.ts - x-pack/test/kubernetes_security/basic/config.ts - x-pack/test/licensing_plugin/config.public.ts - x-pack/test/licensing_plugin/config.ts diff --git a/.buildkite/pipeline-resource-definitions/kibana-codeql.yml b/.buildkite/pipeline-resource-definitions/kibana-codeql.yml new file mode 100644 index 0000000000000..3da2c9137c4e0 --- /dev/null +++ b/.buildkite/pipeline-resource-definitions/kibana-codeql.yml @@ -0,0 +1,34 @@ +# yaml-language-server: $schema=https://gist.githubusercontent.com/elasticmachine/988b80dae436cafea07d9a4a460a011d/raw/rre.schema.json +apiVersion: backstage.io/v1alpha1 +kind: Resource +metadata: + name: bk-kibana-codeql + description: Run CodeQL + links: + - title: Pipeline link + url: https://buildkite.com/elastic/kibana-codeql +spec: + type: buildkite-pipeline + owner: group:kibana-operations + system: buildkite + implementation: + apiVersion: buildkite.elastic.dev/v1 + kind: Pipeline + metadata: + name: kibana / codeql + description: Run CodeQL + spec: + env: + SLACK_NOTIFICATIONS_CHANNEL: "#kibana-operations-alerts" + ELASTIC_SLACK_NOTIFICATIONS_ENABLED: "false" + repository: elastic/kibana + branch_configuration: main + default_branch: main + pipeline_file: ".buildkite/pipelines/codeql/codeql.yml" + provider_settings: + trigger_mode: none + teams: + kibana-operations: + access_level: MANAGE_BUILD_AND_READ + everyone: + access_level: READ_ONLY diff --git a/.buildkite/pipeline-resource-definitions/locations.yml b/.buildkite/pipeline-resource-definitions/locations.yml index 45a155d21280e..5144982a0627d 100644 --- a/.buildkite/pipeline-resource-definitions/locations.yml +++ b/.buildkite/pipeline-resource-definitions/locations.yml @@ -44,3 +44,4 @@ spec: - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/security-solution-quality-gate/kibana-serverless-security-solution-quality-gate-rule-management.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-pointer-compression.yml + - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-codeql.yml diff --git a/.buildkite/pipelines/codeql/codeql.yml b/.buildkite/pipelines/codeql/codeql.yml new file mode 100644 index 0000000000000..52fc4f910713a --- /dev/null +++ b/.buildkite/pipelines/codeql/codeql.yml @@ -0,0 +1,2 @@ +steps: + - command: echo "Placeholder" diff --git a/.buildkite/scripts/steps/checks/native_modules.sh b/.buildkite/scripts/steps/checks/native_modules.sh new file mode 100755 index 0000000000000..e7f585de97d15 --- /dev/null +++ b/.buildkite/scripts/steps/checks/native_modules.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +echo --- Check Production Native Node Modules +node scripts/check_prod_native_modules diff --git a/.buildkite/scripts/steps/checks/quick_checks.txt b/.buildkite/scripts/steps/checks/quick_checks.txt index 028aa47ff9567..e0196950b4a75 100644 --- a/.buildkite/scripts/steps/checks/quick_checks.txt +++ b/.buildkite/scripts/steps/checks/quick_checks.txt @@ -17,3 +17,4 @@ .buildkite/scripts/steps/checks/yarn_deduplicate.sh .buildkite/scripts/steps/checks/prettier_topology.sh .buildkite/scripts/steps/checks/renovate.sh +.buildkite/scripts/steps/checks/native_modules.sh diff --git a/.devcontainer/.env.template b/.devcontainer/.env.template new file mode 100644 index 0000000000000..3ca02c49bfa9c --- /dev/null +++ b/.devcontainer/.env.template @@ -0,0 +1,4 @@ +# /bin/bash or /bin/zsh (oh-my-zsh is installed by default as well) +SHELL=/bin/bash +# Switch to 1 to enable FIPS environment, any other value to disable +FIPS=0 diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000000..539e23a4a3a31 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,69 @@ +FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 + +ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8 +ENV HOME=/home/vscode +ENV NVM_DIR=${HOME}/nvm +ENV NVM_VERSION=v0.39.1 +ENV KBN_DIR=/workspaces/kibana +ENV OPENSSL_PATH=${HOME}/openssl +# Only specific versions are FIPS certified. +ENV OPENSSL_VERSION='3.0.8' + +RUN apt-get update && apt-get install -y curl git zsh locales docker.io perl make gcc xvfb + +RUN locale-gen en_US.UTF-8 + +# Oh My Zsh setup +RUN if [ ! -d "$HOME/.oh-my-zsh" ]; then \ + sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"; \ + fi && \ + ZSH_CUSTOM=${ZSH_CUSTOM:-~/.oh-my-zsh/custom} && \ + if [ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]; then \ + git clone https://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions; \ + fi && \ + sed -i 's/plugins=(git)/plugins=(git ssh-agent npm docker zsh-autosuggestions)/' /home/vscode/.zshrc + +# Docker-in-Docker setup +RUN usermod -aG docker vscode + +# FIPS setup +# https://github.com/openssl/openssl/blob/openssl-3.0/README-FIPS.md +# https://www.openssl.org/docs/man3.0/man7/fips_module.html +WORKDIR ${HOME} + +RUN set -e ; \ + mkdir -p "${OPENSSL_PATH}"; \ + curl --retry 8 -S -L -O "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" ; \ + curl --retry 8 -S -L -O "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz.sha256" ; \ + echo "$(cat openssl-${OPENSSL_VERSION}.tar.gz.sha256) openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c ; \ + tar -zxf "openssl-${OPENSSL_VERSION}.tar.gz" ; \ + rm -rf openssl-${OPENSSL_VERSION}.tar* ; \ + cd "${OPENSSL_PATH}-${OPENSSL_VERSION}" ; \ + ./Configure --prefix="${OPENSSL_PATH}" --openssldir="${OPENSSL_PATH}/ssl" --libdir="${OPENSSL_PATH}/lib" shared -Wl,-rpath,${OPENSSL_PATH}/lib enable-fips; \ + make -j $(nproc) > /dev/null ; \ + make install > /dev/null ; \ + rm -rf "${OPENSSL_PATH}-${OPENSSL_VERSION}" ; \ + chown -R 1000:1000 "${OPENSSL_PATH}"; + +WORKDIR ${KBN_DIR} + +# Node and NVM setup +COPY .node-version /tmp/ +RUN mkdir -p $NVM_DIR && \ + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash && \ + . "$NVM_DIR/nvm.sh" && \ + NODE_VERSION=$(cat /tmp/.node-version) && \ + nvm install ${NODE_VERSION} && \ + nvm use ${NODE_VERSION} && \ + nvm alias default ${NODE_VERSION} && \ + npm install -g yarn && \ + echo "source $NVM_DIR/nvm.sh" >> ${HOME}/.bashrc && \ + echo "source $NVM_DIR/nvm.sh" >> ${HOME}/.zshrc && \ + chown -R 1000:1000 "${HOME}/.npm" + +# Reload the env everytime a new shell is opened incase the .env file changed. +RUN echo "source $KBN_DIR/.devcontainer/scripts/env.sh" >> ${HOME}/.bashrc && \ + echo "source $KBN_DIR/.devcontainer/scripts/env.sh" >> ${HOME}/.zshrc + +# This is for documentation. Ports are exposed via devcontainer.json +EXPOSE 9200 5601 9229 9230 9231 diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000000000..835ce0f756499 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1 @@ +See the [dev docs](https://github.com/elastic/kibana/blob/main/dev_docs/getting_started/setting_up_a_development_env.mdx#using-the-kibana-dev-container-optional) for information on using the Kibana Dev Container. \ No newline at end of file diff --git a/.devcontainer/config/nodejs.cnf b/.devcontainer/config/nodejs.cnf new file mode 100644 index 0000000000000..eef11d640e198 --- /dev/null +++ b/.devcontainer/config/nodejs.cnf @@ -0,0 +1,28 @@ +########################################################################## +## ## +## This OpenSSL config is only loaded when running Kibana in FIPS mode. ## +## ## +## See: ## +## https://github.com/openssl/openssl/blob/openssl-3.0/README-FIPS.md ## +## https://www.openssl.org/docs/man3.0/man7/fips_module.html ## +## ## +########################################################################## + +nodejs_conf = nodejs_init +.include /home/vscode/openssl/ssl/fipsmodule.cnf + +[nodejs_init] +providers = provider_sect +alg_section = algorithm_sect + +[provider_sect] +default = default_sect +# The fips section name should match the section name inside the +# included fipsmodule.cnf. +fips = fips_sect + +[default_sect] +activate = 1 + +[algorithm_sect] +default_properties = fips=yes \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000000..f5fea9e37c5d3 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,41 @@ +{ + "name": "Kibana", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "ms-azuretools.vscode-docker", + "editorconfig.editorconfig", + "timonwong.shellcheck", + "eamodio.gitlens", + "github.vscode-pull-request-github" + ] + } + }, + "forwardPorts": [ + 9200, + 5601, + 9229, + 9230, + 9231 + ], + "postStartCommand": "/workspaces/kibana/.devcontainer/scripts/post_start.sh", + "remoteUser": "vscode", + "features": { + "ghcr.io/devcontainers/features/docker-in-docker:2": { + "version": "latest", + "dockerDashComposeVersion": "latest" + }, + "ghcr.io/devcontainers/features/github-cli:1": { + "installDirectlyFromGitHubRelease": true, + "version": "latest" + }, + "ghcr.io/kreemer/features/chrometesting:1": { + "version": "stable" + } + } +} diff --git a/.devcontainer/scripts/env.sh b/.devcontainer/scripts/env.sh new file mode 100755 index 0000000000000..77c2000663e5f --- /dev/null +++ b/.devcontainer/scripts/env.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +ENV_PATH="${KBN_DIR}/.devcontainer/.env" +KBN_CONFIG_FILE="${KBN_DIR}/config/kibana.dev.yml" + +setup_fips() { + if [ ! -f "$KBN_CONFIG_FILE" ]; then + touch "$KBN_CONFIG_FILE" + fi + + if [ -n "$FIPS" ] && [ "$FIPS" = "1" ]; then + sed -i '/xpack.security.experimental.fipsMode.enabled:/ {s/.*/xpack.security.experimental.fipsMode.enabled: true/; t}; $a\xpack.security.experimental.fipsMode.enabled: true' "$KBN_CONFIG_FILE" + + # Patch node_modules so we can start Kibana in dev mode + sed -i 's/hashType = hashType || '\''md5'\'';/hashType = hashType || '\''sha1'\'';/g' "${KBN_DIR}/node_modules/file-loader/node_modules/loader-utils/lib/getHashDigest.js" + sed -i 's/const hash = createHash("md4");/const hash = createHash("sha1");/g' "${KBN_DIR}/node_modules/webpack/lib/ModuleFilenameHelpers.js" + sed -i 's/contentHash: createHash("md4")/contentHash: createHash("sha1")/g' "${KBN_DIR}/node_modules/webpack/lib/SourceMapDevToolPlugin.js" + + export OPENSSL_MODULES="$OPENSSL_PATH/lib/ossl-modules" + export NODE_OPTIONS="--enable-fips --openssl-config=$KBN_DIR/.devcontainer/config/nodejs.cnf" + echo "FIPS mode enabled" + echo "If manually bootstrapping in FIPS mode use: NODE_OPTIONS='' yarn kbn bootstrap" + else + sed -i '/xpack.security.experimental.fipsMode.enabled:/ {s/.*/xpack.security.experimental.fipsMode.enabled: false/; t}; $a\xpack.security.experimental.fipsMode.enabled: false' "$KBN_CONFIG_FILE" + fi +} + +setup_shell() { + if [ -n "$SHELL" ] && [ -x "$SHELL" ]; then + current_shell=$(ps -p $$ -o comm=) + desired_shell=$(basename "$SHELL") + + if [ "$current_shell" != "$desired_shell" ]; then + sudo chsh -s "$SHELL" vscode + exec "$SHELL" + fi + else + echo "Shell is not set or not executable, using bash" + fi +} + +if [ -f "$ENV_PATH" ]; then + source "$ENV_PATH" + setup_fips + setup_shell +else + echo ".env file not found, using default values" +fi diff --git a/.devcontainer/scripts/post_start.sh b/.devcontainer/scripts/post_start.sh new file mode 100755 index 0000000000000..78490bb73d513 --- /dev/null +++ b/.devcontainer/scripts/post_start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# If FIPS mode is enabled, there can be issues installing some dependencies due to invalid algorithms. +# So override the NODE_OPTIONS environment variable to disable FIPS mode. +NODE_OPTIONS='' yarn kbn bootstrap + +Xvfb :99 -screen 0 1920x1080x24 & +export DISPLAY=:99 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6b02c918db816..b74db49fc30ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -68,11 +68,13 @@ packages/kbn-capture-oas-snapshot-cli @elastic/kibana-core x-pack/test/cases_api_integration/common/plugins/cases @elastic/response-ops packages/kbn-cases-components @elastic/response-ops x-pack/plugins/cases @elastic/response-ops +packages/kbn-cbor @elastic/kibana-operations packages/kbn-cell-actions @elastic/security-threat-hunting-explore src/plugins/chart_expressions/common @elastic/kibana-visualizations packages/kbn-chart-icons @elastic/kibana-visualizations src/plugins/charts @elastic/kibana-visualizations packages/kbn-check-mappings-update-cli @elastic/kibana-core +packages/kbn-check-prod-native-modules-cli @elastic/kibana-operations packages/kbn-ci-stats-core @elastic/kibana-operations packages/kbn-ci-stats-performance-metrics @elastic/kibana-operations packages/kbn-ci-stats-reporter @elastic/kibana-operations @@ -423,6 +425,7 @@ src/plugins/esql_datagrid @elastic/kibana-esql packages/kbn-esql-utils @elastic/kibana-esql packages/kbn-esql-validation-autocomplete @elastic/kibana-esql examples/esql_validation_example @elastic/kibana-esql +test/plugin_functional/plugins/eui_provider_dev_warning @elastic/appex-sharedux packages/kbn-event-annotation-common @elastic/kibana-visualizations packages/kbn-event-annotation-components @elastic/kibana-visualizations src/plugins/event_annotation_listing @elastic/kibana-visualizations @@ -491,6 +494,7 @@ 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 +test/plugin_functional/plugins/hardening @elastic/kibana-security packages/kbn-health-gateway-server @elastic/kibana-core examples/hello_world @elastic/kibana-core src/plugins/home @elastic/kibana-core @@ -758,6 +762,7 @@ x-pack/packages/security/plugin_types_common @elastic/kibana-security x-pack/packages/security/plugin_types_public @elastic/kibana-security x-pack/packages/security/plugin_types_server @elastic/kibana-security x-pack/packages/security/role_management_model @elastic/kibana-security +x-pack/packages/security-solution/common @elastic/security-threat-hunting-investigations x-pack/packages/security-solution/distribution_bar @elastic/kibana-cloud-security-posture x-pack/plugins/security_solution_ess @elastic/security-solution x-pack/packages/security-solution/features @elastic/security-threat-hunting-explore @@ -927,7 +932,7 @@ test/plugin_functional/plugins/ui_settings_plugin @elastic/kibana-core packages/kbn-ui-shared-deps-npm @elastic/kibana-operations packages/kbn-ui-shared-deps-src @elastic/kibana-operations packages/kbn-ui-theme @elastic/kibana-operations -packages/kbn-unified-data-table @elastic/kibana-data-discovery +packages/kbn-unified-data-table @elastic/kibana-data-discovery @elastic/security-threat-hunting-investigations packages/kbn-unified-doc-viewer @elastic/kibana-data-discovery examples/unified_doc_viewer @elastic/kibana-core src/plugins/unified_doc_viewer @elastic/kibana-data-discovery @@ -1032,6 +1037,7 @@ packages/kbn-zod-helpers @elastic/security-detection-rule-management /x-pack/test_serverless/functional/test_suites/common/examples/search_examples @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/examples/unified_field_list_examples @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/management/data_views @elastic/kibana-data-discovery +src/plugins/discover/public/context_awareness/profile_providers/security @elastic/kibana-data-discovery @elastic/security-threat-hunting-investigations # Visualizations /src/plugins/visualize/ @elastic/kibana-visualizations @@ -1275,6 +1281,7 @@ x-pack/test/observability_ai_assistant_functional @elastic/obs-ai-assistant /kbn_pm/ @elastic/kibana-operations /x-pack/dev-tools @elastic/kibana-operations /catalog-info.yaml @elastic/kibana-operations @elastic/kibana-tech-leads +/.devcontainer/ @elastic/kibana-operations # Appex QA /src/dev/code_coverage @elastic/appex-qa @@ -1349,7 +1356,9 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib /packages/kbn-std/src/parse_next_url.ts @elastic/kibana-core @elastic/kibana-security /test/interactive_setup_api_integration/ @elastic/kibana-security /test/interactive_setup_functional/ @elastic/kibana-security +/test/plugin_functional/plugins/hardening @elastic/kibana-security /test/plugin_functional/test_suites/core_plugins/rendering.ts @elastic/kibana-security +/test/plugin_functional/test_suites/hardening @elastic/kibana-security /x-pack/test/accessibility/apps/group1/login_page.ts @elastic/kibana-security /x-pack/test/accessibility/apps/group1/roles.ts @elastic/kibana-security /x-pack/test/accessibility/apps/group1/spaces.ts @elastic/kibana-security @@ -1760,6 +1769,8 @@ x-pack/plugins/observability_solution/observability_shared/public/components/pro # Shared UX packages/react @elastic/appex-sharedux +test/functional/page_objects/solution_navigation.ts @elastic/appex-sharedux +/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @elastic/appex-sharedux # OpenAPI spec files /x-pack/plugins/fleet/common/openapi @elastic/platform-docs diff --git a/.gitignore b/.gitignore index 1936413e13609..02f11f9275184 100644 --- a/.gitignore +++ b/.gitignore @@ -142,10 +142,13 @@ x-pack/test/security_api_integration/plugins/audit_log/audit.log .ftr role_users.json + +.devcontainer/.env + # Ignore temporary files in oas_docs output/kibana.serverless.tmp1.yaml output/kibana.serverless.tmp2.yaml output/kibana.tmp1.yaml output/kibana.tmp2.yaml output/kibana.new.yaml -output/kibana.serverless.new.yaml \ No newline at end of file +output/kibana.serverless.new.yaml diff --git a/api_docs/actions.devdocs.json b/api_docs/actions.devdocs.json index 5def04077bc26..22c2fabddb90b 100644 --- a/api_docs/actions.devdocs.json +++ b/api_docs/actions.devdocs.json @@ -764,7 +764,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -800,6 +800,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -858,6 +884,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1452,7 +1480,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1478,7 +1508,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1724,6 +1754,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index c7e6afda96713..d1b0d67338110 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-08-23 +date: 2024-08-27 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 2d98c3ff77eb7..00f292e066bd1 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-08-23 +date: 2024-08-27 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 8b751d24d590b..c693b3de6677e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 2472ed9795e3f..be6ca5a797716 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 8ed71d6bcbe2d..1a063657bc3ca 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 7a015e6f1ad72..13e52a01e4bc3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.devdocs.json b/api_docs/apm_data_access.devdocs.json index ab948ad53eac0..e6d336d1074ee 100644 --- a/api_docs/apm_data_access.devdocs.json +++ b/api_docs/apm_data_access.devdocs.json @@ -700,7 +700,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -736,6 +736,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -794,6 +820,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1388,7 +1416,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1414,7 +1444,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1660,6 +1690,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index e2f4129a42285..613931cbc07ad 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 85a05e3262d03..c84613332411c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index f4680d871ee01..37d3c259bd800 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index c5bf934faf0f6..f197f466828e3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 267843a336dee..2df911cc5320b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 3b03c9e04048b..51bfb61d58d53 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 2e2a6b765313a..c41165e1ee318 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-08-23 +date: 2024-08-27 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 3eacf8526efad..78b45c64c1598 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 763672a01ae61..8924b2865f020 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-08-23 +date: 2024-08-27 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 c9bbefe01f698..dd48d4ac54d58 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 2be4ac3105c1b..62fd884e90c6d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index f375f7b13c02c..daccfcd4cf298 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-08-23 +date: 2024-08-27 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 2e0473b097025..68c4aee644c2c 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-08-23 +date: 2024-08-27 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 e16c4dfee27da..c8b738ffc3cac 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-08-23 +date: 2024-08-27 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 3690de252c082..be528efc795ec 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index ba19fd7c590e8..485b62c398132 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index da46150b2b097..42e081040e905 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 5af00566bd450..21c6295f9e49e 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -2690,7 +2690,7 @@ "section": "def-public.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; enableUiSettingsValidations: boolean; }>>" + "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; query: Readonly<{} & { timefilter: Readonly<{} & { minRefreshInterval: number; }>; }>; enableUiSettingsValidations: boolean; }>>" ], "path": "src/plugins/data/public/plugin.ts", "deprecated": false, @@ -11983,7 +11983,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; enableUiSettingsValidations: boolean; }>>" + "; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; query: Readonly<{} & { timefilter: Readonly<{} & { minRefreshInterval: number; }>; }>; enableUiSettingsValidations: boolean; }>>" ], "path": "src/plugins/data/server/plugin.ts", "deprecated": false, @@ -16070,7 +16070,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -16106,6 +16106,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -16164,6 +16190,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -16758,7 +16786,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -16784,7 +16814,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -17030,6 +17060,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 1c12685087570..ae5937d365d80 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index dd39100824d66..41028dd816d74 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.devdocs.json b/api_docs/data_query.devdocs.json index fcb1d445f23ae..eec375eb64279 100644 --- a/api_docs/data_query.devdocs.json +++ b/api_docs/data_query.devdocs.json @@ -3430,7 +3430,7 @@ "section": "def-common.RefreshInterval", "text": "RefreshInterval" }, - "; setRefreshInterval: (refreshInterval: Partial<", + "; getMinRefreshInterval: () => number; setRefreshInterval: (refreshInterval: Partial<", { "pluginId": "data", "scope": "common", @@ -3834,7 +3834,7 @@ "section": "def-common.RefreshInterval", "text": "RefreshInterval" }, - "; setRefreshInterval: (refreshInterval: Partial<", + "; getMinRefreshInterval: () => number; setRefreshInterval: (refreshInterval: Partial<", { "pluginId": "data", "scope": "common", diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 077c10aa11247..fffe43296211b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 0d2eb09086dc9..7baaa41c1bfd6 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -1342,7 +1342,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; enableUiSettingsValidations: boolean; }>" + "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; asyncSearch: Readonly<{ pollInterval?: number | undefined; } & { waitForCompletion: moment.Duration; keepAlive: moment.Duration; batchedReduceSize: number; }>; sessions: Readonly<{} & { enabled: boolean; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; }>; }>; query: Readonly<{} & { timefilter: Readonly<{} & { minRefreshInterval: number; }>; }>; enableUiSettingsValidations: boolean; }>" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 739fcafaaa728..c25bda8943efb 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index e2015a95c8308..436eede1240b4 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index a031ea4ccb415..89aa3a4b3ae7d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index 0ef2c7d54d981..1757889dd6502 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index 655bf8c50b024..f003397257a1f 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -12788,7 +12788,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -12824,6 +12824,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -12882,6 +12908,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -13476,7 +13504,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -13502,7 +13532,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -13748,6 +13778,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -14186,14 +14218,14 @@ "plugin": "ml", "path": "x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx" }, - { - "plugin": "@kbn/ml-data-view-utils", - "path": "x-pack/packages/ml/data_view_utils/actions/data_view_handler.ts" - }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/models/job_service/new_job_caps/rollup.ts" }, + { + "plugin": "@kbn/ml-data-view-utils", + "path": "x-pack/packages/ml/data_view_utils/actions/data_view_handler.ts" + }, { "plugin": "enterpriseSearch", "path": "x-pack/plugins/enterprise_search/public/applications/analytics/utils/find_or_create_data_view.ts" diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index b086c09aac273..6a74b9a11ded2 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index a9e33ae5e2a8a..91ca1bc925b24 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.devdocs.json b/api_docs/dataset_quality.devdocs.json index 839cc74cfa844..22bb1d7a3e854 100644 --- a/api_docs/dataset_quality.devdocs.json +++ b/api_docs/dataset_quality.devdocs.json @@ -179,7 +179,7 @@ "label": "indexNameToDataStreamParts", "description": [], "signature": [ - "(dataStreamName: string) => { type: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\"; dataset: string; namespace: string; }" + "(dataStreamName: string) => { type: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\"; dataset: string; namespace: string; }" ], "path": "x-pack/plugins/observability_solution/dataset_quality/common/utils/dataset_name.ts", "deprecated": false, @@ -248,7 +248,7 @@ "KeyofC", "<{ logs: null; metrics: null; traces: null; synthetics: null; profiling: null; }>; }>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; }; }; }) => Promise<{ integrations: ({ name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; })[]; }>; } & ", + " & { params: { query: { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; }; }; }) => Promise<{ integrations: ({ name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; })[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": { endpoint: \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\"; params?: ", "TypeC", @@ -312,7 +312,7 @@ "StringC", "; }>]>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { start: number; end: number; } & { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; } & { dataStream?: string | undefined; }; }; }) => Promise<{ aggregatable: boolean; datasets: string[]; }>; } & ", + " & { params: { query: { start: number; end: number; } & { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; } & { dataStream?: string | undefined; }; }; }) => Promise<{ aggregatable: boolean; datasets: string[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; \"GET /internal/dataset_quality/data_streams/degraded_docs\": { endpoint: \"GET /internal/dataset_quality/data_streams/degraded_docs\"; params?: ", "TypeC", @@ -334,7 +334,7 @@ "StringC", "; }>]>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { start: number; end: number; } & { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ degradedDocs: { dataset: string; count: number; docsCount: number; percentage: number; }[]; }>; } & ", + " & { params: { query: { start: number; end: number; } & { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ degradedDocs: { dataset: string; count: number; docsCount: number; percentage: number; }[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; \"GET /internal/dataset_quality/data_streams/stats\": { endpoint: \"GET /internal/dataset_quality/data_streams/stats\"; params?: ", "TypeC", @@ -350,7 +350,7 @@ "StringC", "; }>]>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ datasetUserPrivileges: { canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }; dataStreamsStats: ({ name: string; userPrivileges: { canMonitor: boolean; }; } & { size?: string | undefined; sizeBytes?: number | undefined; lastActivity?: number | undefined; integration?: string | undefined; totalDocs?: number | null | undefined; })[]; }>; } & ", + " & { params: { query: { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ datasetUserPrivileges: { canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }; dataStreamsStats: ({ name: string; userPrivileges: { canMonitor: boolean; }; } & { size?: string | undefined; sizeBytes?: number | undefined; lastActivity?: number | undefined; integration?: string | undefined; totalDocs?: number | null | undefined; })[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; }[TEndpoint] extends { endpoint: any; params?: infer TRouteParamsRT extends ", { @@ -409,7 +409,7 @@ "KeyofC", "<{ logs: null; metrics: null; traces: null; synthetics: null; profiling: null; }>; }>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; }; }; }) => Promise<{ integrations: ({ name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; })[]; }>; } & ", + " & { params: { query: { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; }; }; }) => Promise<{ integrations: ({ name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; })[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": { endpoint: \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\"; params?: ", "TypeC", @@ -473,7 +473,7 @@ "StringC", "; }>]>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { start: number; end: number; } & { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; } & { dataStream?: string | undefined; }; }; }) => Promise<{ aggregatable: boolean; datasets: string[]; }>; } & ", + " & { params: { query: { start: number; end: number; } & { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; } & { dataStream?: string | undefined; }; }; }) => Promise<{ aggregatable: boolean; datasets: string[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; \"GET /internal/dataset_quality/data_streams/degraded_docs\": { endpoint: \"GET /internal/dataset_quality/data_streams/degraded_docs\"; params?: ", "TypeC", @@ -495,7 +495,7 @@ "StringC", "; }>]>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { start: number; end: number; } & { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ degradedDocs: { dataset: string; count: number; docsCount: number; percentage: number; }[]; }>; } & ", + " & { params: { query: { start: number; end: number; } & { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ degradedDocs: { dataset: string; count: number; docsCount: number; percentage: number; }[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; \"GET /internal/dataset_quality/data_streams/stats\": { endpoint: \"GET /internal/dataset_quality/data_streams/stats\"; params?: ", "TypeC", @@ -511,7 +511,7 @@ "StringC", "; }>]>; }> | undefined; handler: ({}: ", "DatasetQualityRouteHandlerResources", - " & { params: { query: { type?: \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | \"profiling\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ datasetUserPrivileges: { canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }; dataStreamsStats: ({ name: string; userPrivileges: { canMonitor: boolean; }; } & { size?: string | undefined; sizeBytes?: number | undefined; lastActivity?: number | undefined; integration?: string | undefined; totalDocs?: number | null | undefined; })[]; }>; } & ", + " & { params: { query: { type?: \"profiling\" | \"metrics\" | \"synthetics\" | \"traces\" | \"logs\" | undefined; } & { datasetQuery?: string | undefined; }; }; }) => Promise<{ datasetUserPrivileges: { canMonitor: boolean; } & { canRead: boolean; canViewIntegrations: boolean; }; dataStreamsStats: ({ name: string; userPrivileges: { canMonitor: boolean; }; } & { size?: string | undefined; sizeBytes?: number | undefined; lastActivity?: number | undefined; integration?: string | undefined; totalDocs?: number | null | undefined; })[]; }>; } & ", "DatasetQualityRouteCreateOptions", "; }[TEndpoint] extends { endpoint: any; params?: any; handler: ({}: any) => Promise; } & ", { diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 2a121ae5bdbdd..f3589688ad057 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-08-23 +date: 2024-08-27 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 5f58be943dc6b..3f4966f0c7a88 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 279ecce05b35b..9d2017898746e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index a8be386d19906..8e248de96b0bd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index f6d11875ea422..763357dce3d34 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index a981d65d81783..fc1bfd676d94d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 2bb7ac122f2ff..8b59717c8123d 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-08-23 +date: 2024-08-27 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 1b0a82eb85317..97e775ece5349 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-08-23 +date: 2024-08-27 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 48a3bc3efb0b0..d4ae7cd36f63d 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-08-23 +date: 2024-08-27 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 0943f010a0d08..2ea883a26f65b 100644 --- a/api_docs/elastic_assistant.devdocs.json +++ b/api_docs/elastic_assistant.devdocs.json @@ -381,7 +381,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -417,6 +417,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -475,6 +501,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1069,7 +1097,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1095,7 +1125,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1341,6 +1371,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 8b4ba692ba7f0..632160f5c04a9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 81206ed4e9163..6afa158bf1204 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 9cddad2ac9fee..34e8d7bd33b28 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index 4b576936aa3b9..01c434f316a48 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index 222bf0183d193..a86dd58f54772 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entities_data_access.mdx b/api_docs/entities_data_access.mdx index 0d7825c2fdf2d..9bc9b25dd0bfc 100644 --- a/api_docs/entities_data_access.mdx +++ b/api_docs/entities_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entitiesDataAccess title: "entitiesDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the entitiesDataAccess plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index a47af092d63c6..b52d2f36b5f39 100644 --- a/api_docs/entity_manager.mdx +++ b/api_docs/entity_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entityManager title: "entityManager" image: https://source.unsplash.com/400x175/?github description: API docs for the entityManager plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index c92e5932f8ef1..1f1a0ded169d4 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index 0c38a0976cf5f..45d20a01d3834 100644 --- a/api_docs/esql.mdx +++ b/api_docs/esql.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esql title: "esql" image: https://source.unsplash.com/400x175/?github description: API docs for the esql plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esql'] --- import esqlObj from './esql.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index 5c5b5ff146f70..c961d5ad93093 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index defc3968076c3..041bac091bc0b 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-08-23 +date: 2024-08-27 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 6ead5380f7a72..5079a06b4d0f0 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-08-23 +date: 2024-08-27 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 6e2a6a67b77f2..57ee52ba4ebb6 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-08-23 +date: 2024-08-27 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 62e028d3ce32d..3472ef2cd2b8e 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-08-23 +date: 2024-08-27 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 27b36de0289a2..98f8d449dacad 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index 60ef8d250d787..c1ec78c25a48d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index f163478ee0430..1220aeaeb1197 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 416b828807c4a..63a3bb1804286 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index a620bc75025bc..0f53d63b6f7b6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 8e4ef138f270f..da30f6abd5686 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index 48607321d1423..66b5f5c744a70 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index 7d938df0aa168..d31843a6fb7cc 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index ddc6d724db4ba..2e80c4db64538 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index ca86e960f26ce..0c54bc0c3bf43 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 05b1f2714dde7..1807e75907553 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index ef7dd3a22f588..9e08043cf7ad3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 5924d2b5a0daa..cad02c831acd9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index edc0ef60c9365..91eae5512c2eb 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 4b5307ff58419..f67e6ab2de725 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-08-23 +date: 2024-08-27 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 69fc4a6b3b94d..e985fa2b90bff 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index 8aedc38cc1661..00c482ea0b345 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 752fcb763aebe..d717a1ed62e1e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.devdocs.json b/api_docs/files.devdocs.json index f3cc7d80e6a15..c63a73b61a66c 100644 --- a/api_docs/files.devdocs.json +++ b/api_docs/files.devdocs.json @@ -981,7 +981,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -1017,6 +1017,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -1075,6 +1101,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1669,7 +1697,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1695,7 +1725,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1941,6 +1971,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 32286b595947e..60537517ae2ec 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-08-23 +date: 2024-08-27 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 c3f3873d3cbda..93407e10b2fd2 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-08-23 +date: 2024-08-27 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 511e4311c4726..6fdb547691329 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -12347,7 +12347,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -12383,6 +12383,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -12441,6 +12467,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -13035,7 +13063,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -13061,7 +13091,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -13307,6 +13337,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -13718,7 +13750,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -13754,6 +13786,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -13812,6 +13870,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -14406,7 +14466,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -14432,7 +14494,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -14678,6 +14740,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -15102,7 +15166,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -15138,6 +15202,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -15196,6 +15286,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -15790,7 +15882,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -15816,7 +15910,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -16062,6 +16156,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -16483,7 +16579,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -16519,6 +16615,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -16577,6 +16699,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -17171,7 +17295,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -17197,7 +17323,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -17443,6 +17569,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -17867,7 +17995,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -17903,6 +18031,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -17961,6 +18115,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -18555,7 +18711,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -18581,7 +18739,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -18827,6 +18985,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -27819,7 +27979,7 @@ "label": "PackageSpecCategory", "description": [], "signature": [ - "\"monitoring\" | \"security\" | \"connector\" | \"observability\" | \"custom\" | \"infrastructure\" | \"cloud\" | \"enterprise_search\" | \"advanced_analytics_ueba\" | \"analytics_engine\" | \"application_observability\" | \"app_search\" | \"auditd\" | \"authentication\" | \"aws\" | \"azure\" | \"big_data\" | \"cdn_security\" | \"config_management\" | \"connector_client\" | \"containers\" | \"crawler\" | \"credential_management\" | \"crm\" | \"custom_logs\" | \"database_security\" | \"datastore\" | \"dns_security\" | \"edr_xdr\" | \"cloudsecurity_cdr\" | \"elasticsearch_sdk\" | \"elastic_stack\" | \"email_security\" | \"firewall_security\" | \"google_cloud\" | \"iam\" | \"ids_ips\" | \"java_observability\" | \"kubernetes\" | \"language_client\" | \"languages\" | \"load_balancer\" | \"message_queue\" | \"native_search\" | \"network\" | \"network_security\" | \"notification\" | \"os_system\" | \"process_manager\" | \"productivity\" | \"productivity_security\" | \"proxy_security\" | \"sdk_search\" | \"stream_processing\" | \"support\" | \"threat_intel\" | \"ticketing\" | \"version_control\" | \"virtualization\" | \"vpn_security\" | \"vulnerability_management\" | \"web\" | \"web_application_firewall\" | \"websphere\" | \"workplace_search_content_source\" | \"workplace_search\"" + "\"connector\" | \"monitoring\" | \"security\" | \"observability\" | \"custom\" | \"infrastructure\" | \"cloud\" | \"enterprise_search\" | \"advanced_analytics_ueba\" | \"analytics_engine\" | \"application_observability\" | \"app_search\" | \"auditd\" | \"authentication\" | \"aws\" | \"azure\" | \"big_data\" | \"cdn_security\" | \"config_management\" | \"connector_client\" | \"containers\" | \"crawler\" | \"credential_management\" | \"crm\" | \"custom_logs\" | \"database_security\" | \"datastore\" | \"dns_security\" | \"edr_xdr\" | \"cloudsecurity_cdr\" | \"elasticsearch_sdk\" | \"elastic_stack\" | \"email_security\" | \"firewall_security\" | \"google_cloud\" | \"iam\" | \"ids_ips\" | \"java_observability\" | \"kubernetes\" | \"language_client\" | \"languages\" | \"load_balancer\" | \"message_queue\" | \"native_search\" | \"network\" | \"network_security\" | \"notification\" | \"os_system\" | \"process_manager\" | \"productivity\" | \"productivity_security\" | \"proxy_security\" | \"sdk_search\" | \"stream_processing\" | \"support\" | \"threat_intel\" | \"ticketing\" | \"version_control\" | \"virtualization\" | \"vpn_security\" | \"vulnerability_management\" | \"web\" | \"web_application_firewall\" | \"websphere\" | \"workplace_search_content_source\" | \"workplace_search\"" ], "path": "x-pack/plugins/fleet/common/types/models/package_spec.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index b15c6ec799252..b64018272a21b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index ea98ae71624af..eac71905ded56 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 20c3582d29192..197a35e1a463c 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 57ce7c47e0e20..8d281fc9b1aef 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-08-23 +date: 2024-08-27 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 6a7a905680311..16d8e69eaeebd 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-08-23 +date: 2024-08-27 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 43a7f5b6410f4..15a25b6609373 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 0f87c16a2a691..84f5f3de0a2c0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index fbeefebad5d87..fd95715a8cc2f 100644 --- a/api_docs/inference.mdx +++ b/api_docs/inference.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inference title: "inference" image: https://source.unsplash.com/400x175/?github description: API docs for the inference plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index c734a16b4f1b9..19175d82460f5 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-08-23 +date: 2024-08-27 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 1f7d558b514de..e4cafbc124649 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-08-23 +date: 2024-08-27 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 d97ac52c0ac44..5cf566b63af27 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index d23dec3a4e026..2812e63061be9 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index d7a68d8b3622b..4200b4df55f6d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index cda1777957a85..e9fa8ccba29e8 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/investigate_app.mdx b/api_docs/investigate_app.mdx index ffe76069ab27a..2348c5fcb711b 100644 --- a/api_docs/investigate_app.mdx +++ b/api_docs/investigate_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigateApp title: "investigateApp" image: https://source.unsplash.com/400x175/?github description: API docs for the investigateApp plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigateApp'] --- import investigateAppObj from './investigate_app.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 6744b0c19e6ec..36a873aa0aa93 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-08-23 +date: 2024-08-27 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 792436c383657..2b22f5d6fc202 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-08-23 +date: 2024-08-27 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 b1e831ff3bd6b..879e63ec94b52 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-08-23 +date: 2024-08-27 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 5bd1860350682..be52419021093 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-08-23 +date: 2024-08-27 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 c88a385f76601..4eddc3c8f1588 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-08-23 +date: 2024-08-27 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 c77a9dd8d4a6e..f4a1536f13765 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index b85adabcc42b6..7fb32ced0de89 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 8769abaf03a2d..7429ff247175c 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-08-23 +date: 2024-08-27 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 8f88ec67b7798..ca1cc6be7b68c 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-08-23 +date: 2024-08-27 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 dd541ce226ed0..f4446f2c69f3d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_grouping.mdx b/api_docs/kbn_alerts_grouping.mdx index c5490d3682942..0870d46f2715d 100644 --- a/api_docs/kbn_alerts_grouping.mdx +++ b/api_docs/kbn_alerts_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-grouping title: "@kbn/alerts-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-grouping plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index e00c36ade6135..f4ae83ee2bb5d 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-08-23 +date: 2024-08-27 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 55a5c172250b2..b1116871df3d5 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index 0a415d63b6f0c..9d2cf63cd98a9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 346033b477f71..baab52fcd0c72 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 1ef36c6910e86..5bd1bdf21cf2c 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-08-23 +date: 2024-08-27 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.devdocs.json b/api_docs/kbn_apm_synthtrace.devdocs.json index d1fa4a2a3ee91..33cbffd896893 100644 --- a/api_docs/kbn_apm_synthtrace.devdocs.json +++ b/api_docs/kbn_apm_synthtrace.devdocs.json @@ -633,6 +633,38 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.uninstallSystemPackage", + "type": "Function", + "tags": [], + "label": "uninstallSystemPackage", + "description": [], + "signature": [ + "(packageVersion: string) => Promise" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace", + "id": "def-server.InfraSynthtraceKibanaClient.uninstallSystemPackage.$1", + "type": "string", + "tags": [], + "label": "packageVersion", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 3a2224caae80c..f2cd1fc825be9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 51 | 0 | 51 | 9 | +| 53 | 0 | 53 | 9 | ## Server diff --git a/api_docs/kbn_apm_synthtrace_client.devdocs.json b/api_docs/kbn_apm_synthtrace_client.devdocs.json index 269b19c071e85..8f29a85704f03 100644 --- a/api_docs/kbn_apm_synthtrace_client.devdocs.json +++ b/api_docs/kbn_apm_synthtrace_client.devdocs.json @@ -2724,7 +2724,9 @@ " | ", "K8sContainerMetricsDocument", " | ", - "AWSRdsMetricsDocument" + "AWSRdsMetricsDocument", + " | ", + "K8sNodeMetricsDocument" ], "path": "packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts", "deprecated": false, @@ -3135,6 +3137,46 @@ "trackAdoption": false } ] + }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.infra.k8sNode", + "type": "Function", + "tags": [], + "label": "k8sNode", + "description": [], + "signature": [ + "(name: string, podUid: string) => ", + "K8sNode" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.infra.k8sNode.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_node.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.infra.k8sNode.$2", + "type": "string", + "tags": [], + "label": "podUid", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_node.ts", + "deprecated": false, + "trackAdoption": false + } + ] } ], "initialIsOpen": false diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 48e2c279076e0..cd6976985d516 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 201 | 0 | 201 | 31 | +| 204 | 0 | 204 | 33 | ## Common diff --git a/api_docs/kbn_apm_types.mdx b/api_docs/kbn_apm_types.mdx index 891ed29023def..7e25637a0387f 100644 --- a/api_docs/kbn_apm_types.mdx +++ b/api_docs/kbn_apm_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-types title: "@kbn/apm-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-types plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-types'] --- import kbnApmTypesObj from './kbn_apm_types.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index d071411e54dac..4a5c5681ea201 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx index 806a62aec16ea..81e4caa4db02e 100644 --- a/api_docs/kbn_avc_banner.mdx +++ b/api_docs/kbn_avc_banner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-avc-banner title: "@kbn/avc-banner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/avc-banner plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] --- import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 862b74b84207f..83ffe3d48c656 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-08-23 +date: 2024-08-27 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 68eeea1ed2d90..0e695ad07bcff 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-08-23 +date: 2024-08-27 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 eb71eca84f945..56a0eec50a8f2 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-08-23 +date: 2024-08-27 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 611c10b21dc3f..91398cbf372ed 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-08-23 +date: 2024-08-27 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 6a4bb36b0e16c..83fef34dce621 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cbor.devdocs.json b/api_docs/kbn_cbor.devdocs.json new file mode 100644 index 0000000000000..aaa703e771f89 --- /dev/null +++ b/api_docs/kbn_cbor.devdocs.json @@ -0,0 +1,171 @@ +{ + "id": "@kbn/cbor", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.KbnCbor", + "type": "Class", + "tags": [], + "label": "KbnCbor", + "description": [], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.KbnCbor.encode", + "type": "Function", + "tags": [], + "label": "encode", + "description": [], + "signature": [ + "(data: unknown) => any" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.KbnCbor.encode.$1", + "type": "Unknown", + "tags": [], + "label": "data", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.KbnCbor.decode", + "type": "Function", + "tags": [], + "label": "decode", + "description": [], + "signature": [ + "(uint8: any) => any" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.KbnCbor.decode.$1", + "type": "Any", + "tags": [], + "label": "uint8", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.decode", + "type": "Function", + "tags": [], + "label": "decode", + "description": [], + "signature": [ + "(uint8: any) => any" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.decode.$1", + "type": "Any", + "tags": [], + "label": "uint8", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.encode", + "type": "Function", + "tags": [], + "label": "encode", + "description": [], + "signature": [ + "(data: unknown) => any" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/cbor", + "id": "def-common.encode.$1", + "type": "Unknown", + "tags": [], + "label": "data", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/kbn-cbor/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_cbor.mdx b/api_docs/kbn_cbor.mdx new file mode 100644 index 0000000000000..5720f6996dfdf --- /dev/null +++ b/api_docs/kbn_cbor.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCborPluginApi +slug: /kibana-dev-docs/api/kbn-cbor +title: "@kbn/cbor" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/cbor plugin +date: 2024-08-27 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cbor'] +--- +import kbnCborObj from './kbn_cbor.devdocs.json'; + + + +Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 9 | 2 | 9 | 0 | + +## Common + +### Functions + + +### Classes + + diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 9254639429185..a07787f1fbc3a 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-08-23 +date: 2024-08-27 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 3248b3ca65504..56b27d69fcece 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-08-23 +date: 2024-08-27 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 d1f22d1f802a2..795e67895a493 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index ae2ab24e99813..3e7cdf023bff6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index b3bd5f606b7c9..80e3fe3bef8b4 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index b0e274b7ba05f..6f6944f783e90 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index 7b905dc352438..622447bc9ecd5 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index b9ac0505c46a4..85f1b3317f0f0 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-08-23 +date: 2024-08-27 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 e7bee5a37cd70..ee54ac976c335 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-08-23 +date: 2024-08-27 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 70d3aae06b51a..b284131e2e21a 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-08-23 +date: 2024-08-27 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 e9c0198dac35d..acd67820e9cbf 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index b56a116bfde1d..2fbfe5daa0121 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index a0784c14d8142..8520b4bb8e954 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 71adcb19d2c74..ab0b8b39b7997 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index 486a91ed86ff3..35107047deb46 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_public.mdx b/api_docs/kbn_content_management_content_insights_public.mdx index bc33d284ef380..25b8de8994840 100644 --- a/api_docs/kbn_content_management_content_insights_public.mdx +++ b/api_docs/kbn_content_management_content_insights_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-public title: "@kbn/content-management-content-insights-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-public plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-public'] --- import kbnContentManagementContentInsightsPublicObj from './kbn_content_management_content_insights_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_server.mdx b/api_docs/kbn_content_management_content_insights_server.mdx index fa657b1366c81..a91bfa36b7375 100644 --- a/api_docs/kbn_content_management_content_insights_server.mdx +++ b/api_docs/kbn_content_management_content_insights_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-server title: "@kbn/content-management-content-insights-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-server plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-server'] --- import kbnContentManagementContentInsightsServerObj from './kbn_content_management_content_insights_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index f65f7519579f5..6c125110686fe 100644 --- a/api_docs/kbn_content_management_favorites_public.mdx +++ b/api_docs/kbn_content_management_favorites_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-public title: "@kbn/content-management-favorites-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-public plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-public'] --- import kbnContentManagementFavoritesPublicObj from './kbn_content_management_favorites_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_server.mdx b/api_docs/kbn_content_management_favorites_server.mdx index 2f5f9d6d023f1..c61ad339ebc0b 100644 --- a/api_docs/kbn_content_management_favorites_server.mdx +++ b/api_docs/kbn_content_management_favorites_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-server title: "@kbn/content-management-favorites-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-server plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-server'] --- import kbnContentManagementFavoritesServerObj from './kbn_content_management_favorites_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 58934929e5eb9..6999daa312b6d 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-08-23 +date: 2024-08-27 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 01d3524cc3520..76046ecedaef1 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-08-23 +date: 2024-08-27 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 be693874ec840..e37e79687ed42 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-08-23 +date: 2024-08-27 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 b93fee650cdf2..3681ee8831136 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx index 61b4eb0238ab3..8da1564b81135 100644 --- a/api_docs/kbn_content_management_user_profiles.mdx +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-user-profiles title: "@kbn/content-management-user-profiles" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-user-profiles plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] --- import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 7c128f0a22f4b..4cb63afb92a40 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-08-23 +date: 2024-08-27 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 a85a326d620f2..78f7eb84efd71 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index bcb90761435b8..abbefe10b46a9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index e4c73d4685393..9b231d77175e5 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 5d50f83db03dd..a45480f32cc93 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index 6ef07a6820b7f..9ac1416eb37b8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 4632692406529..5bc9d9db9e7e8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index 4169518fbe421..81748a4eaf9da 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 1cf53616f4a23..99e6f7ed95a38 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index 77b74724f6f7c..4ff1b45d2732a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index 243f5e83f075d..90369a003db04 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index 85af400c4f789..8b18bdd944c3b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index 5af8b0b0d4c74..b80bddb5b128c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index b7cf291d9c97b..0c2868074529e 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-08-23 +date: 2024-08-27 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 2802723d5073c..b235d092cd2bd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 6f03be18e8071..64dfef98a4f3e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 80fbe8a6befdf..86ec2b57b7b67 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index 62e67eda0e7bc..4f2e8d28523ff 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index d318e5f4c31f3..52767b383d9c8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 08eedd861d507..6b5767a496834 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index cd5cd358cb1e5..6c0a063c27065 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 608f9f5e0a3eb..a1419417c6872 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index f8fadfa7b7a26..c1c3d5b8793a4 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3700,7 +3700,7 @@ "label": "AppDeepLinkId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"logs\" | \"profiling\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"canvas\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchRelevance\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"enterpriseSearchRelevance:inferenceEndpoints\" | \"observability-logs-explorer\" | \"observabilityOnboarding\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:services\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"profiling:functions\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"securitySolutionUI:notes-management\" | \"fleet:settings\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\" | \"fleet:agents\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"canvas\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"enterpriseSearchRelevance\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"searchPlayground\" | \"searchInferenceEndpoints\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"enterpriseSearchRelevance:inferenceEndpoints\" | \"observability-logs-explorer\" | \"observabilityOnboarding\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:services\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"profiling:functions\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:coverage-overview\" | \"securitySolutionUI:notes-management\" | \"fleet:settings\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\" | \"fleet:agents\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 843179a0a02b6..54eac3381fa00 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index baa2b177c7ba5..caa80ce744939 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 48b4b150af322..82991cfd78825 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 4f15529727a88..850127c0c6951 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-08-23 +date: 2024-08-27 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 21a4fea4c28ff..4a7a8dd051701 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-08-23 +date: 2024-08-27 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 ff65faf65be34..b3271d594ffe6 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-08-23 +date: 2024-08-27 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 dfce3927c1306..300f618e11429 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-08-23 +date: 2024-08-27 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 b43c7f537f0bd..343244e747a0b 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-08-23 +date: 2024-08-27 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 32b9e142bbdea..4423046fa5028 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-08-23 +date: 2024-08-27 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 c2a059a0039d9..4dd709e997aaf 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-08-23 +date: 2024-08-27 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 227bbf05e91f5..af8c1e840fe65 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index e960772427182..f970fd5519df1 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index 2054723bde542..5bc6fab00131a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 778e8cd2423f2..f34c100d033d2 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index a73943266e5c3..8efa9cc15b783 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index baee76ff3b60a..bd58da2512681 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 2606ddb6fd597..fd91a5d75ddcf 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index b845408b4187a..b3952c730cbd7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index a7811dcb4b1da..4dc289ee83060 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index e9a74efb78159..a45de1f50f75c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 2b5fc57c60a7f..25e1837f73ebe 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index f4c9c593e8a0e..7dcb66bdfb339 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json b/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json index def897d69232b..a567679020039 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json @@ -353,7 +353,7 @@ "SearchRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -411,6 +411,22 @@ "BulkRequest", ", options?: ", "TransportRequestOptions", + " | undefined]>; capabilities: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.ClientApiMockInstance", + "text": "ClientApiMockInstance" + }, + ", [params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", " | undefined]>; cat: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -473,6 +489,16 @@ }, "<", "default", + ">; connector: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; count: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -987,7 +1013,17 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; putScript: ", + " | undefined]>; profiling: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", + ">; putScript: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -1003,7 +1039,7 @@ "PutScriptRequest", ", options?: ", "TransportRequestOptions", - " | undefined]>; queryRuleset: ", + " | undefined]>; queryRules: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -1205,6 +1241,16 @@ }, "<", "default", + ">; simulate: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; slm: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -1526,7 +1572,7 @@ "SearchRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -1584,6 +1630,22 @@ "BulkRequest", ", options?: ", "TransportRequestOptions", + " | undefined]>; capabilities: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.ClientApiMockInstance", + "text": "ClientApiMockInstance" + }, + ", [params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", " | undefined]>; cat: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -1646,6 +1708,16 @@ }, "<", "default", + ">; connector: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; count: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -2160,7 +2232,17 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; putScript: ", + " | undefined]>; profiling: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", + ">; putScript: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -2176,7 +2258,7 @@ "PutScriptRequest", ", options?: ", "TransportRequestOptions", - " | undefined]>; queryRuleset: ", + " | undefined]>; queryRules: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -2378,6 +2460,16 @@ }, "<", "default", + ">; simulate: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; slm: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -2653,7 +2745,7 @@ "SearchRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -2711,6 +2803,22 @@ "BulkRequest", ", options?: ", "TransportRequestOptions", + " | undefined]>; capabilities: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.ClientApiMockInstance", + "text": "ClientApiMockInstance" + }, + ", [params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", " | undefined]>; cat: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -2773,6 +2881,16 @@ }, "<", "default", + ">; connector: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; count: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -3287,7 +3405,17 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; putScript: ", + " | undefined]>; profiling: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", + ">; putScript: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -3303,7 +3431,7 @@ "PutScriptRequest", ", options?: ", "TransportRequestOptions", - " | undefined]>; queryRuleset: ", + " | undefined]>; queryRules: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -3505,6 +3633,16 @@ }, "<", "default", + ">; simulate: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; slm: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -3780,7 +3918,7 @@ "SearchRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -3838,6 +3976,22 @@ "BulkRequest", ", options?: ", "TransportRequestOptions", + " | undefined]>; capabilities: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.ClientApiMockInstance", + "text": "ClientApiMockInstance" + }, + ", [params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", " | undefined]>; cat: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -3900,6 +4054,16 @@ }, "<", "default", + ">; connector: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; count: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -4414,7 +4578,17 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; putScript: ", + " | undefined]>; profiling: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", + ">; putScript: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -4430,7 +4604,7 @@ "PutScriptRequest", ", options?: ", "TransportRequestOptions", - " | undefined]>; queryRuleset: ", + " | undefined]>; queryRules: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -4632,6 +4806,16 @@ }, "<", "default", + ">; simulate: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; slm: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -4998,7 +5182,7 @@ "SearchRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + " | undefined]>; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -5056,6 +5240,22 @@ "BulkRequest", ", options?: ", "TransportRequestOptions", + " | undefined]>; capabilities: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.ClientApiMockInstance", + "text": "ClientApiMockInstance" + }, + ", [params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", " | undefined]>; cat: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -5118,6 +5318,16 @@ }, "<", "default", + ">; connector: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; count: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", @@ -5632,7 +5842,17 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined]>; putScript: ", + " | undefined]>; profiling: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", + ">; putScript: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -5648,7 +5868,7 @@ "PutScriptRequest", ", options?: ", "TransportRequestOptions", - " | undefined]>; queryRuleset: ", + " | undefined]>; queryRules: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", "scope": "server", @@ -5850,6 +6070,16 @@ }, "<", "default", + ">; simulate: ", + { + "pluginId": "@kbn/core-elasticsearch-client-server-mocks", + "scope": "server", + "docId": "kibKbnCoreElasticsearchClientServerMocksPluginApi", + "section": "def-server.DeeplyMockedApi", + "text": "DeeplyMockedApi" + }, + "<", + "default", ">; slm: ", { "pluginId": "@kbn/core-elasticsearch-client-server-mocks", diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 8ef2faba93c11..f0873aeae9a46 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.devdocs.json b/api_docs/kbn_core_elasticsearch_server.devdocs.json index 794765550dca2..be09c9b65cbd1 100644 --- a/api_docs/kbn_core_elasticsearch_server.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server.devdocs.json @@ -1233,7 +1233,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -1269,6 +1269,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -1327,6 +1353,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1921,7 +1949,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1947,7 +1977,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -2193,6 +2223,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -2967,7 +2999,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -3003,6 +3035,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -3061,6 +3119,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -3655,7 +3715,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -3681,7 +3743,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -3927,6 +3989,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -4205,7 +4269,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -4241,6 +4305,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -4299,6 +4389,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -4893,7 +4985,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -4919,7 +5013,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -5165,6 +5259,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -5443,7 +5539,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -5479,6 +5575,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -5537,6 +5659,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -6131,7 +6255,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -6157,7 +6283,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -6403,6 +6529,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -6934,7 +7062,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -6970,6 +7098,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -7028,6 +7182,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -7622,7 +7778,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -7648,7 +7806,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -7894,6 +8052,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 750f7d06a7ef6..5ffef6d967286 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json b/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json index ef42b4ea560c9..89c6626b9fd7d 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_server_internal.devdocs.json @@ -190,7 +190,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -226,6 +226,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -284,6 +310,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -878,7 +906,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -904,7 +934,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1150,6 +1180,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -1935,7 +1967,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -1971,6 +2003,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -2029,6 +2087,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -2623,7 +2683,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -2649,7 +2711,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -2895,6 +2957,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 3261dfca50c8b..1210c31594e05 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index fbebceaf61835..47b6947eaa2c9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index 2c67129743c6b..fc49467aa290c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index 93d098ce1f41e..1ea2637231f60 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 0cdd0f1a68e6d..6615011e3671e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index 5b3ee30e20470..8e08648a5df1e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index cef41990d100b..43f43eb6e7c92 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index f7b73b851e444..0756d85c34738 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 72e8197b06d6c..1af4fbadbb98b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index 5cba1c7a96532..3537972f3b5b9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 84057ab3ceb64..f6018a8997841 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index daafb2710e45f..98c5b513b4ad7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index fc35327b3c195..ebbe78fb88e75 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 0d7f2bbc45720..12684496d21aa 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index d7024740c16b8..b67b829b28626 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index a4cc5ceceaed5..2856c722ac306 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 1cddeb8aaa8d8..877056537d0e1 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index 2ae604ba07500..40305d4076732 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 09decfc911666..72f125b8ea29d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index c79bc8889324f..ed5ca78ddc8e8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 4eed50c15f778..e5947d81fd6c6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index a9e4725622fdd..1f8db0d8a5648 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 5de2e5ee6b58d..87de6afc3b871 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index a466979435bf2..0ff64e5fb2d77 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index 24a139f849c86..8e5138f237f33 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -4570,6 +4570,14 @@ "plugin": "rollup", "path": "x-pack/plugins/rollup/server/routes/api/jobs/register_get_route.ts" }, + { + "plugin": "searchIndices", + "path": "x-pack/plugins/search_indices/server/routes/status.ts" + }, + { + "plugin": "searchIndices", + "path": "x-pack/plugins/search_indices/server/routes/status.ts" + }, { "plugin": "searchInferenceEndpoints", "path": "x-pack/plugins/search_inference_endpoints/server/routes.ts" @@ -6684,10 +6692,6 @@ "plugin": "triggersActionsUi", "path": "x-pack/plugins/triggers_actions_ui/server/data/routes/indices.ts" }, - { - "plugin": "ml", - "path": "x-pack/plugins/ml/server/routes/job_service.ts" - }, { "plugin": "globalSearch", "path": "x-pack/plugins/global_search/server/routes/find.ts" @@ -15972,6 +15976,10 @@ "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/job_service.ts" }, + { + "plugin": "ml", + "path": "x-pack/plugins/ml/server/routes/job_service.ts" + }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/saved_objects.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index af814be806669..55da7f47659f9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 6c0a2f955e9f5..c5bac179c2545 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index 8ec6589231fa3..334266aa40623 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index 08067657eb46c..219e972879623 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 8260e37475989..410e09d20f712 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index a6ba0278d0c04..e842d03d48211 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 023b5d6d7c642..1f1016f813882 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 78f043bb16b29..b4f5d3f18ba56 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index 9efe453493f34..b331240f986c8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index 0c30905992b4e..4abfafaac0fa8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index 23c88616c8d1a..3d16fb52525e7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index 64c04a666337f..2ac6ec6eec448 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 7f30aabce4961..18faa4d7ee048 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 2e798ec23c9fa..4c178de68c5eb 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-08-23 +date: 2024-08-27 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 f40494a8df0a0..d1274781df178 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-08-23 +date: 2024-08-27 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 1800751ab0604..42ef59d4e8fe9 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-08-23 +date: 2024-08-27 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 c7979d2ebdaf0..77b4a8b95e19e 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-08-23 +date: 2024-08-27 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 3b6e6ba5ccf7f..2cc392c023c13 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 5ea0ce12d8ca9..8ab79b655f46a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index aac7724306579..5a7b43608a23d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 3a74d9508ee2f..256b5c47368e7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index d3ff8a1d9ecf5..53b94f64191be 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index cc61ed67092d1..aed7cfbfdc30e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 10a074cfd839a..d6b34efb368a3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index e9312e79a5819..a14d996e88b08 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index ba2b23d37dd4f..4424eec6d6d88 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 0487da6f83ec1..38e3dec36efdf 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 96a28d59addfa..7ba63fc4e4015 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index c2e4c94c627bb..1d768b6e2654d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index a45632326c67c..dd6fa5f7be57e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index f61c90c6d78c0..d74667afb522d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 59d91f269920a..64fd700def2a2 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index a9ad1a40dd284..4134abee4f1ef 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index dc25857838570..ac0db52af91fa 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 3989a8d788940..b890ce90ed3a0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index d4bb37bc95777..8dd9ac49ed57c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index 535ec70e27701..3890cf2b4f21f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index d280695b7c881..cecf2378392fb 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-08-23 +date: 2024-08-27 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 0ebfe832c6b9c..d26af5c3ff7fb 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-08-23 +date: 2024-08-27 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 7661e8dcbba38..a4268ddcaf062 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-08-23 +date: 2024-08-27 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 28b9dea5c8f57..f8c9730625e84 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-08-23 +date: 2024-08-27 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 12c2d779be81f..cd0e0b68a49dc 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 277ac7cb4d240..26ebc2421a387 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index e5481e769ade3..25a90fdc8d227 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 8f917154f9906..4ff5c77ce916e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 686ff6c810fde..ca449f755492b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 9f6fef394e33f..fc30ca847bfd4 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-08-23 +date: 2024-08-27 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 ce5e347a74b42..ec1da87fb3620 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 18678e453cd8b..e9b0377c3c715 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 8f64d1f809d54..ccc6a504fb80e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index afcf5a721ad2c..d02f91af0efc3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index f4a7a24da44da..d6de68dec8b87 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 5526f6dc09f8d..e925f5c58a09d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 635996900fcb4..bb5cdd9673a52 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 602b45a783868..859044161ee5d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index 75cdbb84b3f86..f11258261cb8d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 87f89cda62500..b18c1ef66575a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index d89f4315420b3..a6287689c0aa9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json b/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json index 258c7bf8d53f8..37ba415678d77 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.devdocs.json @@ -2549,7 +2549,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -2585,6 +2585,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -2643,6 +2669,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -3237,7 +3265,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -3263,7 +3293,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -3509,6 +3539,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", 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 2cf85cf87db8b..601ada984a49f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index 5e9b9dd22bfab..a84384a614463 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index d0bc2ff65739e..e4e1ef0784aeb 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -13336,6 +13336,8 @@ ], "signature": [ "MappingProperty", + " & ", + "MappingPropertyBase", " & { dynamic?: false | \"strict\" | undefined; properties?: Record | undefined; }" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index b275f63c19fc3..623d97858eee7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 7011e8f93da49..ecd587fa487bb 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 94e13b848f961..6500015899b6c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index d69fb9e24dc64..7fb5702fe6d79 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 2f5a48a0d9c6a..0c27a8397688a 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-08-23 +date: 2024-08-27 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 6932d277fdc5e..8bc3c7ed935e8 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-08-23 +date: 2024-08-27 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 daab7a521b089..0d58383363544 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-08-23 +date: 2024-08-27 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 9163792f48eee..c70b857db551a 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-08-23 +date: 2024-08-27 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 3d0a351a57d1e..45100b7f7459d 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-08-23 +date: 2024-08-27 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 c2372e78a04d8..4b74c9a28a5d9 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-08-23 +date: 2024-08-27 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 0e892ae75adb0..fddd1940b8528 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-08-23 +date: 2024-08-27 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 fabaa41dfcdc5..1add8c563cd14 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index b2ee26ba3ffeb..977a119ee22dd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index f5ba5f2397c44..f14a21281cd55 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index bb1c4f927094b..7f933cef04d0f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index ef26b5aed6d25..0e1040e88f886 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index d8c50098a207f..3c230369dabc6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 8c2467eb84fdf..d548b5b3f6950 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 37a9c857d5700..5864ba9c263ef 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-08-23 +date: 2024-08-27 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 6434f28fde9bc..310c13b531f52 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-08-23 +date: 2024-08-27 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 c64d47b8b3799..9ad53365f8f8f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 3f2f9501ad9f9..480af28046991 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index e4aa01468322f..89401bbaf4f88 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index b824f9efa1961..c2dc85da0bc2a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 316a97694cb44..a4daf6a03b792 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 1066cf86c83a8..2fb4050563b21 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index 8e72b1729dc7e..8fe61a5fd852d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index ad04cbe2f805a..8ac665cc00b13 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 90b1599d9d4fc..b960f54080fa8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 31989f22b0b1d..0909823486fd3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index bf89467217c94..d45fa251ca54a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index d512af802cade..abc774274415d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index 19b9f671973c7..bc200cc7e5a5a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index cd91a900cd37f..2eb282d66a231 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index ed84451aff5fc..f3b23040adfa2 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-08-23 +date: 2024-08-27 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 b968c5d0bf40a..3dbf7eadf3636 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-08-23 +date: 2024-08-27 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 513be1761cf64..19f9c984b80a0 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-08-23 +date: 2024-08-27 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 b507285bf5f9f..ff4289de5ba4c 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-08-23 +date: 2024-08-27 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 3a7cd70790943..5e94d232e6e0a 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-08-23 +date: 2024-08-27 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 e0dcae83fec4c..243cce4ec3906 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-08-23 +date: 2024-08-27 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 728cb27c75b05..2afc049d4af3a 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-08-23 +date: 2024-08-27 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 9192d3200ea1a..2a99a186eb1e2 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-08-23 +date: 2024-08-27 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 415bcbc8f8b0a..1e21317615285 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-08-23 +date: 2024-08-27 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 8154ab0494b1f..feca7186f57ab 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 31b5bb854249e..2727940f5d96a 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-08-23 +date: 2024-08-27 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 d0a12610662bb..7effa5043c39e 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-08-23 +date: 2024-08-27 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 9ac2b3ee90ed3..1d813af16a080 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-08-23 +date: 2024-08-27 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 3bc7a3220c333..f5cf1e2c93a31 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index 7d7a3aff3fe64..3a34ca782dbd0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 05041e32db468..9b8a9c6d92707 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-08-23 +date: 2024-08-27 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 4564eff686343..ea492b42c41c9 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-08-23 +date: 2024-08-27 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 aef624f090f52..eb5f327efbba4 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-08-23 +date: 2024-08-27 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 59a84a971b9c3..b3dee69a77a3c 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-08-23 +date: 2024-08-27 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 acd794158bbba..b2cc0651c36fd 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-08-23 +date: 2024-08-27 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 eb0390f38c5ff..8f87c878d9210 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-08-23 +date: 2024-08-27 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 573f89b0de84e..36a785292f177 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-08-23 +date: 2024-08-27 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 f30f5e3a87f02..403e1f990da63 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-08-23 +date: 2024-08-27 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 474b039cba36e..3daff33862051 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.devdocs.json b/api_docs/kbn_deeplinks_observability.devdocs.json index 8a0fac7dab160..7379ba1cbcfca 100644 --- a/api_docs/kbn_deeplinks_observability.devdocs.json +++ b/api_docs/kbn_deeplinks_observability.devdocs.json @@ -759,7 +759,7 @@ "label": "AppId", "description": [], "signature": [ - "\"metrics\" | \"apm\" | \"synthetics\" | \"ux\" | \"logs\" | \"profiling\" | \"slo\" | \"observabilityAIAssistant\" | \"observability-overview\" | \"observability-logs-explorer\" | \"observabilityOnboarding\"" + "\"profiling\" | \"metrics\" | \"apm\" | \"synthetics\" | \"ux\" | \"logs\" | \"slo\" | \"observabilityAIAssistant\" | \"observability-overview\" | \"observability-logs-explorer\" | \"observabilityOnboarding\"" ], "path": "packages/deeplinks/observability/deep_links.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 7f6c5abe89b90..8b1f3f5648581 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-08-23 +date: 2024-08-27 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 4bbd5c1eef041..be9ae071f666a 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-08-23 +date: 2024-08-27 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 397d173ebd681..07313929d2152 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-08-23 +date: 2024-08-27 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 8363ef57460b7..98f500d49629e 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-08-23 +date: 2024-08-27 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 191be50247cf7..0046e85e69576 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-08-23 +date: 2024-08-27 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 98df028221d09..e163e5e835c3c 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-08-23 +date: 2024-08-27 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 0199c2cbba3bd..db8e105b37cf5 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-08-23 +date: 2024-08-27 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 d845ed0c37058..e129fa1a192da 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-08-23 +date: 2024-08-27 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 936321080692f..c832a66dda064 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 0f8f3c5f9cf6f..9d17daf67d863 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index a375b17d0328d..064fdc1dba74d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index 966a5019ed0ce..5a25941f17f75 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-08-23 +date: 2024-08-27 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 96218e82538a3..e9e7da44ba4f7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 57fb42abf3e64..727523f24632e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index c5fdf9a3b9809..af9b82a99ccca 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-08-23 +date: 2024-08-27 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 1723354ec2622..c37c010bc0f0b 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-08-23 +date: 2024-08-27 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 c4ce9202fdfbf..78bb449ad9c28 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-08-23 +date: 2024-08-27 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.devdocs.json b/api_docs/kbn_ecs_data_quality_dashboard.devdocs.json index 2fe8bd96f7996..031d3c58d56f4 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.devdocs.json +++ b/api_docs/kbn_ecs_data_quality_dashboard.devdocs.json @@ -13,7 +13,7 @@ "signature": [ "(indexName: string) => string" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -27,7 +27,7 @@ "signature": [ "string" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -48,7 +48,7 @@ "signature": [ "React.NamedExoticComponent" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.tsx", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -82,7 +82,7 @@ "signature": [ "(phase: string) => string" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -96,7 +96,7 @@ "signature": [ "string" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -116,7 +116,7 @@ "tags": [], "label": "DATA_QUALITY_DASHBOARD_CONVERSATION_ID", "description": [], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -128,7 +128,7 @@ "tags": [], "label": "DATA_QUALITY_PROMPT_CONTEXT_PILL_TOOLTIP", "description": [], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -142,7 +142,7 @@ "description": [ "The subtitle displayed on the Data Quality dashboard" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -154,7 +154,7 @@ "tags": [], "label": "DATA_QUALITY_SUGGESTED_USER_PROMPT", "description": [], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -171,7 +171,7 @@ "signature": [ "\"https://www.elastic.co/guide/en/ecs/current/ecs-reference.html\"" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -185,7 +185,7 @@ "description": [ "The label displayed for the `ILM phase` combo box on the Data Quality dashboard" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -199,7 +199,7 @@ "description": [ "The tooltip for the `ILM phase` combo box on the Data Quality Dashboard" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -213,7 +213,7 @@ "description": [ "The placeholder for the `ILM phase` combo box on the Data Quality Dashboard" ], - "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts", + "path": "x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 44bb1f804aa62..116ac314da649 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-08-23 +date: 2024-08-27 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 c69498a185477..ecb8be31b9bb9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index f306772062ca1..7b70f3b376749 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 5e17b61aff2ec..7af819c876f97 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index 03fc53242ba56..92dc7af7432dc 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-08-23 +date: 2024-08-27 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 25f7cd0120032..f59d42a818657 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-08-23 +date: 2024-08-27 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 a1d5946db89b3..a85cb56faac7e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 60a70b18cf7e7..66b96f0831e53 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.devdocs.json b/api_docs/kbn_es_query.devdocs.json index d4e035d56caa0..1acb94440bf54 100644 --- a/api_docs/kbn_es_query.devdocs.json +++ b/api_docs/kbn_es_query.devdocs.json @@ -6539,7 +6539,7 @@ " & { meta: ", "PhraseFilterMeta", "; query: { script: { script: ", - "InlineScript", + "Script", "; }; }; }" ], "path": "packages/kbn-es-query/src/filters/build_filters/phrase_filter.ts", @@ -6571,7 +6571,7 @@ "text": "RangeFilterMeta" }, "; query: { script: { script: ", - "InlineScript", + "Script", "; }; }; }" ], "path": "packages/kbn-es-query/src/filters/build_filters/range_filter.ts", diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index c790625b269da..39290298bbf43 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 2bd4e0406c25d..7defc402c73ae 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 48f91348df10d..4682902de18c0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index b7c0236008256..37f59971731b8 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-08-23 +date: 2024-08-27 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 d03a1e2569b14..ceff3fc8ccc09 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.devdocs.json b/api_docs/kbn_esql_validation_autocomplete.devdocs.json index ae6eee29d9988..64858bc5fa7f7 100644 --- a/api_docs/kbn_esql_validation_autocomplete.devdocs.json +++ b/api_docs/kbn_esql_validation_autocomplete.devdocs.json @@ -1100,6 +1100,90 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getColumnForASTNode", + "type": "Function", + "tags": [], + "label": "getColumnForASTNode", + "description": [ + "\nThis function returns the variable or field matching a column" + ], + "signature": [ + "(column: ", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLColumn", + "text": "ESQLColumn" + }, + ", { fields, variables }: Pick<", + "ReferenceMaps", + ", \"fields\" | \"variables\">) => ", + { + "pluginId": "@kbn/esql-validation-autocomplete", + "scope": "common", + "docId": "kibKbnEsqlValidationAutocompletePluginApi", + "section": "def-common.ESQLRealField", + "text": "ESQLRealField" + }, + " | ", + { + "pluginId": "@kbn/esql-validation-autocomplete", + "scope": "common", + "docId": "kibKbnEsqlValidationAutocompletePluginApi", + "section": "def-common.ESQLVariable", + "text": "ESQLVariable" + }, + " | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getColumnForASTNode.$1", + "type": "Object", + "tags": [], + "label": "column", + "description": [], + "signature": [ + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLColumn", + "text": "ESQLColumn" + } + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.getColumnForASTNode.$2", + "type": "Object", + "tags": [], + "label": "{ fields, variables }", + "description": [], + "signature": [ + "Pick<", + "ReferenceMaps", + ", \"fields\" | \"variables\">" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.getCommandDefinition", @@ -2071,90 +2155,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.lookupColumn", - "type": "Function", - "tags": [], - "label": "lookupColumn", - "description": [ - "\nThis function returns the variable or field matching a column" - ], - "signature": [ - "(column: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLColumn", - "text": "ESQLColumn" - }, - ", { fields, variables }: Pick<", - "ReferenceMaps", - ", \"fields\" | \"variables\">) => ", - { - "pluginId": "@kbn/esql-validation-autocomplete", - "scope": "common", - "docId": "kibKbnEsqlValidationAutocompletePluginApi", - "section": "def-common.ESQLRealField", - "text": "ESQLRealField" - }, - " | ", - { - "pluginId": "@kbn/esql-validation-autocomplete", - "scope": "common", - "docId": "kibKbnEsqlValidationAutocompletePluginApi", - "section": "def-common.ESQLVariable", - "text": "ESQLVariable" - }, - " | undefined" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.lookupColumn.$1", - "type": "Object", - "tags": [], - "label": "column", - "description": [], - "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLColumn", - "text": "ESQLColumn" - } - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/esql-validation-autocomplete", - "id": "def-common.lookupColumn.$2", - "type": "Object", - "tags": [], - "label": "{ fields, variables }", - "description": [], - "signature": [ - "Pick<", - "ReferenceMaps", - ", \"fields\" | \"variables\">" - ], - "path": "packages/kbn-esql-validation-autocomplete/src/shared/helpers.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.printFunctionSignature", @@ -3538,6 +3538,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/esql-validation-autocomplete", + "id": "def-common.SuggestionRawDefinition.filterText", + "type": "string", + "tags": [], + "label": "filterText", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-esql-validation-autocomplete/src/autocomplete/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/esql-validation-autocomplete", "id": "def-common.SuggestionRawDefinition.asSnippet", diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 4fc32e0dbb833..2ac95c4c555f1 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 195 | 0 | 183 | 10 | +| 196 | 0 | 184 | 10 | ## Common diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index cfcfcbac790ff..efac234b0c359 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-08-23 +date: 2024-08-27 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 201d15302e23d..c6d229e10c886 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-08-23 +date: 2024-08-27 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 fabd4c9797dcf..3b3bc618408ac 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-08-23 +date: 2024-08-27 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 3df5abc983e9d..6f95154559c0f 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-08-23 +date: 2024-08-27 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 d4767ba61d4d6..840b94c6099f2 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-08-23 +date: 2024-08-27 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 936fae00f3de0..c6792527501e6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_formatters.mdx b/api_docs/kbn_formatters.mdx index 15132a91756c9..975f0d8b3d26c 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-08-23 +date: 2024-08-27 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 ea4d99a5c7849..9c4ce7cd1354f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 3aed8639e099d..cfebddd016b50 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-08-23 +date: 2024-08-27 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 733b3bf34b506..b2e6edad7e89d 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-08-23 +date: 2024-08-27 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 d60ff9aa7b151..c6d1d68f7a327 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-08-23 +date: 2024-08-27 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 7efaa6410796d..1464998937fe7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index b1f65ab2c74ca..d0c7b1be21c63 100644 --- a/api_docs/kbn_grid_layout.mdx +++ b/api_docs/kbn_grid_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grid-layout title: "@kbn/grid-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grid-layout plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index d02cdaa544a2e..e7e86425d091f 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 5d76eb0daf705..84fda653e2328 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 944c854b00c0b..f94a968bc8644 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index 85a31b027cc3e..43784a2c1d056 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-08-23 +date: 2024-08-27 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 bab30589a155f..79395e0977fd1 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-08-23 +date: 2024-08-27 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 c69f9a4f02e9b..0ee681a28e023 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 793e37d5b1158..42732c51a4ffb 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index 06538f7593b5b..28004f413df58 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-08-23 +date: 2024-08-27 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 042c8ef149ca7..a48990ffc2fa5 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-08-23 +date: 2024-08-27 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 a77ce451bf833..d139435df3ccf 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-08-23 +date: 2024-08-27 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 3bb1857a55002..b09f55a9e5f97 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-08-23 +date: 2024-08-27 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 6d97010b6deab..f8aca0a66b844 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-08-23 +date: 2024-08-27 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 83c7603a8eee6..7163a7ed32568 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-08-23 +date: 2024-08-27 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 482f78480bb86..1fc1c9353910c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_investigation_shared.mdx b/api_docs/kbn_investigation_shared.mdx index 00114dcedb219..ac1933bb3dd1b 100644 --- a/api_docs/kbn_investigation_shared.mdx +++ b/api_docs/kbn_investigation_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-investigation-shared title: "@kbn/investigation-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/investigation-shared plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/investigation-shared'] --- import kbnInvestigationSharedObj from './kbn_investigation_shared.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 939696fd3275f..d0f6f93a36eac 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index 4c18ec4b8a35d..8cec6e84ef1ba 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-08-23 +date: 2024-08-27 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 67886fcfe5bc0..df2e9c7a23301 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index a4b0e3eb31fba..1d5b84f2a194e 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-08-23 +date: 2024-08-27 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 86760b2d5710c..7d3fafdc2db73 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_json_schemas.mdx b/api_docs/kbn_json_schemas.mdx index 84200c0b540a3..79935fd0d6a0f 100644 --- a/api_docs/kbn_json_schemas.mdx +++ b/api_docs/kbn_json_schemas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-schemas title: "@kbn/json-schemas" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-schemas plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 0432d74e5d202..fe033bedeb821 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index 4da72c69beebe..d0946f8d0e8ac 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 0884f5dccf462..d8aef714d9841 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-08-23 +date: 2024-08-27 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 4d7ecefbaf477..7a747c70900fa 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-08-23 +date: 2024-08-27 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 6bff491c250c3..e486986a1d1b1 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index ec2301c32e666..6df141252cea5 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-08-23 +date: 2024-08-27 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 8c375eae598d1..1068a46bdf200 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-08-23 +date: 2024-08-27 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 e5c6008ec5b57..a86b9da564a60 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index a2f231ecb1d21..482a1affe0697 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-08-23 +date: 2024-08-27 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 4bce70ade99e9..b8b07cc1545ad 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-08-23 +date: 2024-08-27 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 e7ac38eb898fb..8c96d2c16a813 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-08-23 +date: 2024-08-27 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 b0ce6d16b7b40..154e4bc028289 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-08-23 +date: 2024-08-27 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 d7f9370e5b95c..32813dd411a99 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-08-23 +date: 2024-08-27 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 a873740659c9a..33e21f4205d2f 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-08-23 +date: 2024-08-27 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 751b5dedfd861..ad0c52760082f 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-08-23 +date: 2024-08-27 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 d42edd3de9a9c..980f56f1f6bb2 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-08-23 +date: 2024-08-27 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 ae050205e39ee..e4bd5c7f40094 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-08-23 +date: 2024-08-27 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 1bb6a08ffe9f6..89444186dd490 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-08-23 +date: 2024-08-27 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 b87327074d54b..6fa1f251b0fc7 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-08-23 +date: 2024-08-27 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 6eb49e28483ba..7f6fab807b5f6 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-08-23 +date: 2024-08-27 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 58a03a60f3477..5baf3af31bdb0 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-08-23 +date: 2024-08-27 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 f3eec66312be9..caf901e9b2adf 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-08-23 +date: 2024-08-27 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.devdocs.json b/api_docs/kbn_ml_agg_utils.devdocs.json index 3e2c306db4d73..5994abdf8b656 100644 --- a/api_docs/kbn_ml_agg_utils.devdocs.json +++ b/api_docs/kbn_ml_agg_utils.devdocs.json @@ -698,7 +698,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -734,6 +734,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -792,6 +818,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1386,7 +1414,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1412,7 +1442,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1658,6 +1688,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 323c24eb64fe6..0788af076a72c 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-08-23 +date: 2024-08-27 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 190c97438d167..37b3106e80804 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-08-23 +date: 2024-08-27 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 650dc022bce5f..84d5d09e14d3b 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-08-23 +date: 2024-08-27 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 f28c92bccdd5d..21643d9c482c1 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-08-23 +date: 2024-08-27 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 a676635136e2f..8e5cbb35a5dbc 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-08-23 +date: 2024-08-27 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 b31748d7d63fa..55b4bc658e837 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-08-23 +date: 2024-08-27 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 fb9a745abfce6..bbaf79051310f 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-08-23 +date: 2024-08-27 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 092772ed4e32d..a2401c59a14ba 100644 --- a/api_docs/kbn_ml_date_picker.devdocs.json +++ b/api_docs/kbn_ml_date_picker.devdocs.json @@ -728,7 +728,7 @@ "section": "def-common.RefreshInterval", "text": "RefreshInterval" }, - "; setRefreshInterval: (refreshInterval: Partial<", + "; getMinRefreshInterval: () => number; setRefreshInterval: (refreshInterval: Partial<", { "pluginId": "data", "scope": "common", diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index a0ce2c3363eca..d199168f0da7d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index c68b4d0ce5f9c..e48ca364a2e2d 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-08-23 +date: 2024-08-27 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 f5cdb6905d12b..91f4f290961ad 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-08-23 +date: 2024-08-27 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 ccede0bbd347c..a28085aa353b4 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-08-23 +date: 2024-08-27 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 51d1ff218b1b8..af6d69d9c079c 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-08-23 +date: 2024-08-27 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 ac91ebde6424e..b62cc5822b671 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 06666ff5a9130..422e5c60201a6 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-08-23 +date: 2024-08-27 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 9aff4c2c89e31..cc204d9d961ec 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-08-23 +date: 2024-08-27 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 45c572f3ad966..85197b205df74 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-08-23 +date: 2024-08-27 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 be4b2d3bb0d41..a431ba883a067 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-08-23 +date: 2024-08-27 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 4de3e0922d0ed..6e1b48a2118d9 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-08-23 +date: 2024-08-27 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 05b935ae124bb..def110412a8da 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-08-23 +date: 2024-08-27 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 53802452b622b..52b74aed2dcf2 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-08-23 +date: 2024-08-27 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 032501da24b38..ef36e23dff982 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-08-23 +date: 2024-08-27 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 9012f4734b754..cb20c7911f56e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 5494e0f48311b..a442b83f178de 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-08-23 +date: 2024-08-27 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 1d5aec8db1637..58bf4daeca916 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-08-23 +date: 2024-08-27 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 a0ea7162e6ebb..411ec82b9b901 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-08-23 +date: 2024-08-27 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 99267ec1eef8e..ea636c6b29a2a 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-08-23 +date: 2024-08-27 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 61ad6236ffd63..71c861ce26287 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-08-23 +date: 2024-08-27 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 f536f915eee8f..952cea5ca675a 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-08-23 +date: 2024-08-27 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 80f5f15c88914..5a9b39313757f 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-08-23 +date: 2024-08-27 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 3c435da06b324..22424f19ffeec 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_rule_utils.mdx b/api_docs/kbn_observability_alerting_rule_utils.mdx index 5f2b36e00df43..a7f3bfdfc78de 100644 --- a/api_docs/kbn_observability_alerting_rule_utils.mdx +++ b/api_docs/kbn_observability_alerting_rule_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-rule-utils title: "@kbn/observability-alerting-rule-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-rule-utils plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-rule-utils'] --- import kbnObservabilityAlertingRuleUtilsObj from './kbn_observability_alerting_rule_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 74487dbb1e26c..45b4e9439fab2 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-08-23 +date: 2024-08-27 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 2a69cb9181603..8765cfb145649 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-08-23 +date: 2024-08-27 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 10c3d9080dddd..49b07d4e68f06 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-08-23 +date: 2024-08-27 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 8f8ebf4c05a83..310ce0e970f3e 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-08-23 +date: 2024-08-27 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 cd7e584e46cac..ca28901736540 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index a47312e715cad..8374769babe61 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index 1d1d478e5bf2a..c623a747d1f92 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index eeb34ac211e92..561225ef84ba3 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-08-23 +date: 2024-08-27 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 91a1facd9a015..d5f9db4ad3c1f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_check.mdx b/api_docs/kbn_plugin_check.mdx index 923e0c1a369a1..01125bfede9ef 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-08-23 +date: 2024-08-27 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 0888554bad3b2..8452e5b00c94b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 86708185c11a3..fb46a0911997f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index c972b9db39e86..09aca35c8c683 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index 3669035aecb57..6cdbb1935fb7f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index d108124b24dae..437c50eb2858e 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-08-23 +date: 2024-08-27 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 cb3133473b76f..5d9f7f858bf04 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-08-23 +date: 2024-08-27 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 d69bbf488dce6..c5f428f42e982 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-08-23 +date: 2024-08-27 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 7e0c63f7903d7..b86335808cbff 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-08-23 +date: 2024-08-27 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 a31451fdff77d..99051444ed653 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-08-23 +date: 2024-08-27 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 742711ea7df13..a85b1ebcff194 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-08-23 +date: 2024-08-27 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 eaa364840c153..445f551fc2abd 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-08-23 +date: 2024-08-27 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 1510ae5fb08bc..0ae9eb3256543 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-08-23 +date: 2024-08-27 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 8978384be4b9d..115d877788967 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-08-23 +date: 2024-08-27 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 6e737de92bffc..9efcf620e87fc 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_recently_accessed.mdx b/api_docs/kbn_recently_accessed.mdx index 412632c3b0179..acc96f83709d1 100644 --- a/api_docs/kbn_recently_accessed.mdx +++ b/api_docs/kbn_recently_accessed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-recently-accessed title: "@kbn/recently-accessed" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/recently-accessed plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/recently-accessed'] --- import kbnRecentlyAccessedObj from './kbn_recently_accessed.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 6690b71909a21..8844145592be1 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-08-23 +date: 2024-08-27 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 037b9425a2266..7b82fde6b2d1a 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-08-23 +date: 2024-08-27 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 6217c5ee2337d..31c062c852f83 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-08-23 +date: 2024-08-27 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 1792f4f34c251..87aba75095c4d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 84bb85c9576bc..007843217d3cc 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-08-23 +date: 2024-08-27 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 5779f65ed4495..e9a64666f306e 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-08-23 +date: 2024-08-27 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 df258a3060008..ef16397fb63c5 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-08-23 +date: 2024-08-27 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 55ed57f26c2a1..84bf57f43d8f9 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-08-23 +date: 2024-08-27 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 3db6c8b18236f..7ffb4afa20566 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-08-23 +date: 2024-08-27 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 96ba168b33972..13c7b558aecc9 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-08-23 +date: 2024-08-27 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 d60cf2e162e95..c7df4f2a35bda 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-08-23 +date: 2024-08-27 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 138ea68eab72f..439f54983a057 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-08-23 +date: 2024-08-27 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 b27092487d258..527ef257e206f 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-08-23 +date: 2024-08-27 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 7bc4c52322639..b0740c1f0780f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 5e0a407c85708..04ab2e2a811e6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 6f09bd45a812e..6f0c3bb8d8142 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index 795f9db5861af..a52fa8da91fcc 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 03029eea045a8..e46de85c77888 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rollup.mdx b/api_docs/kbn_rollup.mdx index 01a9638cf1390..60b97a50a443a 100644 --- a/api_docs/kbn_rollup.mdx +++ b/api_docs/kbn_rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rollup title: "@kbn/rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rollup plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rollup'] --- import kbnRollupObj from './kbn_rollup.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index 05ad1ba3e2cec..d3f48e8d7d757 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-08-23 +date: 2024-08-27 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 1b56d5e316cf8..4ecb903b21904 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-08-23 +date: 2024-08-27 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 eae1f1a05b050..e5b9399563b7b 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-08-23 +date: 2024-08-27 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 feac2dff9ed64..49957d43bb9f5 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 8ad8de87939d4..7bfc27355d592 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index 12c57a959b5c0..a01abd70ab52a 100644 --- a/api_docs/kbn_screenshotting_server.mdx +++ b/api_docs/kbn_screenshotting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-screenshotting-server title: "@kbn/screenshotting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/screenshotting-server plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/screenshotting-server'] --- import kbnScreenshottingServerObj from './kbn_screenshotting_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index c4361738cdf67..652436cc2dc9d 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-08-23 +date: 2024-08-27 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.mdx b/api_docs/kbn_search_connectors.mdx index 96dbe8adacaf2..22640dd1b1273 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-08-23 +date: 2024-08-27 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 a4ca5f1ac69fc..573a1a2d7198c 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-08-23 +date: 2024-08-27 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 908d0a740ebd2..2c623dd2691c8 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-08-23 +date: 2024-08-27 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 dc2361bcb7301..f33aed11984d7 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-08-23 +date: 2024-08-27 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 ebcf9f7900675..4ac282e8ebca1 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 9d7c8b27af6db..f6189b9954646 100644 --- a/api_docs/kbn_security_api_key_management.mdx +++ b/api_docs/kbn_security_api_key_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-api-key-management title: "@kbn/security-api-key-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-api-key-management plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-api-key-management'] --- import kbnSecurityApiKeyManagementObj from './kbn_security_api_key_management.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core.mdx b/api_docs/kbn_security_authorization_core.mdx index badff5202e268..593238d47cb2c 100644 --- a/api_docs/kbn_security_authorization_core.mdx +++ b/api_docs/kbn_security_authorization_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core title: "@kbn/security-authorization-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core'] --- import kbnSecurityAuthorizationCoreObj from './kbn_security_authorization_core.devdocs.json'; diff --git a/api_docs/kbn_security_form_components.mdx b/api_docs/kbn_security_form_components.mdx index 030d2324fe4ba..d8387aec6dcb2 100644 --- a/api_docs/kbn_security_form_components.mdx +++ b/api_docs/kbn_security_form_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-form-components title: "@kbn/security-form-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-form-components plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-form-components'] --- import kbnSecurityFormComponentsObj from './kbn_security_form_components.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index fa82b3e9bcfb5..02b95af23522a 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-08-23 +date: 2024-08-27 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 39d351ade594d..998678024f3fd 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-08-23 +date: 2024-08-27 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 80c809cc7dd3a..07ec6782f80ed 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index a2acfc49e4148..a06bff9ce2b9e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_role_management_model.mdx b/api_docs/kbn_security_role_management_model.mdx index 531a52a37c5cd..f71acbae2bc64 100644 --- a/api_docs/kbn_security_role_management_model.mdx +++ b/api_docs/kbn_security_role_management_model.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-role-management-model title: "@kbn/security-role-management-model" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-role-management-model plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-role-management-model'] --- import kbnSecurityRoleManagementModelObj from './kbn_security_role_management_model.devdocs.json'; diff --git a/api_docs/kbn_security_solution_distribution_bar.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index 31306e2d72aab..5bf0cd8b907ae 100644 --- a/api_docs/kbn_security_solution_distribution_bar.mdx +++ b/api_docs/kbn_security_solution_distribution_bar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-distribution-bar title: "@kbn/security-solution-distribution-bar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-distribution-bar plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-distribution-bar'] --- import kbnSecuritySolutionDistributionBarObj from './kbn_security_solution_distribution_bar.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 31137a5d7d719..88581262f9d03 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-08-23 +date: 2024-08-27 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 eb519bebe55ae..d73e565c2d382 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-08-23 +date: 2024-08-27 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 2258cc7d71131..d55725ff48879 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-08-23 +date: 2024-08-27 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 ac60145edc58d..7511ee792f431 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-08-23 +date: 2024-08-27 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 4950f118e8ee7..973abe9ee9af1 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-08-23 +date: 2024-08-27 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 5061443dec2a1..8bafe23e3c1d5 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-08-23 +date: 2024-08-27 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 c58ff670ae158..f927981e3c76f 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-08-23 +date: 2024-08-27 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.devdocs.json b/api_docs/kbn_securitysolution_es_utils.devdocs.json index 11713763f55f1..e7dcb1d4de62f 100644 --- a/api_docs/kbn_securitysolution_es_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_es_utils.devdocs.json @@ -778,7 +778,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; asyncSearch: ", "default", @@ -810,6 +810,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -868,6 +894,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1462,7 +1490,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1488,7 +1518,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1734,6 +1764,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -2058,7 +2090,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; asyncSearch: ", "default", @@ -2090,6 +2122,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -2148,6 +2206,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -2742,7 +2802,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -2768,7 +2830,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -3014,6 +3076,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 6898b0286e09d..7144772c9980e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index ef96444422ce2..7c6f79c3c27f9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 7278c5f686b04..534121d95f21b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 390a0ec22753f..a358d827360c1 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index 224cf584847f1..b8398b5a0ded0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 318bb58a09648..425198e68fa64 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index 74ee5ce8c2bfd..318da48ddaa26 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 657f5f85e2391..65e5148a9331d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index c99f66064bee1..6d573f6f5cc89 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index e9174cdd344dc..1eab2bc0ed216 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index d7d376d363d78..3468d526df5e8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 608ec97b54c9e..05a4daffe5c6a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index aa444eabe5931..b1ed44e073df3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 831e018a82546..b51cc183606cf 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 9921697008aad..5100bf9f97a93 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 5b09548b80c89..0d11189a3ef25 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_client.mdx b/api_docs/kbn_server_route_repository_client.mdx index a734378af95b4..1d83cb20af3b9 100644 --- a/api_docs/kbn_server_route_repository_client.mdx +++ b/api_docs/kbn_server_route_repository_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-client title: "@kbn/server-route-repository-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-client plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-client'] --- import kbnServerRouteRepositoryClientObj from './kbn_server_route_repository_client.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_utils.mdx b/api_docs/kbn_server_route_repository_utils.mdx index 20bf284859ca7..23891106ad167 100644 --- a/api_docs/kbn_server_route_repository_utils.mdx +++ b/api_docs/kbn_server_route_repository_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-utils title: "@kbn/server-route-repository-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-utils plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-utils'] --- import kbnServerRouteRepositoryUtilsObj from './kbn_server_route_repository_utils.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 1de3929c01581..61dafac929b27 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-08-23 +date: 2024-08-27 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 b09ba0b4043c3..c1e8df59b84d8 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-08-23 +date: 2024-08-27 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 7247c3f389f9c..f70c33f9b8247 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-08-23 +date: 2024-08-27 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 3e388102ab34b..442c12f67f7f2 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-08-23 +date: 2024-08-27 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 3a4db5270ae9f..45be2d441bb8a 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-08-23 +date: 2024-08-27 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 b158030222ea1..324655fc2323d 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-08-23 +date: 2024-08-27 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 a03b47edc4bb2..2d3e2564915ef 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index f05ca50ae482b..aae967f68a3f6 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-08-23 +date: 2024-08-27 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 82acd79904a3a..094a565d51d2d 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-08-23 +date: 2024-08-27 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 8cd6d51f54b2c..7640ea9e3ca91 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 2d6623fe92ccc..f5c6d7eea87cb 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 9cca26e4eaa0f..73601f7cdaddd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json index 3b673465c3055..0adc32c67e70c 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json +++ b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json @@ -464,7 +464,7 @@ "section": "def-public.ChromeProjectNavigationNode", "text": "ChromeProjectNavigationNode" }, - ", \"id\" | \"children\" | \"path\" | \"sideNavStatus\"> & { title: React.ReactNode; }" + ", \"id\" | \"children\" | \"path\" | \"sideNavStatus\" | \"deepLink\"> & { title: React.ReactNode; }" ], "path": "packages/shared-ux/chrome/navigation/src/ui/components/panel/types.ts", "deprecated": false, diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 0312bac82fe60..a377faa46c293 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-08-23 +date: 2024-08-27 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 88a54bb14a57b..e32610fbef5e1 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-08-23 +date: 2024-08-27 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 eca64b8995263..f57e2086cebd6 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-08-23 +date: 2024-08-27 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 7a0073e11be1a..b5a4e93b87331 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-08-23 +date: 2024-08-27 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 254c04ad7083d..77c95a810948c 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-08-23 +date: 2024-08-27 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 ffed47c1c4737..917b5b2333728 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-08-23 +date: 2024-08-27 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 b385d83a9a5f5..5ab094f0c0998 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-08-23 +date: 2024-08-27 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 1c63aa07fbf4b..09de63ec5b353 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-08-23 +date: 2024-08-27 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 878bb783e079a..a374a425114b1 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-08-23 +date: 2024-08-27 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 a331639c4ffbb..1bdf08c90ee82 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-08-23 +date: 2024-08-27 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 8bb41978cf5f5..9c5ac68c6c303 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-08-23 +date: 2024-08-27 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 f20211955ad79..bcf34b6ef3392 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 4ab53420a9176..d0aed0b2316a7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index de459da2915c8..5b70a207847bd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 90f4086d6670f..7a21b8493ca77 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 414dec3c3ed76..0d1cf5386c1ca 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index ed53504957d15..b5fac87442b4a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 2b3fb4957d4d7..68321851bfd22 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 739e445148849..710fde66a173c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index e21d27e4abb42..8ee8c50122e85 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index c8fc18951e04f..dc2d925b0b96f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index d59bd03a1c2a6..85b6a53f72741 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index c9d6e5c85886b..560c9d0489351 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index f3b6efaf2fb4f..428b867b21446 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index b7ea8ed510c11..7ffa3ea4574ff 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 7f3f11fb29dde..d5c6199d4cc4c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 23e8dd74d96d4..c9cdda33b1e55 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index 5862bf0cdec99..331eb2df1de59 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-08-23 +date: 2024-08-27 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 cbecc936edfae..422fe9392d236 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 2b1964ae9fbd6..68881e7842119 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index 59e5921d23043..5a6daa4d86af3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 3380fdf3c2038..fb7e548678b19 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index 576eee12e9906..122ff503d0dd4 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_table_persist.mdx b/api_docs/kbn_shared_ux_table_persist.mdx index 33f2a75eeb912..24d4af745e4de 100644 --- a/api_docs/kbn_shared_ux_table_persist.mdx +++ b/api_docs/kbn_shared_ux_table_persist.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-table-persist title: "@kbn/shared-ux-table-persist" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-table-persist plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-table-persist'] --- import kbnSharedUxTablePersistObj from './kbn_shared_ux_table_persist.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index d5c9707572867..2856cf3fc5f1a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 8d1627f084c4a..de90e78bbe94b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 677105b6c7bd9..634de2e778da3 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index 66e63ac694980..5605e34172e00 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-08-23 +date: 2024-08-27 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 5ce583bfa71c4..7d4509c2d6574 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index e298f808ea98c..f4db0b702a9ea 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 2546fa95132e7..891f3a4febf4c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_synthetics_e2e.mdx b/api_docs/kbn_synthetics_e2e.mdx index 9926f39666033..1e145f1a18644 100644 --- a/api_docs/kbn_synthetics_e2e.mdx +++ b/api_docs/kbn_synthetics_e2e.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-e2e title: "@kbn/synthetics-e2e" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-e2e plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-e2e'] --- import kbnSyntheticsE2eObj from './kbn_synthetics_e2e.devdocs.json'; diff --git a/api_docs/kbn_synthetics_private_location.mdx b/api_docs/kbn_synthetics_private_location.mdx index ef4e16584ffe4..84664ce4602b8 100644 --- a/api_docs/kbn_synthetics_private_location.mdx +++ b/api_docs/kbn_synthetics_private_location.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-private-location title: "@kbn/synthetics-private-location" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-private-location plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-private-location'] --- import kbnSyntheticsPrivateLocationObj from './kbn_synthetics_private_location.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 447d21aa5ec39..2eb6cc14c7264 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 54f5af848ac5b..a753af4adf4ba 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-08-23 +date: 2024-08-27 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 49cadfd214ea4..2bd09dcd13d06 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-08-23 +date: 2024-08-27 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 3b9cc45e919d6..ab7d1a7acb987 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 8dceb39f8565f..e7f8d05bea5f8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index 3ec2d1a5a745d..7915972645781 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-08-23 +date: 2024-08-27 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 b11747c1501bd..c4e829ee77482 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-08-23 +date: 2024-08-27 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 27f6b408c8df7..df8071ff2bae3 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-08-23 +date: 2024-08-27 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 a51c1b6173e05..784c136482a24 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-08-23 +date: 2024-08-27 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 fce78359050f7..56f7693e17141 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-08-23 +date: 2024-08-27 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 6caf3ac9d3184..01370ca6bc79c 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-08-23 +date: 2024-08-27 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 4e891254e3d78..37b85246847fe 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index 675e22d08092b..24885548ccb26 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-08-23 +date: 2024-08-27 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 bb0894d12d32a..4745ae503988a 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-08-23 +date: 2024-08-27 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 948d6a0c1dbab..32a3ec515d213 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-08-23 +date: 2024-08-27 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 7deda8b6ae014..c913eec4ea995 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-08-23 +date: 2024-08-27 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 267888acc285f..6645b4a75c39e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 9b11af1fa6cf7..6dda726eb2f67 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index 2abf40ca1dace..8038c5607f6f2 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index 7a7293261be72..3a8e0c8bc43de 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index d1c86be4b386c..3730028bc7038 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index b81852c5e29c7..6e23bd09e9281 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 07dbbf4a5d935..b5360f7bb8a9b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index c64f2dbbf02e7..eba9cbe479837 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 75001a6a02598..d6ea70a2aed24 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index ba20658c91538..6e44040dfdee4 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-08-23 +date: 2024-08-27 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 4b0832d360457..31ad7698725dd 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-08-23 +date: 2024-08-27 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 a19da2fa87b9c..00b688c24559a 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-08-23 +date: 2024-08-27 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.devdocs.json b/api_docs/kbn_yarn_lock_validator.devdocs.json index a23de912a27b9..316310a6c43a7 100644 --- a/api_docs/kbn_yarn_lock_validator.devdocs.json +++ b/api_docs/kbn_yarn_lock_validator.devdocs.json @@ -19,6 +19,84 @@ "common": { "classes": [], "functions": [ + { + "parentPluginId": "@kbn/yarn-lock-validator", + "id": "def-common.findProductionDependencies", + "type": "Function", + "tags": [], + "label": "findProductionDependencies", + "description": [ + "\nGet a list of the all production dependencies for Kibana by starting with the\ndependencies listed in package.json and then traversing deeply into the transitive\ndependencies as declared by the yarn.lock file." + ], + "signature": [ + "(log: ", + { + "pluginId": "@kbn/some-dev-log", + "scope": "common", + "docId": "kibKbnSomeDevLogPluginApi", + "section": "def-common.SomeDevLog", + "text": "SomeDevLog" + }, + ", yarnLock: ", + { + "pluginId": "@kbn/yarn-lock-validator", + "scope": "common", + "docId": "kibKbnYarnLockValidatorPluginApi", + "section": "def-common.YarnLock", + "text": "YarnLock" + }, + ") => Map" + ], + "path": "packages/kbn-yarn-lock-validator/src/find_production_dependencies.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/yarn-lock-validator", + "id": "def-common.findProductionDependencies.$1", + "type": "Object", + "tags": [], + "label": "log", + "description": [], + "signature": [ + { + "pluginId": "@kbn/some-dev-log", + "scope": "common", + "docId": "kibKbnSomeDevLogPluginApi", + "section": "def-common.SomeDevLog", + "text": "SomeDevLog" + } + ], + "path": "packages/kbn-yarn-lock-validator/src/find_production_dependencies.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/yarn-lock-validator", + "id": "def-common.findProductionDependencies.$2", + "type": "Object", + "tags": [], + "label": "yarnLock", + "description": [], + "signature": [ + { + "pluginId": "@kbn/yarn-lock-validator", + "scope": "common", + "docId": "kibKbnYarnLockValidatorPluginApi", + "section": "def-common.YarnLock", + "text": "YarnLock" + } + ], + "path": "packages/kbn-yarn-lock-validator/src/find_production_dependencies.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/yarn-lock-validator", "id": "def-common.readYarnLock", diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 48fdc9abd3372..957417d1279bd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 6 | 0 | 2 | 0 | +| 9 | 0 | 4 | 0 | ## Common diff --git a/api_docs/kbn_zod.mdx b/api_docs/kbn_zod.mdx index ff94665fc5d89..5ff1f59317f45 100644 --- a/api_docs/kbn_zod.mdx +++ b/api_docs/kbn_zod.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod title: "@kbn/zod" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod'] --- import kbnZodObj from './kbn_zod.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 2f47511afeabc..6d577c60ef430 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-08-23 +date: 2024-08-27 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 31e2451f79511..c875f0cbc61de 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 5733095c33f19..5b84c0375f740 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index ffdad60028e3f..0645ecabf59f2 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 7f151cb600d5a..1f6abaa25bc29 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-08-23 +date: 2024-08-27 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 85a362470f83b..c43741ded505e 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index a78936e3541ea..570168a8dd2b8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 414031e0a16ca..82902a4f786e4 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index 4b2b5ca92e7da..1f5315779511a 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-08-23 +date: 2024-08-27 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 57ec05e6a20a2..72b49df0783f8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.devdocs.json b/api_docs/lists.devdocs.json index 4ee259f08b88e..fa444a280770c 100644 --- a/api_docs/lists.devdocs.json +++ b/api_docs/lists.devdocs.json @@ -4535,7 +4535,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -4571,6 +4571,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -4629,6 +4655,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -5223,7 +5251,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -5249,7 +5279,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -5495,6 +5525,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 2e6361544f03c..53a054d43fb22 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-08-23 +date: 2024-08-27 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 17648f309bf24..512a59d0cf859 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-08-23 +date: 2024-08-27 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 c1db007d2bd12..0973459c59bba 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-08-23 +date: 2024-08-27 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 26a9dabfba0d7..2eb3bc8027c02 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-08-23 +date: 2024-08-27 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 e0987b7750b54..da12ff0f537aa 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 81bf336ba778e..d8a4b185e9580 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-08-23 +date: 2024-08-27 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 f1630bb32fb06..65ae1ecf2b5d3 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-08-23 +date: 2024-08-27 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 3d91b9fc9894a..21983f6f07d17 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.devdocs.json b/api_docs/ml.devdocs.json index 5d035e99c13d4..8a976f079a485 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -1343,7 +1343,13 @@ ">; getDataFrameAnalyticsStats(analyticsId?: string | undefined): Promise<", "GetDataFrameAnalyticsStatsResponse", ">; createDataFrameAnalytics(analyticsId: string, analyticsConfig: ", - "DeepPartial", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.DeepPartialObject", + "text": "DeepPartialObject" + }, "<", { "pluginId": "@kbn/ml-data-frame-analytics-utils", @@ -1373,7 +1379,13 @@ ">; jobsExist(analyticsIds: string[], allSpaces?: boolean): Promise<", "JobsExistsResponse", ">; evaluateDataFrameAnalytics(evaluateConfig: any): Promise; explainDataFrameAnalytics(jobConfig: ", - "DeepPartial", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.DeepPartialObject", + "text": "DeepPartialObject" + }, "<", { "pluginId": "@kbn/ml-data-frame-analytics-utils", @@ -1387,7 +1399,13 @@ ">; startDataFrameAnalytics(analyticsId: string): Promise; stopDataFrameAnalytics(analyticsId: string, force?: boolean): Promise; getAnalyticsAuditMessages(analyticsId: string): Promise<", "JobMessage", "[]>; validateDataFrameAnalytics(analyticsConfig: ", - "DeepPartial", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.DeepPartialObject", + "text": "DeepPartialObject" + }, "<", { "pluginId": "@kbn/ml-data-frame-analytics-utils", @@ -1717,10 +1735,10 @@ "text": "ModelConfig" }, "): Promise<", - "InferenceModelConfigContainer", - ">; getAllInferenceEndpoints(): Promise<{ endpoints: ", - "GetInferenceEndpointsResponse", - "[]; }>; }; notifications: { findMessages(params: ", + "InferenceInferenceEndpointInfo", + ">; getAllInferenceEndpoints(): Promise<", + "InferenceGetResponse", + ">; }; notifications: { findMessages(params: ", "NotificationsQueryParams", "): Promise<", "NotificationsSearchResponse", diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 5dc2b430d2128..5c00beaa1f2f0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.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 | |-------------------|-----------|------------------------|-----------------| -| 154 | 3 | 67 | 103 | +| 154 | 3 | 67 | 101 | ## Client diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 6f43591eab849..6df6f57ef01ab 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-08-23 +date: 2024-08-27 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 e097e62b8a5b6..12bef159b0c21 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index ffb6a748dcf4c..9db57429f5cfd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index 9fa3ea112d4ba..7e06a0834bf6d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index b079605cc11ad..1eb4d22046907 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-08-23 +date: 2024-08-27 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 e842e4488d1cb..8d474055489c5 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-08-23 +date: 2024-08-27 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 e65e8b6f565f3..6651a704fce86 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-08-23 +date: 2024-08-27 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 517ebad166e0a..eaa4e3814d3d8 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -5516,7 +5516,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -5552,6 +5552,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -5610,6 +5636,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -6204,7 +6232,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -6230,7 +6260,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -6476,6 +6506,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -6837,7 +6869,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -6873,6 +6905,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -6931,6 +6989,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -7525,7 +7585,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -7551,7 +7613,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -7797,6 +7859,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", @@ -9026,7 +9090,7 @@ "SearchInnerHitsResult", "> | undefined; matched_queries?: string[] | undefined; _nested?: ", "SearchNestedIdentity", - " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", + " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", "SortResults", " | undefined; }>; find: (findParams: { query?: string | undefined; start?: string | undefined; end?: string | undefined; sloId?: string | undefined; sloInstanceId?: string | undefined; serviceName?: string | undefined; }) => Promise<{ items: { id: string | undefined; annotation: { title: string; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }[]; total: number; }>; delete: (deleteParams: { id: string; }) => Promise<", "DeleteByQueryResponse", @@ -12828,7 +12892,7 @@ "SearchInnerHitsResult", "> | undefined; matched_queries?: string[] | undefined; _nested?: ", "SearchNestedIdentity", - " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", + " | undefined; _ignored?: string[] | undefined; ignored_field_values?: Record | undefined; _shard?: string | undefined; _node?: string | undefined; _routing?: string | undefined; _rank?: number | undefined; _seq_no?: number | undefined; _primary_term?: number | undefined; _version?: number | undefined; sort?: ", "SortResults", " | undefined; }>; find: (findParams: { query?: string | undefined; start?: string | undefined; end?: string | undefined; sloId?: string | undefined; sloInstanceId?: string | undefined; serviceName?: string | undefined; }) => Promise<{ items: { id: string | undefined; annotation: { title: string; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }[]; total: number; }>; delete: (deleteParams: { id: string; }) => Promise<", "DeleteByQueryResponse", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 8dfe00bc850e6..0061af2708ea7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index ca2e54657c2e0..e39ad294021e9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index 2785e2169195d..8cbaaa872d4cb 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-08-23 +date: 2024-08-27 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 f920dfbc800b3..9441612794ad0 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-08-23 +date: 2024-08-27 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 3e7947f22d1fe..2740655f8fa99 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-08-23 +date: 2024-08-27 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 22be734488a54..f9dfd904a907b 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-08-23 +date: 2024-08-27 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 2071b367a363e..df83c7a009637 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-08-23 +date: 2024-08-27 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 ab804ae459ced..d28a5118490df 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-08-23 +date: 2024-08-27 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 d7f555f0a84da..2ce6c1982def4 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-08-23 +date: 2024-08-27 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 1ed74c3064395..908398da629f7 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-08-23 +date: 2024-08-27 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 | |--------------|----------|------------------------| -| 843 | 717 | 46 | +| 846 | 719 | 46 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 52603 | 241 | 39516 | 1932 | +| 52632 | 243 | 39544 | 1932 | ## Plugin Directory @@ -142,7 +142,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 209 | 0 | 205 | 28 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | - | 60 | 0 | 60 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Exposes utilities for accessing metrics data | 128 | 8 | 128 | 5 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 154 | 3 | 67 | 103 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 154 | 3 | 67 | 101 | | | [@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 | @@ -179,6 +179,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | AI Assistant for Search | 6 | 0 | 6 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin hosting shared features for connectors | 19 | 0 | 19 | 3 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 10 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 10 | 0 | 10 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 10 | 0 | 6 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin to provide access to and rendering of python notebooks for use in the persistent developer console. | 10 | 0 | 10 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 17 | 0 | 11 | 1 | @@ -207,7 +208,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 226 | 1 | 182 | 17 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [@elastic/kibana-localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 590 | 1 | 564 | 51 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 591 | 1 | 565 | 51 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 156 | 0 | 110 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 212 | 0 | 145 | 11 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). | 15 | 0 | 10 | 3 | @@ -255,8 +256,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 4 | 0 | 4 | 0 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 51 | 0 | 51 | 9 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 201 | 0 | 201 | 31 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 53 | 0 | 53 | 9 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 204 | 0 | 204 | 33 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 316 | 0 | 315 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 11 | 0 | 11 | 0 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 3 | 0 | 3 | 0 | @@ -265,6 +266,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 10 | 0 | 10 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 7 | 0 | 7 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 19 | 0 | 16 | 0 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 2 | 9 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 44 | 1 | 30 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 23 | 0 | 19 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 84 | 0 | 84 | 0 | @@ -507,7 +509,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@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) | - | 152 | 1 | 120 | 15 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 66 | 0 | 62 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 195 | 0 | 183 | 10 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 196 | 0 | 184 | 10 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 40 | 0 | 40 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 39 | 0 | 14 | 1 | @@ -768,7 +770,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 146 | 0 | 143 | 3 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 19 | 0 | 17 | 1 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 13 | 0 | 13 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 2 | 0 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1254 | 0 | 4 | 0 | | | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 20 | 0 | 10 | 0 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index aa02f40aef7d0..26d7c9c969ddc 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-08-23 +date: 2024-08-27 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 9eaf48a3622a6..923fe76dbc464 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index bac059a68f37f..c30d5f49f61ce 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-08-23 +date: 2024-08-27 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 cb6172c4e273e..5e0fc31881f4b 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-08-23 +date: 2024-08-27 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 3d1c7cf8bdcb8..e3aecf65ea502 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index ad4cc2ae99a86..719d6340a68cc 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index 440ece81cf7d0..093bf4409da7f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index af74a4e3d7437..8558cf0f6e0aa 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index 1a4b2fceb9993..524d0519041a4 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 1abdfa387d38a..55ffba4f93e71 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index cbbb5f60a7271..7835452fc8e1b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index cca089333172c..66a83f84b9ae8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index 12f594b03c2c4..da2d0665bab32 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 812997c8ddd93..ce9d137330667 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index 1179462c13786..6493c183bf1d7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 464b53f00ebd7..7c9f3dac7cf17 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index a887bade5e4c8..de3a94a7d7cd9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_assistant.mdx b/api_docs/search_assistant.mdx index c84725550c6d2..91e578291858c 100644 --- a/api_docs/search_assistant.mdx +++ b/api_docs/search_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchAssistant title: "searchAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the searchAssistant plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchAssistant'] --- import searchAssistantObj from './search_assistant.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index 50d26e136591e..e906c5523870a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index 4bdd9c8b64b6a..d14cd8e67279f 100644 --- a/api_docs/search_homepage.mdx +++ b/api_docs/search_homepage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchHomepage title: "searchHomepage" image: https://source.unsplash.com/400x175/?github description: API docs for the searchHomepage plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_indices.devdocs.json b/api_docs/search_indices.devdocs.json new file mode 100644 index 0000000000000..e79f47a7894f0 --- /dev/null +++ b/api_docs/search_indices.devdocs.json @@ -0,0 +1,171 @@ +{ + "id": "searchIndices", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "searchIndices", + "id": "def-public.SearchIndicesPluginSetup", + "type": "Interface", + "tags": [], + "label": "SearchIndicesPluginSetup", + "description": [], + "path": "x-pack/plugins/search_indices/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "searchIndices", + "id": "def-public.SearchIndicesPluginStart", + "type": "Interface", + "tags": [], + "label": "SearchIndicesPluginStart", + "description": [], + "path": "x-pack/plugins/search_indices/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "searchIndices", + "id": "def-server.SearchIndicesPluginSetup", + "type": "Interface", + "tags": [], + "label": "SearchIndicesPluginSetup", + "description": [], + "path": "x-pack/plugins/search_indices/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "searchIndices", + "id": "def-server.SearchIndicesPluginStart", + "type": "Interface", + "tags": [], + "label": "SearchIndicesPluginStart", + "description": [], + "path": "x-pack/plugins/search_indices/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "searchIndices", + "id": "def-common.IndicesStatusResponse", + "type": "Interface", + "tags": [], + "label": "IndicesStatusResponse", + "description": [], + "path": "x-pack/plugins/search_indices/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchIndices", + "id": "def-common.IndicesStatusResponse.indexNames", + "type": "Array", + "tags": [], + "label": "indexNames", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/search_indices/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "searchIndices", + "id": "def-common.UserStartPrivilegesResponse", + "type": "Interface", + "tags": [], + "label": "UserStartPrivilegesResponse", + "description": [], + "path": "x-pack/plugins/search_indices/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchIndices", + "id": "def-common.UserStartPrivilegesResponse.privileges", + "type": "Object", + "tags": [], + "label": "privileges", + "description": [], + "signature": [ + "{ canCreateApiKeys: boolean; canCreateIndex: boolean; }" + ], + "path": "x-pack/plugins/search_indices/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "searchIndices", + "id": "def-common.PLUGIN_ID", + "type": "string", + "tags": [], + "label": "PLUGIN_ID", + "description": [], + "signature": [ + "\"searchIndices\"" + ], + "path": "x-pack/plugins/search_indices/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "searchIndices", + "id": "def-common.PLUGIN_NAME", + "type": "string", + "tags": [], + "label": "PLUGIN_NAME", + "description": [], + "signature": [ + "\"searchIndices\"" + ], + "path": "x-pack/plugins/search_indices/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/search_indices.mdx b/api_docs/search_indices.mdx new file mode 100644 index 0000000000000..1812f60b5c8b9 --- /dev/null +++ b/api_docs/search_indices.mdx @@ -0,0 +1,49 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibSearchIndicesPluginApi +slug: /kibana-dev-docs/api/searchIndices +title: "searchIndices" +image: https://source.unsplash.com/400x175/?github +description: API docs for the searchIndices plugin +date: 2024-08-27 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchIndices'] +--- +import searchIndicesObj from './search_indices.devdocs.json'; + + + +Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 10 | 0 | 10 | 0 | + +## Client + +### Setup + + +### Start + + +## Server + +### Setup + + +### Start + + +## Common + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index eac1d82c53b30..f2ace37c453c9 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index 65d41d4067493..96eeb74884b60 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-08-23 +date: 2024-08-27 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 6ac3a66ad4359..831135e7c8899 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index eb269da0adc38..e289d2ade1afa 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index d8012610139a2..ae4e037e5e71d 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -3324,7 +3324,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly responseActionScanEnabled: true; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly assistantBedrockChat: true; readonly newUserDetailsFlyoutManagedUser: false; 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: true; readonly jamfDataInAnalyzerEnabled: false; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly responseActionScanEnabled: true; readonly securitySolutionNotesEnabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly assistantKnowledgeBaseByDefault: false; readonly assistantBedrockChat: true; readonly newUserDetailsFlyoutManagedUser: false; 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: true; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly unifiedComponentsInTimelineDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly manualRuleRunEnabled: false; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: 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 da1e6a70bf239..77b452878fa70 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-08-23 +date: 2024-08-27 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 95a511f99d1da..3d9049b43d2c2 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-08-23 +date: 2024-08-27 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 4d2303631756e..7f401033ab837 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-08-23 +date: 2024-08-27 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 ab11d0ad37ef8..3a66ca3ae8c1b 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-08-23 +date: 2024-08-27 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 7f655fca58e0b..7507c218b3ad9 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-08-23 +date: 2024-08-27 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 3ce5854182cd4..25f8e60fcd4bf 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-08-23 +date: 2024-08-27 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 7277033802b1d..81fa8b0bd5ccd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index 9217a1297810a..8840b6fe9b7cf 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index d0007f69c9928..44d6d76eec612 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-08-23 +date: 2024-08-27 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 fb57b41f6e06d..7866c061cf7be 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index e3703e983e728..07eff2e32f515 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 642db789beb54..b8475bcdf867f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index 80b4556a34fff..82ebcf572b38c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.devdocs.json b/api_docs/task_manager.devdocs.json index 3793c0f0f87e4..8a7db40cdda12 100644 --- a/api_docs/task_manager.devdocs.json +++ b/api_docs/task_manager.devdocs.json @@ -300,7 +300,7 @@ "label": "stop", "description": [], "signature": [ - "() => void" + "() => Promise" ], "path": "x-pack/plugins/task_manager/server/plugin.ts", "deprecated": false, diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index edebb8a295200..9975a683c2fc6 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 14742dff6ee7c..0092af0da949f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.devdocs.json b/api_docs/telemetry_collection_manager.devdocs.json index 89928b629a3db..549b935636476 100644 --- a/api_docs/telemetry_collection_manager.devdocs.json +++ b/api_docs/telemetry_collection_manager.devdocs.json @@ -216,7 +216,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -252,6 +252,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -310,6 +336,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -904,7 +932,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -930,7 +960,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1176,6 +1206,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index 5912c990dcfde..50b7b81a75760 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index a74c217d3c4a4..08d7f118d0da8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 3cd851a6b90c2..750e14de23137 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 82b36503730a2..ace667e6e035d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index ddc62457e8849..7d2ca3e44137f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 9792b40c46aca..4182ee2d921a7 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index 5c0b17eb4499f..925b73c56806c 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -9645,7 +9645,7 @@ "label": "parseAggregationResults", "description": [], "signature": [ - "({ isCountAgg, isGroupAgg, esResult, resultLimit, sourceFieldsParams, generateSourceFieldsFromHits, }: ParseAggregationResultsOpts) => ", + "({ isCountAgg, isGroupAgg, esResult, resultLimit, sourceFieldsParams, generateSourceFieldsFromHits, termField, }: ParseAggregationResultsOpts) => ", { "pluginId": "triggersActionsUi", "scope": "common", @@ -9663,7 +9663,7 @@ "id": "def-common.parseAggregationResults.$1", "type": "Object", "tags": [], - "label": "{\n isCountAgg,\n isGroupAgg,\n esResult,\n resultLimit,\n sourceFieldsParams = [],\n generateSourceFieldsFromHits = false,\n}", + "label": "{\n isCountAgg,\n isGroupAgg,\n esResult,\n resultLimit,\n sourceFieldsParams = [],\n generateSourceFieldsFromHits = false,\n termField,\n}", "description": [], "signature": [ "ParseAggregationResultsOpts" @@ -10133,6 +10133,27 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-common.ParsedAggregationGroup.groups", + "type": "Array", + "tags": [], + "label": "groups", + "description": [], + "signature": [ + { + "pluginId": "@kbn/observability-alerting-rule-utils", + "scope": "common", + "docId": "kibKbnObservabilityAlertingRuleUtilsPluginApi", + "section": "def-common.Group", + "text": "Group" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/triggers_actions_ui/common/data/lib/parse_aggregation_results.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "triggersActionsUi", "id": "def-common.ParsedAggregationGroup.value", diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index b5fe646028a5d..dd0573a7dad31 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 590 | 1 | 564 | 51 | +| 591 | 1 | 565 | 51 | ## Client diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 14bf81bcfef85..147415a02455d 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-08-23 +date: 2024-08-27 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 1fdb07fde8da0..bc047abd77f93 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-08-23 +date: 2024-08-27 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 edd5423d1971a..6e9dc36957bab 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-08-23 +date: 2024-08-27 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 7f9551ac55cc4..28ebf3b09f032 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index fbf5c170e1168..a9acfbdc11377 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -626,7 +626,7 @@ }, "[] | undefined; iconType?: ", "IconType", - " | undefined; showQueryInput?: boolean | undefined; dataTestSubj?: string | undefined; showSaveQuery?: boolean | undefined; customSubmitButton?: React.ReactNode; dataViewPickerOverride?: React.ReactNode; screenTitle?: string | undefined; showQueryMenu?: boolean | undefined; showFilterBar?: boolean | undefined; showDatePicker?: boolean | undefined; showAutoRefreshOnly?: boolean | undefined; additionalQueryBarMenuItems?: ", + " | undefined; showQueryInput?: boolean | undefined; dataTestSubj?: string | undefined; minRefreshInterval?: number | undefined; showSaveQuery?: boolean | undefined; customSubmitButton?: React.ReactNode; dataViewPickerOverride?: React.ReactNode; screenTitle?: string | undefined; showQueryMenu?: boolean | undefined; showFilterBar?: boolean | undefined; showDatePicker?: boolean | undefined; showAutoRefreshOnly?: boolean | undefined; additionalQueryBarMenuItems?: ", "AdditionalQueryBarMenuItems", " | undefined; filtersForSuggestions?: ", { diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 54b7c47deb42c..71c9f28b32724 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index e90d4de39f9c7..47c6345975227 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-08-23 +date: 2024-08-27 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 4ddc4f8074f00..ddddde515e257 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-08-23 +date: 2024-08-27 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 6b64db71f7dc8..fe41ec1fa440d 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.devdocs.json b/api_docs/usage_collection.devdocs.json index c807c2733c9d6..04dc99f0bda52 100644 --- a/api_docs/usage_collection.devdocs.json +++ b/api_docs/usage_collection.devdocs.json @@ -483,7 +483,7 @@ "TransportRequestOptions", " | undefined): Promise<", "SearchResponse", - ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kQueryRuleset]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", + ">; }; name: string | symbol; [kAsyncSearch]: symbol | null; [kAutoscaling]: symbol | null; [kCat]: symbol | null; [kCcr]: symbol | null; [kCluster]: symbol | null; [kConnector]: symbol | null; [kDanglingIndices]: symbol | null; [kEnrich]: symbol | null; [kEql]: symbol | null; [kEsql]: symbol | null; [kFeatures]: symbol | null; [kFleet]: symbol | null; [kGraph]: symbol | null; [kIlm]: symbol | null; [kIndices]: symbol | null; [kInference]: symbol | null; [kIngest]: symbol | null; [kLicense]: symbol | null; [kLogstash]: symbol | null; [kMigration]: symbol | null; [kMl]: symbol | null; [kMonitoring]: symbol | null; [kNodes]: symbol | null; [kProfiling]: symbol | null; [kQueryRules]: symbol | null; [kRollup]: symbol | null; [kSearchApplication]: symbol | null; [kSearchableSnapshots]: symbol | null; [kSecurity]: symbol | null; [kShutdown]: symbol | null; [kSimulate]: symbol | null; [kSlm]: symbol | null; [kSnapshot]: symbol | null; [kSql]: symbol | null; [kSsl]: symbol | null; [kSynonyms]: symbol | null; [kTasks]: symbol | null; [kTextStructure]: symbol | null; [kTransform]: symbol | null; [kWatcher]: symbol | null; [kXpack]: symbol | null; transport: ", "default", "; child: (opts: ", "ClientOptions", @@ -519,6 +519,32 @@ "TransportRequestOptions", " | undefined): Promise<", "BulkResponse", + ">; }; capabilities: { (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithOutMeta", + " | undefined): Promise<", + "TODO", + ">; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptionsWithMeta", + " | undefined): Promise<", + "TransportResult", + "<", + "TODO", + ", unknown>>; (this: That, params?: ", + "TODO", + " | ", + "TODO", + " | undefined, options?: ", + "TransportRequestOptions", + " | undefined): Promise<", + "TODO", ">; }; cat: ", "default", "; ccr: ", @@ -577,6 +603,8 @@ "ClosePointInTimeResponse", ">; }; cluster: ", "default", + "; connector: ", + "default", "; count: { (this: That, params?: ", "CountRequest", " | ", @@ -1171,7 +1199,9 @@ "PingRequest", " | undefined, options?: ", "TransportRequestOptions", - " | undefined): Promise; }; putScript: { (this: That, params: ", + " | undefined): Promise; }; profiling: ", + "default", + "; putScript: { (this: That, params: ", "PutScriptRequest", " | ", "PutScriptRequest", @@ -1197,7 +1227,7 @@ "TransportRequestOptions", " | undefined): Promise<", "AcknowledgedResponseBase", - ">; }; queryRuleset: ", + ">; }; queryRules: ", "default", "; rankEval: { (this: That, params: ", "RankEvalRequest", @@ -1443,6 +1473,8 @@ "default", "; shutdown: ", "default", + "; simulate: ", + "default", "; slm: ", "default", "; snapshot: ", diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 2403b51076c6f..1986d4cc93a16 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index ddf0576809d6d..52db8bff35a05 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index c27f7da18f709..9bc6e6e6365ad 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 666ce1d6d2e93..7b5e9d38452bd 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 84d46e34098b2..0922ed4326778 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index 410042f5b675b..ff203dbd3293b 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index e1ead079f5fb6..99d6c80770730 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index 985bff449c64e..1e4c96030615c 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index 65771f0f50810..8400a667f3f2f 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 4822e0c936b06..b00f3eb7627c8 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index f493ff35e75da..a1abd27f4405a 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 1de84e76ab942..23bbfa5922da0 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index 47f45c79e7b3c..b49f7ebbcaa5f 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -4320,7 +4320,7 @@ "section": "def-common.RefreshInterval", "text": "RefreshInterval" }, - "; setRefreshInterval: (refreshInterval: Partial<", + "; getMinRefreshInterval: () => number; setRefreshInterval: (refreshInterval: Partial<", { "pluginId": "data", "scope": "common", diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index a400a3f4386f2..4e0c973ce0fb9 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-08-23 +date: 2024-08-27 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/serverless.security.yml b/config/serverless.security.yml index 6f39182d1e2e6..b5922379f3c4b 100644 --- a/config/serverless.security.yml +++ b/config/serverless.security.yml @@ -106,3 +106,8 @@ xpack.ml.compatibleModuleType: 'security' # Disable the embedded Dev Console console.ui.embeddedEnabled: false + +# mTLS cert paths for agentless-api calls +xpack.fleet.agentless.api.tls.certificate: "/mnt/elastic-internal/http-certs/tls.crt" +xpack.fleet.agentless.api.tls.key: "/mnt/elastic-internal/http-certs/tls.key" +xpack.fleet.agentless.api.tls.ca: "/mnt/elastic-internal/http-certs/ca.crt" diff --git a/dev_docs/getting_started/setting_up_a_development_env.mdx b/dev_docs/getting_started/setting_up_a_development_env.mdx index 49b745f9d0f0d..a63dfdce59b4d 100644 --- a/dev_docs/getting_started/setting_up_a_development_env.mdx +++ b/dev_docs/getting_started/setting_up_a_development_env.mdx @@ -3,8 +3,8 @@ id: kibDevTutorialSetupDevEnv slug: /kibana-dev-docs/getting-started/setup-dev-env title: Set up a Development Environment description: Learn how to setup a development environment for contributing to the Kibana repository -date: 2022-07-07 -tags: ['kibana', 'onboarding', 'dev', 'architecture', 'setup'] +date: 2024-08-09 +tags: ['kibana', 'onboarding', 'dev', 'architecture', 'setup', 'devcontainer'] --- Setting up a development environment is pretty easy. @@ -92,3 +92,28 @@ node scripts/register_git_hook ``` After the script completes the pre-commit hook will be created within the file `.git/hooks/pre-commit`. If you choose to not install it, don’t worry, we still run a quick CI check to provide feedback earliest as we can about the same checks. + +## Using the Kibana Dev Container (optional) + +Kibana also supports using a [dev container](https://containers.dev/) which can integrate with various editors and tools [(supported tools)](https://containers.dev/supporting). The dev container provides a consistent development environment across different machines and setups which is based on Ubuntu Jammy (22.04). The only prerequisite is having [Docker](https://www.docker.com/) installed locally. VS Code is the recommended editor and will be used for these instructions because it is the most mature, but it is not required. + +### Setting up the Dev Container + +1. Make a copy of `.devcontainer/.env.template` and rename it to `.devcontainer/.env`. Edit any values you're interested in. +1. There are three options for mounting the Kibana repo into the container: + - **Local Filesystem**: Clone the repo locally, or use an existing copy, and open it in VS Code. When prompted, select "Reopen in Dev Container". This uses a bind mount, allowing the container to access and modify files directly on your local filesystem. Your git credentials should be automatically mounted in the container as well. Note that Bazel will create symlinks and a cache inside the container file system. So, if switching to working on your local filesystem afterwards, you will need to bootstrap again. + - **Docker Repo Volume**: Use the `Dev Containers: Clone Repository in Named Container Volume...` command from the Command Palette (`F1`). This clones the repo into a Docker volume, isolating it from your local filesystem. You will need to configure your git credentials manually in this isolated environment. + - **Docker PR Volume**: Use the `Dev Containers: Clone GitHub Pull Request in Named Container Volume...` command from the Command Palette (`F1`). This is the same as the previous option, but can be useful for testing a PR in insolation of your local filesystem. +1. VS Code will then build the container, this will take a few minutes the first time, but subsequent builds will utilize Docker caching and be much faster. +1. Once the container is built and started, it will automatically run `yarn kbn bootstrap`. +1. You should see the Kibana repo and your terminal will be inside the container. You can develop as normal now, including running `yarn es` from inside the container. + +### Customizing the Dev Container +Installing any extra extensions or making adjustments to the OS environment inside the container will not have an effect on your local OS or VS Code installation. Editing the `devcontainer.json` or `.devcontainer/Dockerfile` should be reserved for changes to all dev environments. + +### FIPS Mode + +The dev container is pre-configured to run Kibana in FIPS mode if needed. Simply change the `.env` file to `FIPS=1` and reopen your terminal. There should be a log message in your terminal which indicates `FIPS mode enabled`. + +### Troubleshooting +- Sometimes when rebuilding the container, there will be an error message that it failed. Usually hitting retry will fix this, and is only related to VS Code trying to reconnect to the container too quickly. \ No newline at end of file diff --git a/dev_docs/operations/writing_stable_functional_tests.mdx b/dev_docs/operations/writing_stable_functional_tests.mdx index 9403b9144260d..42aadf702ba92 100644 --- a/dev_docs/operations/writing_stable_functional_tests.mdx +++ b/dev_docs/operations/writing_stable_functional_tests.mdx @@ -75,6 +75,10 @@ await testSubjects.existsOrFail('savedItemDetailPage') Even if you are very careful, the more UI automation you do the more likely you are to make a mistake and write a flaky test. If there is any way to do setup work for your test via the Kibana or Elasticsearch APIs rather than interacting with the UI, then take advantage of that opportunity to write less UI automation. +## Incorrect usage of EUI components in React code will cause a functional test failure + +For EUI to support theming and internationalization, EUI components in your React application must be wrapped in `EuiProvider` (more preferably, use the `KibanaRenderContextProvider` wrapper). The functional test runner treats EUI as a first-class citizen and will throw an error when incorrect usage of EUI is detected. However, experiencing this type of failure in a test run is unlikely: in dev mode, a toast message alerts developers of incorrect EUI usage in real-time. + ## Do you really need a functional test for this? Once you've invested a lot of time and energy into figuring out how to write functional tests well it can be tempting to use them for all sorts of things which might not justify the cost of a functional test. Make sure that your test is validating something that couldn't be validated by a series of unit tests on a component+store+API. diff --git a/dev_docs/tutorials/performance/adding_custom_performance_metrics.mdx b/dev_docs/tutorials/performance/adding_custom_performance_metrics.mdx index 1c1224c1c858a..37322e3f55e05 100644 --- a/dev_docs/tutorials/performance/adding_custom_performance_metrics.mdx +++ b/dev_docs/tutorials/performance/adding_custom_performance_metrics.mdx @@ -294,6 +294,58 @@ This event will be indexed with the following structure: } ``` +#### Add custom metrics +Having `kibana:plugin_render_time` metric event is not always enough, depending on the use case you would likely need some complementary information to give some sense to the value reported by the metric (e.g. number of hosts, number of services, number of dataStreams, etc). +`kibana:plugin_render_time` metric API supports up to 9 numbered free fields that can be used to report numeric metrics that you intend to analyze. Note that they can be used for any type of numeric information you may want to report. + +We could make use of these custom metrics using the following format: + +```typescript +... + // Call onPageReady once the meaningful data has rendered and visible to the user + onPageReady({ + key1: 'datasets', + value1: 5, + key2: 'documents', + value2: 1000, + }); +... +``` + +where the `keys` will be the keys for the custom metrics we can later aggregate and analyze further. + +An event using custom metrics will be indexed with the following structure: + +```typescript +{ + "_index": "backing-ebt-kibana-browser-performance-metrics-000001", // Performance metrics are stored in a dedicated simplified index (browser \ server). + "_source": { + "timestamp": "2024-08-13T11:29:58.275Z" + "event_type": "performance_metric", // All performance events share a common event type to simplify mapping + "eventName": 'kibana:plugin_render_time', // Event name as specified when reporting it + "duration": 736, // Event duration as specified when reporting it + "meta": { + "target": '/home', + }, + "context": { // Context holds information identifying the deployment, version, application and page that generated the event + "version": "8.16.0-SNAPSHOT", + "cluster_name": "elasticsearch", + "pageName": "application:home:app", + "applicationId": "home", + "page": "app", + "entityId": "61c58ad0-3dd3-11e8-b2b9-5d5dc1715159", + "branch": "main", + ... + }, + "key1": "datasets", + "value1": 5, + "key2": "documents", + "value2": 1000, + ... + }, +} +``` + ### Development environment The metric will be delivered to the [Telemetry Staging](https://telemetry-v2-staging.elastic.dev/) cluster, alongside with the event's context. diff --git a/package.json b/package.json index 6e1a4a4a7f6ef..78d2e97408fa0 100644 --- a/package.json +++ b/package.json @@ -199,6 +199,7 @@ "@kbn/cases-api-integration-test-plugin": "link:x-pack/test/cases_api_integration/common/plugins/cases", "@kbn/cases-components": "link:packages/kbn-cases-components", "@kbn/cases-plugin": "link:x-pack/plugins/cases", + "@kbn/cbor": "link:packages/kbn-cbor", "@kbn/cell-actions": "link:packages/kbn-cell-actions", "@kbn/chart-expressions-common": "link:src/plugins/chart_expressions/common", "@kbn/chart-icons": "link:packages/kbn-chart-icons", @@ -478,6 +479,7 @@ "@kbn/esql-utils": "link:packages/kbn-esql-utils", "@kbn/esql-validation-autocomplete": "link:packages/kbn-esql-validation-autocomplete", "@kbn/esql-validation-example-plugin": "link:examples/esql_validation_example", + "@kbn/eui-provider-dev-warning": "link:test/plugin_functional/plugins/eui_provider_dev_warning", "@kbn/event-annotation-common": "link:packages/kbn-event-annotation-common", "@kbn/event-annotation-components": "link:packages/kbn-event-annotation-components", "@kbn/event-annotation-listing-plugin": "link:src/plugins/event_annotation_listing", @@ -538,6 +540,7 @@ "@kbn/guided-onboarding-plugin": "link:src/plugins/guided_onboarding", "@kbn/handlebars": "link:packages/kbn-handlebars", "@kbn/hapi-mocks": "link:packages/kbn-hapi-mocks", + "@kbn/hardening-plugin": "link:test/plugin_functional/plugins/hardening", "@kbn/health-gateway-server": "link:packages/kbn-health-gateway-server", "@kbn/hello-world-plugin": "link:examples/hello_world", "@kbn/home-plugin": "link:src/plugins/home", @@ -775,6 +778,7 @@ "@kbn/security-plugin-types-public": "link:x-pack/packages/security/plugin_types_public", "@kbn/security-plugin-types-server": "link:x-pack/packages/security/plugin_types_server", "@kbn/security-role-management-model": "link:x-pack/packages/security/role_management_model", + "@kbn/security-solution-common": "link:x-pack/packages/security-solution/common", "@kbn/security-solution-distribution-bar": "link:x-pack/packages/security-solution/distribution_bar", "@kbn/security-solution-ess": "link:x-pack/plugins/security_solution_ess", "@kbn/security-solution-features": "link:x-pack/packages/security-solution/features", @@ -1028,13 +1032,13 @@ "base64-js": "^1.3.1", "bitmap-sdf": "^1.0.3", "blurhash": "^2.0.1", + "borc": "3.0.0", "brace": "0.11.1", "brok": "^5.0.2", "byte-size": "^8.1.0", "cacheable-lookup": "6", "camelcase-keys": "7.0.2", "canvg": "^3.0.9", - "cbor-x": "^1.3.3", "chalk": "^4.1.0", "cheerio": "^1.0.0-rc.12", "chroma-js": "^2.1.0", @@ -1293,10 +1297,10 @@ "@frsource/cypress-plugin-visual-regression-diff": "^3.3.10", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@istanbuljs/schema": "^0.1.2", - "@jest/console": "^29.6.1", - "@jest/reporters": "^29.6.1", + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", "@jest/transform": "^29.6.1", - "@jest/types": "^29.6.1", + "@jest/types": "^29.6.3", "@kayahr/text-encoding": "^1.3.0", "@kbn/alerting-api-integration-helpers": "link:x-pack/test/alerting_api_integration/packages/helpers", "@kbn/ambient-common-types": "link:packages/kbn-ambient-common-types", @@ -1313,6 +1317,7 @@ "@kbn/bazel-runner": "link:packages/kbn-bazel-runner", "@kbn/capture-oas-snapshot-cli": "link:packages/kbn-capture-oas-snapshot-cli", "@kbn/check-mappings-update-cli": "link:packages/kbn-check-mappings-update-cli", + "@kbn/check-prod-native-modules-cli": "link:packages/kbn-check-prod-native-modules-cli", "@kbn/ci-stats-core": "link:packages/kbn-ci-stats-core", "@kbn/ci-stats-performance-metrics": "link:packages/kbn-ci-stats-performance-metrics", "@kbn/ci-stats-reporter": "link:packages/kbn-ci-stats-reporter", @@ -1629,7 +1634,7 @@ "argsplit": "^1.0.5", "autoprefixer": "^10.4.7", "axe-core": "^4.10.0", - "babel-jest": "^29.6.1", + "babel-jest": "^29.7.0", "babel-loader": "^8.2.5", "babel-plugin-add-module-exports": "^1.0.4", "babel-plugin-istanbul": "^6.1.1", @@ -1683,7 +1688,7 @@ "eslint-plugin-react-perf": "^3.3.1", "eslint-traverse": "^1.0.0", "exit-hook": "^2.2.0", - "expect": "^29.6.1", + "expect": "^29.7.0", "expose-loader": "^0.7.5", "express": "^4.19.2", "faker": "^5.1.0", @@ -1702,16 +1707,16 @@ "http2-proxy": "^5.0.53", "http2-wrapper": "^2.2.1", "ignore": "^5.3.0", - "jest": "^29.6.1", + "jest": "^29.7.0", "jest-canvas-mock": "^2.5.2", - "jest-cli": "^29.6.1", - "jest-config": "^29.6.1", - "jest-diff": "^29.6.1", - "jest-environment-jsdom": "^29.6.1", - "jest-matcher-utils": "^29.6.1", - "jest-mock": "^29.6.1", - "jest-runtime": "^29.6.1", - "jest-snapshot": "^29.6.1", + "jest-cli": "^29.7.0", + "jest-config": "^29.7.0", + "jest-diff": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", "jest-specific-snapshot": "^8.0.0", "jest-styled-components": "7.0.3", "jsdom": "^20.0.1", diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 5f9a17713861c..0b7f0e8afd958 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -180,14 +180,24 @@ export class ChromeService { if (isDev) { setEuiDevProviderWarning((providerError) => { const errorObject = new Error(providerError.toString()); - // show a stack trace in the console + // 1. show a stack trace in the console // eslint-disable-next-line no-console console.error(errorObject); + // 2. store error in sessionStorage so it can be detected in testing + const storedError = { + message: providerError.toString(), + stack: errorObject.stack ?? 'undefined', + pageHref: window.location.href, + pageTitle: document.title, + }; + sessionStorage.setItem('dev.euiProviderWarning', JSON.stringify(storedError)); + + // 3. error toast / popup notifications.toasts.addDanger({ title: '`EuiProvider` is missing', text: mountReactNode( -

+

), + 'data-test-subj': 'core-chrome-euiDevProviderWarning-toast', toastLifeTimeMs: 60 * 60 * 1000, // keep message visible for up to an hour }); }); 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 0a1292be9b3f1..0c40edfc26292 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 @@ -20,6 +20,7 @@ import type { } from '@kbn/core-chrome-browser'; import type { InternalHttpStart } from '@kbn/core-http-browser-internal'; import { + Subject, BehaviorSubject, combineLatest, map, @@ -32,6 +33,7 @@ import { of, type Observable, type Subscription, + timer, } from 'rxjs'; import { type Location, createLocation } from 'history'; import deepEqual from 'react-fast-compare'; @@ -326,20 +328,50 @@ export class ProjectNavigationService { } const { sideNavComponent, homePage = '' } = definition; - const homePageLink = this.navLinksService?.get(homePage); if (sideNavComponent) { this.setSideNavComponent(sideNavComponent); } - if (homePageLink) { - this.setProjectHome(homePageLink.href); - } + this.waitForLink(homePage, (navLink: ChromeNavLink) => { + this.setProjectHome(navLink.href); + }); this.initNavigation(nextId, definition.navigationTree$); }); } + /** + * This method waits for the chrome nav link to be available and then calls the callback. + * This is necessary to avoid race conditions when we register the solution navigation + * before the deep links are available (plugins can register them later). + * + * @param linkId The chrome nav link id + * @param cb The callback to call when the link is found + * @returns + */ + private waitForLink(linkId: string, cb: (chromeNavLink: ChromeNavLink) => undefined): void { + if (!this.navLinksService) return; + + let navLink: ChromeNavLink | undefined = this.navLinksService.get(linkId); + if (navLink) { + cb(navLink); + return; + } + + const stop$ = new Subject(); + const tenSeconds = timer(10000); + + this.deepLinksMap$.pipe(takeUntil(tenSeconds), takeUntil(stop$)).subscribe((navLinks) => { + navLink = navLinks[linkId]; + + if (navLink) { + cb(navLink); + stop$.next(); + } + }); + } + private setProjectHome(homeHref: string) { this.projectHome$.next(homeHref); } diff --git a/packages/deeplinks/observability/locators/dataset_quality.ts b/packages/deeplinks/observability/locators/dataset_quality.ts index e30648e3f129c..9e04e10e9933e 100644 --- a/packages/deeplinks/observability/locators/dataset_quality.ts +++ b/packages/deeplinks/observability/locators/dataset_quality.ts @@ -23,14 +23,6 @@ type TimeRangeConfig = { refresh: RefreshInterval; }; -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -type DatasetConfig = { - rawName: string; - type: string; - name: string; - namespace: string; -}; - // eslint-disable-next-line @typescript-eslint/consistent-type-definitions type Filters = { timeRange: TimeRangeConfig; @@ -38,7 +30,4 @@ type Filters = { export interface DataQualityLocatorParams extends SerializableRecord { filters?: Filters; - flyout?: { - dataset: DatasetConfig; - }; } diff --git a/packages/deeplinks/observability/locators/dataset_quality_details.ts b/packages/deeplinks/observability/locators/dataset_quality_details.ts new file mode 100644 index 0000000000000..6f51bbbfe7ce3 --- /dev/null +++ b/packages/deeplinks/observability/locators/dataset_quality_details.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { SerializableRecord } from '@kbn/utility-types'; + +export const DATA_QUALITY_DETAILS_LOCATOR_ID = 'DATA_QUALITY_DETAILS_LOCATOR'; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type RefreshInterval = { + pause: boolean; + value: number; +}; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type TimeRangeConfig = { + from: string; + to: string; + refresh: RefreshInterval; +}; + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +type DegradedFieldsTable = { + page?: number; + rowsPerPage?: number; + sort?: { + field: string; + direction: 'asc' | 'desc'; + }; +}; + +export interface DataQualityDetailsLocatorParams extends SerializableRecord { + dataStream: string; + timeRange?: TimeRangeConfig; + breakdownField?: string; + degradedFields?: { + table?: DegradedFieldsTable; + }; +} diff --git a/packages/deeplinks/observability/locators/index.ts b/packages/deeplinks/observability/locators/index.ts index 67e79ecb577ea..48902c8f37cf4 100644 --- a/packages/deeplinks/observability/locators/index.ts +++ b/packages/deeplinks/observability/locators/index.ts @@ -7,6 +7,7 @@ */ export * from './dataset_quality'; +export * from './dataset_quality_details'; export * from './logs_explorer'; export * from './observability_logs_explorer'; export * from './observability_onboarding'; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts index a5ca11ad20203..c9956dc8a666e 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/host.ts @@ -8,6 +8,7 @@ /* eslint-disable max-classes-per-file */ import { Entity, Fields } from '../entity'; import { Serializable } from '../serializable'; +import { k8sNode } from './k8s_node'; import { pod } from './pod'; interface HostDocument extends Fields { @@ -20,17 +21,20 @@ interface HostDocument extends Fields { 'host.ip'?: string; 'host.os.name'?: string; 'host.os.version'?: string; + 'host.os.platform'?: string; 'cloud.provider'?: string; } class Host extends Entity { - cpu() { + cpu({ cpuTotalValue }: { cpuTotalValue?: number } = {}) { return new HostMetrics({ ...this.fields, - 'system.cpu.total.norm.pct': 0.094, + 'system.cpu.total.norm.pct': cpuTotalValue ?? 0.98, 'system.cpu.user.pct': 0.805, 'system.cpu.system.pct': 0.704, 'system.cpu.cores': 16, + 'process.cpu.pct': 0.1, + 'system.cpu.nice.pct': 0.1, 'metricset.period': 10000, 'metricset.name': 'cpu', }); @@ -45,6 +49,7 @@ class Host extends Entity { 'system.memory.total': 68719476736, 'system.memory.used.bytes': 39964708864, 'system.memory.used.pct': 0.582, + 'process.memory.pct': 0.1, 'metricset.period': 10000, 'metricset.name': 'memory', }); @@ -72,6 +77,22 @@ class Host extends Entity { }); } + core() { + return new HostMetrics({ + ...this.fields, + 'system.core.total.pct': 0.98, + 'system.core.user.pct': 0.805, + 'system.core.nice.pct': 0.704, + 'system.core.idle.pct': 0.1, + 'system.core.iowait.pct': 0.1, + 'system.core.irq.pct': 0.1, + 'system.core.softirq.pct': 0.1, + 'system.core.steal.pct': 0.1, + 'metricset.period': 10000, + 'metricset.name': 'core', + }); + } + filesystem() { return new HostMetrics({ ...this.fields, @@ -96,6 +117,10 @@ class Host extends Entity { pod(uid: string) { return pod(uid, this.fields['host.hostname']); } + + node(podUid: string) { + return k8sNode(this.fields['host.hostname'], podUid); + } } export interface HostMetricsDocument extends HostDocument { @@ -120,6 +145,17 @@ export interface HostMetricsDocument extends HostDocument { 'system.load'?: { 1: number; cores: number }; 'host.network.ingress.bytes'?: number; 'host.network.egress.bytes'?: number; + 'process.cpu.pct'?: number; + 'process.memory.pct'?: number; + 'system.core.total.pct'?: number; + 'system.core.user.pct'?: number; + 'system.core.nice.pct'?: number; + 'system.core.idle.pct'?: number; + 'system.core.iowait.pct'?: number; + 'system.core.irq.pct'?: number; + 'system.core.softirq.pct'?: number; + 'system.core.steal.pct'?: number; + 'system.cpu.nice.pct'?: number; } class HostMetrics extends Serializable {} @@ -132,6 +168,7 @@ export function host(name: string): Host { 'host.name': name, 'host.ip': '10.128.0.2', 'host.os.name': 'Linux', + 'host.os.platform': 'ubuntu', 'host.os.version': '4.19.76-linuxkit', 'cloud.provider': 'gcp', }); diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts index c325635e27098..b8b0600fc1838 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/index.ts @@ -11,13 +11,15 @@ import { host, HostMetricsDocument } from './host'; import { k8sContainer, K8sContainerMetricsDocument } from './k8s_container'; import { pod, PodMetricsDocument } from './pod'; import { awsRds, AWSRdsMetricsDocument } from './aws/rds'; +import { k8sNode, K8sNodeMetricsDocument } from './k8s_node'; export type InfraDocument = | HostMetricsDocument | PodMetricsDocument | DockerContainerMetricsDocument | K8sContainerMetricsDocument - | AWSRdsMetricsDocument; + | AWSRdsMetricsDocument + | K8sNodeMetricsDocument; export const infra = { host, @@ -25,4 +27,5 @@ export const infra = { dockerContainer, k8sContainer, awsRds, + k8sNode, }; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_container.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_container.ts index 6aa813913c118..7135581f6129c 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_container.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_container.ts @@ -18,11 +18,13 @@ interface K8sContainerDocument extends Fields { 'container.name'?: string; 'container.image.name'?: string; 'container.runtime'?: string; - 'host.name'?: string; + 'host.name': string; + 'host.hostname': string; 'cloud.provider'?: string; 'cloud.instance.id'?: string; 'cloud.image.id'?: string; 'event.dataset'?: string; + 'agent.id': string; } export class K8sContainer extends Entity { @@ -31,6 +33,7 @@ export class K8sContainer extends Entity { ...this.fields, 'kubernetes.container.cpu.usage.limit.pct': 46, 'kubernetes.container.memory.usage.limit.pct': 30, + 'kubernetes.pod.cpu.usage.limit.pct': 46, }); } } @@ -38,6 +41,7 @@ export class K8sContainer extends Entity { export interface K8sContainerMetricsDocument extends K8sContainerDocument { 'kubernetes.container.cpu.usage.limit.pct': number; 'kubernetes.container.memory.usage.limit.pct': number; + 'kubernetes.pod.cpu.usage.limit.pct': number; } class K8sContainerMetrics extends Serializable {} @@ -51,6 +55,8 @@ export function k8sContainer(id: string, uid: string, nodeName: string): K8sCont 'container.runtime': 'containerd', 'container.image.name': 'image-1', 'host.name': 'host-1', + 'host.hostname': 'host-1', + 'agent.id': 'synthtrace', 'cloud.instance.id': 'instance-1', 'cloud.image.id': 'image-1', 'cloud.provider': 'aws', diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_node.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_node.ts new file mode 100644 index 0000000000000..8b596a6591669 --- /dev/null +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/k8s_node.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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. + */ +/* eslint-disable max-classes-per-file */ +import { Entity, Fields } from '../entity'; +import { Serializable } from '../serializable'; + +interface K8sNodeDocument extends Fields { + 'kubernetes.node.name': string; + 'kubernetes.pod.uid'?: string; + 'agent.id': string; + 'host.hostname': string; + 'host.name': string; + 'metricset.name'?: string; + 'event.dataset'?: string; +} + +export class K8sNode extends Entity { + metrics() { + return new K8sNodeMetrics({ + ...this.fields, + 'kubernetes.node.cpu.allocatable.cores': 0.53, + 'kubernetes.node.cpu.usage.nanocores': 0.32, + 'kubernetes.node.memory.allocatable.bytes': 0.46, + 'kubernetes.node.memory.usage.bytes': 0.86, + 'kubernetes.node.fs.capacity.bytes': 100, + 'kubernetes.node.fs.used.bytes': 100, + 'kubernetes.node.pod.allocatable.total': 10, + }); + } +} + +export interface K8sNodeMetricsDocument extends K8sNodeDocument { + 'kubernetes.node.cpu.allocatable.cores': number; + 'kubernetes.node.cpu.usage.nanocores': number; + 'kubernetes.node.memory.allocatable.bytes': number; + 'kubernetes.node.memory.usage.bytes': number; + 'kubernetes.node.fs.capacity.bytes': number; + 'kubernetes.node.fs.used.bytes': number; + 'kubernetes.node.pod.allocatable.total': number; +} + +class K8sNodeMetrics extends Serializable {} + +export function k8sNode(name: string, podUid: string) { + return new K8sNode({ + 'kubernetes.node.name': name, + 'kubernetes.pod.uid': podUid, + 'agent.id': 'synthtrace', + 'host.hostname': name, + 'host.name': name, + 'event.dataset': 'kubernetes.node', + }); +} diff --git a/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts b/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts index 35ebe94ba6ee1..b885fd1aeb606 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/infra/pod.ts @@ -12,6 +12,9 @@ import { Serializable } from '../serializable'; import { k8sContainer } from './k8s_container'; interface PodDocument extends Fields { + 'agent.id': string; + 'host.hostname': string; + 'host.name': string; 'kubernetes.pod.uid': string; 'kubernetes.node.name': string; 'metricset.name'?: string; @@ -40,5 +43,8 @@ export function pod(uid: string, nodeName: string) { return new Pod({ 'kubernetes.pod.uid': uid, 'kubernetes.node.name': nodeName, + 'agent.id': 'synthtrace', + 'host.hostname': nodeName, + 'host.name': nodeName, }); } diff --git a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts index 6c42d7051a9b0..dcd5e6da2d261 100644 --- a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts +++ b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_es_client.ts @@ -22,7 +22,14 @@ export class InfraSynthtraceEsClient extends SynthtraceEsClient { ...options, pipeline: infraPipeline(), }); - this.dataStreams = ['metrics-*', 'logs-*']; + this.dataStreams = [ + 'metrics-system*', + 'metrics-kubernetes*', + 'metrics-docker*', + 'metrics-aws*', + 'metricbeat-*', + 'logs-*', + ]; } } @@ -60,7 +67,10 @@ function getRoutingTransform() { document._index = 'metrics-system.filesystem-default'; } else if (metricset === 'diskio') { document._index = 'metrics-system.diskio-default'; + } else if (metricset === 'core') { + document._index = 'metrics-system.core-default'; } else if ('container.id' in document) { + document._index = 'metrics-docker.container-default'; document._index = 'metrics-kubernetes.container-default'; } else if ('kubernetes.pod.uid' in document) { document._index = 'metrics-kubernetes.pod-default'; diff --git a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts index b39efada2abff..5c6e02aaedc3a 100644 --- a/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts +++ b/packages/kbn-apm-synthtrace/src/lib/infra/infra_synthtrace_kibana_client.ts @@ -70,4 +70,27 @@ export class InfraSynthtraceKibanaClient { this.logger.info(`Installed System package ${packageVersion}`); } + + async uninstallSystemPackage(packageVersion: string) { + this.logger.debug(`Uninstalling System package ${packageVersion}`); + + const url = join(this.target, `/api/fleet/epm/packages/system/${packageVersion}`); + const response = await pRetry(() => { + return fetch(url, { + method: 'DELETE', + headers: kibanaHeaders(), + body: '{"force":true}', + }); + }); + + const responseJson = await response.json(); + + if (!responseJson.items) { + throw new Error( + `Failed to uninstall System package version ${packageVersion}, received HTTP ${response.status} and message: ${responseJson.message} for url ${url}` + ); + } + + this.logger.info(`System package ${packageVersion} uninstalled`); + } } diff --git a/packages/kbn-cbor/README.md b/packages/kbn-cbor/README.md new file mode 100644 index 0000000000000..3f28f45253e80 --- /dev/null +++ b/packages/kbn-cbor/README.md @@ -0,0 +1,3 @@ +# @kbn/cbor + +Simple wrapper around borc to expose CBOR encode and decode methods with reasonable performance and no native modules \ No newline at end of file diff --git a/packages/kbn-cbor/index.test.ts b/packages/kbn-cbor/index.test.ts new file mode 100644 index 0000000000000..706fd691e4731 --- /dev/null +++ b/packages/kbn-cbor/index.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { encode, decode } from '.'; + +describe('KbnCbor', () => { + it('should correctly encode and decode data', () => { + const data = { hello: 'world', count: 123, isValid: true }; + + // encoding + const encoded = encode(data); + expect(encoded).toBeInstanceOf(Buffer); + expect(encoded.length).toBeGreaterThan(0); + + // decoding + const decoded = decode(encoded); + expect(decoded).toEqual(data); + }); + + it('should encode data to Buffer', () => { + const data = { foo: 'bar' }; + + const encoded = encode(data); + expect(Buffer.isBuffer(encoded)).toBe(true); + }); + + it('should decode Buffer to original data', () => { + const data = { foo: 'bar', num: 42, arr: [1, 2, 3] }; + + const encoded = encode(data); + const decoded = decode(encoded); + + expect(decoded).toEqual(data); + }); +}); diff --git a/packages/kbn-cbor/index.ts b/packages/kbn-cbor/index.ts new file mode 100644 index 0000000000000..6b55b931e7852 --- /dev/null +++ b/packages/kbn-cbor/index.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. + */ + +// NOTE: This can possibly be replaced with node-cbor using encode, and decodeFirstSync if we do need +// to change into something better maintained but for now we are going to stick with borc as it is +// a little faster +import { encode as encodeJS, decode as decodeJS } from 'borc'; + +export class KbnCbor { + static encode(data: unknown) { + return encodeJS(data); + } + + static decode(uint8: any) { + return decodeJS(uint8); + } +} + +export const encode = KbnCbor.encode; +export const decode = KbnCbor.decode; diff --git a/packages/kbn-cbor/jest.config.js b/packages/kbn-cbor/jest.config.js new file mode 100644 index 0000000000000..e804d351d8d9d --- /dev/null +++ b/packages/kbn-cbor/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-cbor'], +}; diff --git a/packages/kbn-cbor/kibana.jsonc b/packages/kbn-cbor/kibana.jsonc new file mode 100644 index 0000000000000..91ecbb2d27def --- /dev/null +++ b/packages/kbn-cbor/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/cbor", + "owner": "@elastic/kibana-operations" +} diff --git a/packages/kbn-cbor/package.json b/packages/kbn-cbor/package.json new file mode 100644 index 0000000000000..20d13f0f907fa --- /dev/null +++ b/packages/kbn-cbor/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/cbor", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./index.ts" +} diff --git a/packages/kbn-cbor/tsconfig.json b/packages/kbn-cbor/tsconfig.json new file mode 100644 index 0000000000000..f4b12f8b2de2b --- /dev/null +++ b/packages/kbn-cbor/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + "../../typings/borc.d.ts" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/packages/kbn-check-prod-native-modules-cli/README.md b/packages/kbn-check-prod-native-modules-cli/README.md new file mode 100644 index 0000000000000..4a5749a699ffa --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/README.md @@ -0,0 +1,3 @@ +# @kbn/check-prod-native-modules-cli + +Simple and straightforward CLI for searching for native modules installed as prod dependencies or as a result of any prod dependency. \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/check_prod_native_modules.test.ts b/packages/kbn-check-prod-native-modules-cli/check_prod_native_modules.test.ts new file mode 100644 index 0000000000000..ff795bf5a0b2d --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/check_prod_native_modules.test.ts @@ -0,0 +1,243 @@ +/* + * Copyright 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 { promises as fs, existsSync } from 'fs'; +import { ToolingLog } from '@kbn/tooling-log'; +import { findProductionDependencies, readYarnLock } from '@kbn/yarn-lock-validator'; +import { + checkProdNativeModules, + checkDependencies, + isNativeModule, +} from './check_prod_native_modules'; + +jest.mock('fs', () => ({ + promises: { + readdir: jest.fn(), + }, + existsSync: jest.fn(), +})); + +jest.mock('@kbn/repo-info', () => ({ + REPO_ROOT: '/mocked/repo/root', +})); + +jest.mock('@kbn/tooling-log', () => ({ + ToolingLog: jest.fn().mockImplementation(() => ({ + info: jest.fn(), + error: jest.fn(), + success: jest.fn(), + })), +})); + +jest.mock('@kbn/yarn-lock-validator', () => ({ + findProductionDependencies: jest.fn(), + readYarnLock: jest.fn(), +})); + +jest.mock( + // eslint-disable-next-line @kbn/imports/no_unresolvable_imports + '/test/node_modules/test-package/package.json', + () => ({ + name: 'test-package', + version: '1.0.0', + }), + { virtual: true } +); + +jest.mock( + // eslint-disable-next-line @kbn/imports/no_unresolvable_imports + '/test/node_modules/@scope/package/package.json', + () => ({ + name: '@scope/package', + version: '1.0.0', + }), + { virtual: true } +); + +describe('Check Prod Native Modules', () => { + let mockLog: jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + mockLog = new ToolingLog() as jest.Mocked; + }); + + describe('isNativeModule', () => { + it('should return true if binding.gyp is found', async () => { + (fs.readdir as jest.Mock).mockResolvedValueOnce([ + { name: 'binding.gyp', isDirectory: () => false }, + ]); + + const result = await isNativeModule('/test/path', mockLog); + expect(result).toBe(true); + }); + + it('should return true if .node file is found', async () => { + (fs.readdir as jest.Mock).mockResolvedValueOnce([ + { name: 'test.node', isDirectory: () => false }, + ]); + + const result = await isNativeModule('/test/path', mockLog); + expect(result).toBe(true); + }); + + it('should return false if no native module indicators are found', async () => { + (fs.readdir as jest.Mock).mockResolvedValueOnce([ + { name: 'regular.js', isDirectory: () => false }, + ]); + + const result = await isNativeModule('/test/path', mockLog); + expect(result).toBe(false); + }); + + it('should log an error if there is an issue reading the directory', async () => { + (fs.readdir as jest.Mock).mockRejectedValueOnce(new Error('Read error')); + + await isNativeModule('/test/path', mockLog); + expect(mockLog.error).toHaveBeenCalledWith('Error when reading /test/path: Read error'); + }); + }); + + describe('checkDependencies', () => { + it('should identify native modules in production dependencies', async () => { + const mockProductionDependencies = new Map([['test-package@1.0.0', true]]); + const mockProdNativeModulesFound: Array<{ name: string; version: string; path: string }> = []; + + (fs.readdir as jest.Mock).mockResolvedValueOnce([ + { name: 'test-package', isDirectory: () => true }, + ]); + (fs.readdir as jest.Mock) + .mockResolvedValueOnce([{ name: 'binding.gyp', isDirectory: () => false }]) + .mockResolvedValueOnce([]); + (existsSync as jest.Mock).mockReturnValue(true); + jest + // eslint-disable-next-line @typescript-eslint/no-var-requires + .spyOn(require('./check_prod_native_modules'), 'isNativeModule') + .mockResolvedValueOnce(true); + + await checkDependencies( + '/test/node_modules', + mockProductionDependencies, + mockProdNativeModulesFound, + mockLog + ); + + expect(mockProdNativeModulesFound).toEqual([ + { name: 'test-package', version: '1.0.0', path: '/test/node_modules/test-package' }, + ]); + }); + + it('should handle scoped packages', async () => { + const mockProductionDependencies = new Map([['@scope/package@1.0.0', true]]); + const mockProdNativeModulesFound: Array<{ name: string; version: string; path: string }> = []; + + (fs.readdir as jest.Mock) + .mockResolvedValueOnce([{ name: '@scope', isDirectory: () => true }]) + .mockResolvedValueOnce([{ name: 'package', isDirectory: () => true }]); + (fs.readdir as jest.Mock) + .mockResolvedValueOnce([{ name: 'binding.gyp', isDirectory: () => false }]) + .mockResolvedValueOnce([]); + (existsSync as jest.Mock).mockReturnValue(true); + (existsSync as jest.Mock).mockReturnValue(true); + jest + // eslint-disable-next-line @typescript-eslint/no-var-requires + .spyOn(require('./check_prod_native_modules'), 'isNativeModule') + .mockResolvedValueOnce(true); + + await checkDependencies( + '/test/node_modules', + mockProductionDependencies, + mockProdNativeModulesFound, + mockLog + ); + + expect(mockProdNativeModulesFound).toEqual([ + { name: '@scope/package', version: '1.0.0', path: '/test/node_modules/@scope/package' }, + ]); + }); + }); + + describe('checkProdNativeModules', () => { + it('should return false when no native modules are found', async () => { + (existsSync as jest.Mock).mockReturnValue(true); + (findProductionDependencies as jest.Mock).mockReturnValue(new Map()); + (readYarnLock as jest.Mock).mockResolvedValueOnce({}); + (fs.readdir as jest.Mock).mockResolvedValue([]); + jest + // eslint-disable-next-line @typescript-eslint/no-var-requires + .spyOn(require('./check_prod_native_modules'), 'checkDependencies') + .mockResolvedValue(undefined); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(false); + expect(mockLog.success).toHaveBeenCalledWith( + 'No production native modules installed were found' + ); + }); + + it('should return true and log errors when native modules are found', async () => { + (existsSync as jest.Mock).mockReturnValueOnce(true).mockReturnValueOnce(true); + (findProductionDependencies as jest.Mock).mockReturnValue( + new Map([['native-module@1.0.0', { name: 'native-module', version: '1.0.0' }]]) + ); + (readYarnLock as jest.Mock).mockResolvedValueOnce({}); + + // Mock loadPackageJson to return a mock package JSON object + jest + // eslint-disable-next-line @typescript-eslint/no-var-requires + .spyOn(require('./helpers'), 'loadPackageJson') + .mockImplementation((packageJsonPath: any) => { + return { + name: 'native-module', + version: '1.0.0', + }; + }); + + (fs.readdir as jest.Mock) + .mockResolvedValueOnce([{ name: 'native-module', isDirectory: () => true }]) + // .mockResolvedValueOnce([{ name: 'package.json', isDirectory: () => false }]) + .mockResolvedValueOnce([{ name: 'binding.gyp', isDirectory: () => false }]); + jest + // eslint-disable-next-line @typescript-eslint/no-var-requires + .spyOn(require('./check_prod_native_modules'), 'checkDependencies') + .mockImplementationOnce((_, __, prodNativeModulesFound: any) => { + prodNativeModulesFound.push({ + name: 'native-module', + version: '1.0.0', + path: '/path/to/native-module', + }); + }); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(true); + expect(mockLog.error).toHaveBeenNthCalledWith( + 1, + 'Production native module detected: node_modules/native-module' + ); + expect(mockLog.error).toHaveBeenNthCalledWith( + 2, + 'Production native modules were detected and logged above' + ); + }); + + it('should throw an error if root node_modules folder is not found', async () => { + (existsSync as jest.Mock).mockReturnValue(false); + (findProductionDependencies as jest.Mock).mockReturnValue(new Map()); + (readYarnLock as jest.Mock).mockResolvedValueOnce({}); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(true); + expect(mockLog.error).toHaveBeenCalledWith( + 'No root node_modules folder was found in the project. Impossible to continue' + ); + }); + }); +}); diff --git a/packages/kbn-check-prod-native-modules-cli/check_prod_native_modules.ts b/packages/kbn-check-prod-native-modules-cli/check_prod_native_modules.ts new file mode 100644 index 0000000000000..df188401abdd6 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/check_prod_native_modules.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 * as path from 'path'; +import { promises as fs, existsSync } from 'fs'; +import { REPO_ROOT } from '@kbn/repo-info'; +import type { ToolingLog } from '@kbn/tooling-log'; +import { findProductionDependencies, readYarnLock } from '@kbn/yarn-lock-validator'; +import { loadPackageJson } from './helpers'; + +// Checks if a given path contains a native module or not recursively +async function isNativeModule(modulePath: string, log: ToolingLog): Promise { + const stack: string[] = [modulePath]; + + while (stack.length > 0) { + const currentPath = stack.pop() as string; + + // Skip processing if the current directory is a node_modules folder + if (path.basename(currentPath) === 'node_modules') { + continue; + } + + try { + const entries = await fs.readdir(currentPath, { withFileTypes: true }); + + for (const entry of entries) { + const entryPath = path.join(currentPath, entry.name); + + if (entry.isDirectory()) { + stack.push(entryPath); + } else if (entry.name === 'binding.gyp' || entry.name.endsWith('.node')) { + return true; + } + } + } catch (err) { + log.error(`Error when reading ${currentPath}: ${err.message}`); + } + } + return false; +} + +// Searches through node_modules and for each module which is a prod dep (or a direct result of one) checks recursively for native modules +async function checkDependencies( + rootNodeModulesDir: string, + productionDependencies: Map, + prodNativeModulesFound: Array<{ name: string; version: string; path: string }>, + log: ToolingLog +) { + const stack: string[] = [rootNodeModulesDir]; + + while (stack.length > 0) { + const currentDir = stack.pop() as string; + + try { + const entries = await fs.readdir(currentDir, { withFileTypes: true }); + + for (const entry of entries) { + if (!entry.isDirectory()) continue; + + const entryPath = path.join(currentDir, entry.name); + if (entry.name.startsWith('@')) { + // Handle scoped packages (e.g., @scope/package) + stack.push(entryPath); + continue; + } + + const packageJsonPath = path.join(entryPath, 'package.json'); + if (existsSync(packageJsonPath)) { + const packageJson = loadPackageJson(packageJsonPath); + const dependencyKey = `${packageJson.name}@${packageJson.version}`; + + if (productionDependencies.has(dependencyKey)) { + const isNative = await isNativeModule(entryPath, log); + if (isNative) { + prodNativeModulesFound.push({ + name: packageJson.name, + version: packageJson.version, + path: entryPath, + }); + } + } + } + + // Adds nested node_modules to the stack to check for further dependencies + const nestedNodeModulesPath = path.join(entryPath, 'node_modules'); + if (existsSync(nestedNodeModulesPath)) { + stack.push(nestedNodeModulesPath); + } + } + } catch (err) { + throw new Error(`Error processing directory ${currentDir}: ${err.message}`); + } + } +} + +// Checks if there are native modules in the production dependencies +async function checkProdNativeModules(log: ToolingLog) { + log.info('Checking for native modules on production dependencies...'); + const rootNodeModulesDir = path.join(REPO_ROOT, 'node_modules'); + const prodNativeModulesFound: Array<{ name: string; version: string; path: string }> = []; + + try { + // Gets all production dependencies based on package.json and then searches across transient dependencies using lock file + const rawProductionDependencies = findProductionDependencies(log, await readYarnLock()); + + // Converts rawProductionDependencies into a simple Map of production dependencies + const productionDependencies: Map = new Map(); + rawProductionDependencies.forEach((depInfo, depKey) => { + productionDependencies.set(`${depInfo.name}@${depInfo.version}`, true); + }); + + // Fail if no root node_modules folder + if (!existsSync(rootNodeModulesDir)) { + throw new Error( + 'No root node_modules folder was found in the project. Impossible to continue' + ); + } + + // Goes into the node_modules folder and for each node_module which is a production dependency (or a result of one) checks recursively if there are native modules + await checkDependencies( + rootNodeModulesDir, + productionDependencies, + prodNativeModulesFound, + log + ); + + // In that case no prod native modules were found + if (!prodNativeModulesFound.length) { + log.success('No production native modules installed were found'); + return false; + } + + // Logs every detected native module at once + prodNativeModulesFound.forEach((dep) => { + log.error(`Production native module detected: ${path.relative(REPO_ROOT, dep.path)}`); + }); + + throw new Error('Production native modules were detected and logged above'); + } catch (err) { + log.error(err.message); + return true; + } +} + +export { checkProdNativeModules, checkDependencies, isNativeModule }; diff --git a/packages/kbn-check-prod-native-modules-cli/helpers.ts b/packages/kbn-check-prod-native-modules-cli/helpers.ts new file mode 100644 index 0000000000000..6efccaac6ad68 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/helpers.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// helper function to load package.json +function loadPackageJson(packageJsonPath: string) { + return require(packageJsonPath); +} + +export { loadPackageJson }; diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/node_modules/package-a/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/node_modules/package-a/package.json new file mode 100644 index 0000000000000..785a76c07d76f --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/node_modules/package-a/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-a", + "version": "1.0.0" +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/node_modules/package-b/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/node_modules/package-b/package.json new file mode 100644 index 0000000000000..62a888ea46a01 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/node_modules/package-b/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-b", + "version": "2.0.0" +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/package.json new file mode 100644 index 0000000000000..17cf802f22889 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/package.json @@ -0,0 +1,8 @@ +{ + "name": "no-native-modules-project", + "version": "1.0.0", + "dependencies": { + "package-a": "^1.0.0", + "package-b": "^2.0.0" + } +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/yarn.lock b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/yarn.lock new file mode 100644 index 0000000000000..e44b1d1767019 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_native_modules/yarn.lock @@ -0,0 +1,11 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +package-a@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-a/-/package-a-1.0.0.tgz" + integrity sha1-example123 + +package-b@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/package-b/-/package-b-2.0.0.tgz" + integrity sha1-example456 diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_node_modules/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_node_modules/package.json new file mode 100644 index 0000000000000..b8478fdabc03c --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_node_modules/package.json @@ -0,0 +1,8 @@ +{ + "name": "no-node-modules-project", + "version": "1.0.0", + "dependencies": { + "package-a": "^1.0.0", + "package-b": "^2.0.0" + } +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_node_modules/yarn.lock b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_node_modules/yarn.lock new file mode 100644 index 0000000000000..e44b1d1767019 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/no_node_modules/yarn.lock @@ -0,0 +1,11 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +package-a@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-a/-/package-a-1.0.0.tgz" + integrity sha1-example123 + +package-b@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/package-b/-/package-b-2.0.0.tgz" + integrity sha1-example456 diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/native-module/binding.gyp b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/native-module/binding.gyp new file mode 100644 index 0000000000000..4d850b6b74fdf --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/native-module/binding.gyp @@ -0,0 +1,8 @@ +{ + "targets": [ + { + "target_name": "native_module", + "sources": [ "" ] + } + ] +} diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/native-module/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/native-module/package.json new file mode 100644 index 0000000000000..2d11f7b6c542e --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/native-module/package.json @@ -0,0 +1,5 @@ +{ + "name": "native-module", + "version": "1.0.0", + "gypfile": true +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/package-b/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/package-b/package.json new file mode 100644 index 0000000000000..62a888ea46a01 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/node_modules/package-b/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-b", + "version": "2.0.0" +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/package.json new file mode 100644 index 0000000000000..bf04488f0b8f6 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/package.json @@ -0,0 +1,10 @@ +{ + "name": "with-native-modules-project", + "version": "1.0.0", + "devDependencies": { + "native-module": "^1.0.0" + }, + "dependencies": { + "package-b": "^2.0.0" + } +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/yarn.lock b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/yarn.lock new file mode 100644 index 0000000000000..2dcb949a3fe54 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_dev_native_modules/yarn.lock @@ -0,0 +1,11 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +native-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/native-module/-/native-module-1.0.0.tgz" + integrity sha1-example789 + +package-b@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/package-b/-/package-b-2.0.0.tgz" + integrity sha1-example456 diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module/binding.gyp b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module/binding.gyp new file mode 100644 index 0000000000000..4d850b6b74fdf --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module/binding.gyp @@ -0,0 +1,8 @@ +{ + "targets": [ + { + "target_name": "native_module", + "sources": [ "" ] + } + ] +} diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module/package.json new file mode 100644 index 0000000000000..2d11f7b6c542e --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module/package.json @@ -0,0 +1,5 @@ +{ + "name": "native-module", + "version": "1.0.0", + "gypfile": true +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module2/a.node b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module2/a.node new file mode 100644 index 0000000000000..573541ac9702d --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module2/a.node @@ -0,0 +1 @@ +0 diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module2/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module2/package.json new file mode 100644 index 0000000000000..49afa2f226630 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/native-module2/package.json @@ -0,0 +1,4 @@ +{ + "name": "native-module2", + "version": "1.0.0" +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/package-b/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/package-b/package.json new file mode 100644 index 0000000000000..62a888ea46a01 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/node_modules/package-b/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-b", + "version": "2.0.0" +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/package.json new file mode 100644 index 0000000000000..1f3541823693f --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/package.json @@ -0,0 +1,9 @@ +{ + "name": "with-native-modules-project", + "version": "1.0.0", + "dependencies": { + "native-module": "^1.0.0", + "native-module2": "^1.0.0", + "package-b": "^2.0.0" + } +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/yarn.lock b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/yarn.lock new file mode 100644 index 0000000000000..96e286d5b03cf --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_native_modules/yarn.lock @@ -0,0 +1,16 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +native-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/native-module/-/native-module-1.0.0.tgz" + integrity sha1-example789 + +native-module2@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/native-module/-/native-module2-1.0.0.tgz" + integrity sha1-example789 + +package-b@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/package-b/-/package-b-2.0.0.tgz" + integrity sha1-example456 diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/native-module/binding.gyp b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/native-module/binding.gyp new file mode 100644 index 0000000000000..4d850b6b74fdf --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/native-module/binding.gyp @@ -0,0 +1,8 @@ +{ + "targets": [ + { + "target_name": "native_module", + "sources": [ "" ] + } + ] +} diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/native-module/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/native-module/package.json new file mode 100644 index 0000000000000..2d11f7b6c542e --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/native-module/package.json @@ -0,0 +1,5 @@ +{ + "name": "native-module", + "version": "1.0.0", + "gypfile": true +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/package-a/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/package-a/package.json new file mode 100644 index 0000000000000..127ebe036ed37 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/package-a/package.json @@ -0,0 +1,7 @@ +{ + "name": "packaga-a", + "version": "1.0.0", + "dependencies": { + "native-module": "^1.0.0" + } +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/package-b/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/package-b/package.json new file mode 100644 index 0000000000000..62a888ea46a01 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/node_modules/package-b/package.json @@ -0,0 +1,4 @@ +{ + "name": "package-b", + "version": "2.0.0" +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/package.json b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/package.json new file mode 100644 index 0000000000000..22f67d7fdce96 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/package.json @@ -0,0 +1,8 @@ +{ + "name": "with-native-modules-project", + "version": "1.0.0", + "dependencies": { + "package-a": "^1.0.0", + "package-b": "^2.0.0" + } +} \ No newline at end of file diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/yarn.lock b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/yarn.lock new file mode 100644 index 0000000000000..61adb1a8b22b3 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/with_transient_native_modules/yarn.lock @@ -0,0 +1,18 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + +native-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/native-module/-/native-module-1.0.0.tgz" + integrity sha1-example789 + +package-a@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-a/-/package-a-1.0.0.tgz" + integrity sha1-example789 + dependencies: + native-module "^1.0.0" + +package-b@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/package-b/-/package-b-2.0.0.tgz" + integrity sha1-example456 diff --git a/packages/kbn-check-prod-native-modules-cli/integration_tests/run_check_prod_native_modules.cli.test.ts b/packages/kbn-check-prod-native-modules-cli/integration_tests/run_check_prod_native_modules.cli.test.ts new file mode 100644 index 0000000000000..1df0501a544fe --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/integration_tests/run_check_prod_native_modules.cli.test.ts @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 path from 'path'; +import fs from 'fs'; +import { ToolingLog } from '@kbn/tooling-log'; +import { checkProdNativeModules } from '../check_prod_native_modules'; + +describe('checkProdNativeModules', () => { + let mockLog: jest.Mocked; + const fixturesDir = path.join(__dirname, '__fixtures__'); + + beforeEach(() => { + mockLog = { + info: jest.fn(), + success: jest.fn(), + error: jest.fn(), + } as unknown as jest.Mocked; + + jest.clearAllMocks(); + }); + + it('should return false when no native modules are found', async () => { + // Use a fixture without native modules + const noNativeModulesDir = path.join(fixturesDir, 'no_native_modules'); + const noNativeModulesPkgJsonPath = path.join(noNativeModulesDir, 'package.json'); + jest.spyOn(process, 'cwd').mockReturnValue(noNativeModulesDir); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'REPO_ROOT', noNativeModulesDir); + + const noNativeModulesPkgJson = JSON.parse(fs.readFileSync(noNativeModulesPkgJsonPath, 'utf8')); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'kibanaPackageJson', noNativeModulesPkgJson); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(false); + expect(mockLog.success).toHaveBeenCalledWith( + 'No production native modules installed were found' + ); + }); + + it('should return true and log errors when native modules are found', async () => { + // Use a fixture with native modules + const withNativeModulesDir = path.join(fixturesDir, 'with_native_modules'); + const withNativeModulesPkgJsonPath = path.join(withNativeModulesDir, 'package.json'); + jest.spyOn(process, 'cwd').mockReturnValue(withNativeModulesDir); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'REPO_ROOT', withNativeModulesDir); + + const withNativeModulesPkgJson = JSON.parse( + fs.readFileSync(withNativeModulesPkgJsonPath, 'utf8') + ); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'kibanaPackageJson', withNativeModulesPkgJson); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(true); + expect(mockLog.error).toHaveBeenCalledWith( + expect.stringContaining('Production native module detected:') + ); + expect(mockLog.error).toHaveBeenCalledWith( + 'Production native modules were detected and logged above' + ); + }); + + it('should throw an error when root node_modules folder is not found', async () => { + // Use a fixture without node_modules + const noNodeModulesDir = path.join(fixturesDir, 'no_node_modules'); + const noNodeModulesPkgJsonPath = path.join(noNodeModulesDir, 'package.json'); + jest.spyOn(process, 'cwd').mockReturnValue(noNodeModulesDir); + + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'REPO_ROOT', noNodeModulesDir); + + const noNodeModulesPkgJson = JSON.parse(fs.readFileSync(noNodeModulesPkgJsonPath, 'utf8')); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'kibanaPackageJson', noNodeModulesPkgJson); + + expect(await checkProdNativeModules(mockLog)).toBe(true); + expect(mockLog.error).toHaveBeenCalledWith( + 'No root node_modules folder was found in the project. Impossible to continue' + ); + }); + + it('should return false when no prod native modules are found', async () => { + // Use a fixture without native modules + const withDevNativeModulesDir = path.join(fixturesDir, 'with_dev_native_modules'); + const withDevNativeModulesPkgJsonPath = path.join(withDevNativeModulesDir, 'package.json'); + jest.spyOn(process, 'cwd').mockReturnValue(withDevNativeModulesDir); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'REPO_ROOT', withDevNativeModulesDir); + + const withDevNativeModulesPkgJson = JSON.parse( + fs.readFileSync(withDevNativeModulesPkgJsonPath, 'utf8') + ); + + jest.replaceProperty( + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@kbn/repo-info'), + 'kibanaPackageJson', + withDevNativeModulesPkgJson + ); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(false); + expect(mockLog.success).toHaveBeenCalledWith( + 'No production native modules installed were found' + ); + }); + + it('should return true and log errors when prod transient native modules are found', async () => { + // Use a fixture with native modules + const withTransientNativeModulesDir = path.join(fixturesDir, 'with_transient_native_modules'); + const withTransientNativeModulesPkgJsonPath = path.join( + withTransientNativeModulesDir, + 'package.json' + ); + jest.spyOn(process, 'cwd').mockReturnValue(withTransientNativeModulesDir); + // eslint-disable-next-line @typescript-eslint/no-var-requires + jest.replaceProperty(require('@kbn/repo-info'), 'REPO_ROOT', withTransientNativeModulesDir); + + const withTransientNativeModulesPkgJson = JSON.parse( + fs.readFileSync(withTransientNativeModulesPkgJsonPath, 'utf8') + ); + + jest.replaceProperty( + // eslint-disable-next-line @typescript-eslint/no-var-requires + require('@kbn/repo-info'), + 'kibanaPackageJson', + withTransientNativeModulesPkgJson + ); + + const result = await checkProdNativeModules(mockLog); + + expect(result).toBe(true); + expect(mockLog.error).toHaveBeenCalledWith( + expect.stringContaining('Production native module detected:') + ); + expect(mockLog.error).toHaveBeenCalledWith( + 'Production native modules were detected and logged above' + ); + }); +}); diff --git a/packages/kbn-check-prod-native-modules-cli/jest.config.js b/packages/kbn-check-prod-native-modules-cli/jest.config.js new file mode 100644 index 0000000000000..3a0fc2e1c98d5 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-check-prod-native-modules-cli'], +}; diff --git a/packages/kbn-check-prod-native-modules-cli/jest.integration.config.js b/packages/kbn-check-prod-native-modules-cli/jest.integration.config.js new file mode 100644 index 0000000000000..17aa3994d5763 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/jest.integration.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_integration_node', + rootDir: '../..', + roots: ['/packages/kbn-check-prod-native-modules-cli'], +}; diff --git a/packages/kbn-check-prod-native-modules-cli/kibana.jsonc b/packages/kbn-check-prod-native-modules-cli/kibana.jsonc new file mode 100644 index 0000000000000..6daa5ddb876ff --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "type": "shared-server", + "id": "@kbn/check-prod-native-modules-cli", + "owner": "@elastic/kibana-operations", + "devOnly": true +} diff --git a/packages/kbn-check-prod-native-modules-cli/package.json b/packages/kbn-check-prod-native-modules-cli/package.json new file mode 100644 index 0000000000000..68af62072eba6 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/check-prod-native-modules-cli", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./run_check_prod_native_modules_cli" +} diff --git a/packages/kbn-check-prod-native-modules-cli/run_check_prod_native_modules_cli.ts b/packages/kbn-check-prod-native-modules-cli/run_check_prod_native_modules_cli.ts new file mode 100644 index 0000000000000..7850dc09f06c8 --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/run_check_prod_native_modules_cli.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { run } from '@kbn/dev-cli-runner'; +import { createFailError } from '@kbn/dev-cli-errors'; +import { checkProdNativeModules } from './check_prod_native_modules'; + +run( + async ({ log }) => { + const foundProdNativeModules = await checkProdNativeModules(log); + if (foundProdNativeModules) { + throw createFailError( + 'Failed: check all previous errors before continuing. Chat with the Kibana Operations Team if you do need help.' + ); + } + }, + { + usage: `node scripts/check_prod_native_modules`, + description: + 'Check if there are production dependencies that contains or installs dependencies that contain native modules and errors out on those cases', + } +); diff --git a/packages/kbn-check-prod-native-modules-cli/tsconfig.json b/packages/kbn-check-prod-native-modules-cli/tsconfig.json new file mode 100644 index 0000000000000..1ced58536098e --- /dev/null +++ b/packages/kbn-check-prod-native-modules-cli/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/repo-info", + "@kbn/tooling-log", + "@kbn/dev-cli-runner", + "@kbn/dev-cli-errors", + "@kbn/yarn-lock-validator", + ] +} diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index 656d3e1cf0fec..d494955d8d644 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -50,6 +50,7 @@ export { getLogLevelCoalescedValueLabel, LogLevelCoalescedValue, LogLevelBadge, + getFieldValue, } from './src'; export type { LogsContextService } from './src'; diff --git a/packages/kbn-discover-utils/src/utils/get_field_value.test.ts b/packages/kbn-discover-utils/src/utils/get_field_value.test.ts new file mode 100644 index 0000000000000..fcdc151f54947 --- /dev/null +++ b/packages/kbn-discover-utils/src/utils/get_field_value.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { DataTableRecord } from '../types'; +import { getFieldValue } from './get_field_value'; + +const dataTableRecord: DataTableRecord = { + id: '1', + raw: {}, + flattened: { + 'field1.value': 'value1', + 'field2.value': ['value2'], + }, +}; + +describe('getFieldValue', () => { + it('should return the value of field correctly', () => { + expect(getFieldValue(dataTableRecord, 'field1.value')).toBe('value1'); + }); + + it('should return the first value of field correctly if field has a value of Array type', () => { + expect(getFieldValue(dataTableRecord, 'field2.value')).toBe('value2'); + }); + + it('should return undefined when field is not available', () => { + expect(getFieldValue(dataTableRecord, 'field3.value')).toBeUndefined(); + }); +}); diff --git a/packages/kbn-discover-utils/src/utils/get_field_value.ts b/packages/kbn-discover-utils/src/utils/get_field_value.ts new file mode 100644 index 0000000000000..043b5f2458a7a --- /dev/null +++ b/packages/kbn-discover-utils/src/utils/get_field_value.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { DataTableRecord } from '../types'; + +export const getFieldValue = (record: DataTableRecord, field: string) => { + const value = record.flattened[field]; + return Array.isArray(value) ? value[0] : value; +}; diff --git a/packages/kbn-discover-utils/src/utils/index.ts b/packages/kbn-discover-utils/src/utils/index.ts index fd368beda5d7c..6c719f74dfa7a 100644 --- a/packages/kbn-discover-utils/src/utils/index.ts +++ b/packages/kbn-discover-utils/src/utils/index.ts @@ -15,5 +15,6 @@ export * from './get_log_document_overview'; export * from './get_message_field_with_fallbacks'; export * from './get_should_show_field_handler'; export * from './nested_fields'; +export * from './get_field_value'; export * from './calc_field_counts'; export { isLegacyTableEnabled } from './is_legacy_table_enabled'; diff --git a/packages/kbn-expandable-flyout/__mocks__/index.tsx b/packages/kbn-expandable-flyout/__mocks__/index.tsx new file mode 100644 index 0000000000000..1b35419219fbb --- /dev/null +++ b/packages/kbn-expandable-flyout/__mocks__/index.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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'; + +export const useExpandableFlyoutApi = jest.fn(() => ({ + openFlyout: jest.fn(), + closeFlyout: jest.fn(), + openPanels: jest.fn(), + openRightPanel: jest.fn(), + openLeftPanel: jest.fn(), + openPreviewPanel: jest.fn(), + closeRightPanel: jest.fn(), + closeLeftPanel: jest.fn(), + closePreviewPanel: jest.fn(), + closePanels: jest.fn(), + previousPreviewPanel: jest.fn(), +})); + +export const useExpandableFlyoutState = jest.fn(); + +export const ExpandableFlyoutProvider = jest.fn(({ children }: React.PropsWithChildren<{}>) => { + return <>{children}; +}); + +export const withExpandableFlyoutProvider = ( + Component: React.ComponentType +) => { + return (props: T) => { + return ; + }; +}; + +export const ExpandableFlyout = jest.fn(); diff --git a/packages/kbn-expandable-flyout/index.ts b/packages/kbn-expandable-flyout/index.ts index e5eaae99c26f8..00f9b1521cc4d 100644 --- a/packages/kbn-expandable-flyout/index.ts +++ b/packages/kbn-expandable-flyout/index.ts @@ -14,6 +14,7 @@ export { useExpandableFlyoutState } from './src/hooks/use_expandable_flyout_stat export { type FlyoutState as ExpandableFlyoutState } from './src/state'; export { ExpandableFlyoutProvider } from './src/provider'; +export { withExpandableFlyoutProvider } from './src/with_provider'; export type { ExpandableFlyoutProps } from './src'; export type { FlyoutPanelProps, PanelPath, ExpandableFlyoutApi } from './src/types'; diff --git a/packages/kbn-expandable-flyout/src/index.test.tsx b/packages/kbn-expandable-flyout/src/index.test.tsx index d08a78c706781..2235cbd5d408b 100644 --- a/packages/kbn-expandable-flyout/src/index.test.tsx +++ b/packages/kbn-expandable-flyout/src/index.test.tsx @@ -110,4 +110,27 @@ describe('ExpandableFlyout', () => { expect(getByTestId(PREVIEW_SECTION_TEST_ID)).toBeInTheDocument(); }); + + it('should not render flyout when right has value but does not matches registered panels', () => { + const state = { + byId: { + [id]: { + right: { + id: 'key1', + }, + left: undefined, + preview: undefined, + }, + }, + }; + + const { queryByTestId } = render( + + + + ); + + expect(queryByTestId('my-test-flyout')).toBeNull(); + expect(queryByTestId(RIGHT_SECTION_TEST_ID)).toBeNull(); + }); }); diff --git a/packages/kbn-expandable-flyout/src/index.tsx b/packages/kbn-expandable-flyout/src/index.tsx index ba11b597e0b06..a112187bd733b 100644 --- a/packages/kbn-expandable-flyout/src/index.tsx +++ b/packages/kbn-expandable-flyout/src/index.tsx @@ -86,7 +86,8 @@ export const ExpandableFlyout: React.FC = ({ showPreview, }); - const hideFlyout = !left && !right && !preview?.length; + const hideFlyout = !(left && leftSection) && !(right && rightSection) && !preview?.length; + if (hideFlyout) { return null; } @@ -94,6 +95,7 @@ export const ExpandableFlyout: React.FC = ({ return ( { diff --git a/packages/kbn-expandable-flyout/src/with_provider.test.tsx b/packages/kbn-expandable-flyout/src/with_provider.test.tsx new file mode 100644 index 0000000000000..e262157048778 --- /dev/null +++ b/packages/kbn-expandable-flyout/src/with_provider.test.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { render } from '@testing-library/react'; +import { useExpandableFlyoutApi } from './hooks/use_expandable_flyout_api'; +import React from 'react'; +import { withExpandableFlyoutProvider } from './with_provider'; + +const TestComponent = () => { + useExpandableFlyoutApi(); + + return
; +}; + +describe('withExpandableFlyoutProvider', () => { + it('should throw when rendered without Expandable Provider', () => { + expect(() => render()).toThrow(); + }); + + it('should not throw when rendered with Expandable Provider', () => { + const TestComponentWithProvider = withExpandableFlyoutProvider(TestComponent); + expect(() => render()).not.toThrow(); + }); +}); diff --git a/packages/kbn-expandable-flyout/src/with_provider.tsx b/packages/kbn-expandable-flyout/src/with_provider.tsx new file mode 100644 index 0000000000000..a12b46a6405d0 --- /dev/null +++ b/packages/kbn-expandable-flyout/src/with_provider.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 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 { ComponentType } from 'react'; +import { ExpandableFlyoutContextProviderProps } from './context'; +import { ExpandableFlyoutProvider } from './provider'; + +export const withExpandableFlyoutProvider = ( + Component: ComponentType, + expandableProviderProps?: ExpandableFlyoutContextProviderProps +) => { + return (props: Props) => { + return ( + + + + ); + }; +}; diff --git a/packages/kbn-ftr-common-functional-ui-services/services/browser.ts b/packages/kbn-ftr-common-functional-ui-services/services/browser.ts index c017433446d75..8ac46821c60bf 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/browser.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/browser.ts @@ -590,6 +590,27 @@ class BrowserService extends FtrService { await this.driver.executeScript('return window.localStorage.clear();'); } + /** + * Adds a value in session storage for the focused window/frame. + * + * @return {Promise} + */ + public async getSessionStorageItem(key: string): Promise { + return await this.driver.executeScript( + `return window.sessionStorage.getItem("${key}");` + ); + } + + /** + * Removes a value in session storage for the focused window/frame. + * + * @param {string} key + * @return {Promise} + */ + public async removeSessionStorageItem(key: string): Promise { + await this.driver.executeScript('return window.sessionStorage.removeItem(arguments[0]);', key); + } + /** * Clears session storage for the focused window/frame. * diff --git a/packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts b/packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts index 6eb10984eeb66..a4c45e7b24e7c 100644 --- a/packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/remote/remote.ts @@ -18,6 +18,16 @@ export async function RemoteProvider({ getService }: FtrProviderContext) { const browserType: Browsers = config.get('browser.type'); type BrowserStorage = 'sessionStorage' | 'localStorage'; + const getSessionStorageItem = async (key: string) => { + try { + return await driver.executeScript(`return window.sessionStorage.getItem("${key}");`); + } catch (error) { + if (!error.message.includes(`Failed to read the 'sessionStorage' property from 'Window'`)) { + throw error; + } + } + }; + const clearBrowserStorage = async (storageType: BrowserStorage) => { try { await driver.executeScript(`window.${storageType}.clear();`); @@ -93,6 +103,32 @@ export async function RemoteProvider({ getService }: FtrProviderContext) { lifecycle.afterTestSuite.add(async () => { await tryWebDriverCall(async () => { + // collect error message stashed in SessionStorage that indicate EuiProvider implementation error + const euiProviderWarning = await getSessionStorageItem('dev.euiProviderWarning'); + if (euiProviderWarning != null) { + let errorMessage: string; + let errorStack: string; + let pageHref: string; + let pageTitle: string; + try { + ({ + message: errorMessage, + stack: errorStack, + pageHref, + pageTitle, + } = JSON.parse(euiProviderWarning)); + } catch (error) { + throw new Error(`Found EuiProvider dev error, but the details could not be parsed`); + } + + log.error(`pageTitle: ${pageTitle}`); + log.error(`pageHref: ${pageHref}`); + log.error(`Error: ${errorMessage}`); + log.error(`Error stack: ${errorStack}`); + throw new Error(`Found EuiProvider dev error on: ${pageHref}`); + } + + // global cleanup const { width, height } = windowSizeStack.shift()!; await driver.manage().window().setRect({ width, height }); await clearBrowserStorage('sessionStorage'); diff --git a/packages/kbn-language-documentation-popover/src/components/documentation.scss b/packages/kbn-language-documentation-popover/src/components/documentation.scss index 752797decfa4e..2db3d25619d6e 100644 --- a/packages/kbn-language-documentation-popover/src/components/documentation.scss +++ b/packages/kbn-language-documentation-popover/src/components/documentation.scss @@ -62,8 +62,8 @@ } .documentation__docsText { - @include euiYScroll; padding: $euiSize; + @include euiYScroll; } .documentation__docsTextGroup, diff --git a/packages/kbn-test/src/auth/sesson_manager.test.ts b/packages/kbn-test/src/auth/session_manager.test.ts similarity index 98% rename from packages/kbn-test/src/auth/sesson_manager.test.ts rename to packages/kbn-test/src/auth/session_manager.test.ts index 929517e7c5a10..fe5e0e9fb9198 100644 --- a/packages/kbn-test/src/auth/sesson_manager.test.ts +++ b/packages/kbn-test/src/auth/session_manager.test.ts @@ -28,7 +28,6 @@ const roleEditor = 'editor'; const cloudUsersFilePath = resolve(REPO_ROOT, SERVERLESS_ROLES_ROOT_PATH, 'role_users.json'); const createLocalSAMLSessionMock = jest.spyOn(samlAuth, 'createLocalSAMLSession'); -const createCloudSAMLSessionMock = jest.spyOn(samlAuth, 'createCloudSAMLSession'); const getSecurityProfileMock = jest.spyOn(samlAuth, 'getSecurityProfile'); const readCloudUsersFromFileMock = jest.spyOn(helper, 'readCloudUsersFromFile'); const isValidHostnameMock = jest.spyOn(helper, 'isValidHostname'); @@ -41,6 +40,11 @@ jest.mock('../kbn_client/kbn_client', () => { const get = jest.fn(); describe('SamlSessionManager', () => { + let createCloudSAMLSessionMock: jest.SpyInstance; + beforeEach(() => { + createCloudSAMLSessionMock = jest.spyOn(samlAuth, 'createCloudSAMLSession'); + }); + describe('for local session', () => { beforeEach(() => { jest.resetAllMocks(); @@ -199,6 +203,7 @@ describe('SamlSessionManager', () => { }); test('should throw error if TEST_CLOUD_HOST_NAME is not set', async () => { + createCloudSAMLSessionMock.mockRestore(); isValidHostnameMock.mockReturnValueOnce(false); const samlSessionManager = new SamlSessionManager(samlSessionManagerOptions); await expect( diff --git a/packages/kbn-unified-data-table/kibana.jsonc b/packages/kbn-unified-data-table/kibana.jsonc index 3fe1b76b931c3..b80f8b6a55596 100644 --- a/packages/kbn-unified-data-table/kibana.jsonc +++ b/packages/kbn-unified-data-table/kibana.jsonc @@ -2,5 +2,8 @@ "type": "shared-browser", "id": "@kbn/unified-data-table", "description": "Contains functionality for the unified data table which can be integrated into apps", - "owner": "@elastic/kibana-data-discovery" + "owner": [ + "@elastic/kibana-data-discovery", + "@elastic/security-threat-hunting-investigations" + ] } diff --git a/packages/kbn-yarn-lock-validator/index.ts b/packages/kbn-yarn-lock-validator/index.ts index 819f81bf210a2..67f37fd554a61 100644 --- a/packages/kbn-yarn-lock-validator/index.ts +++ b/packages/kbn-yarn-lock-validator/index.ts @@ -9,3 +9,4 @@ export { readYarnLock } from './src/yarn_lock'; export type { YarnLock } from './src/yarn_lock'; export { validateDependencies } from './src/validate_yarn_lock'; +export { findProductionDependencies } from './src/find_production_dependencies'; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx index 76c36c03c0ac6..8a811c95ff298 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx @@ -73,6 +73,7 @@ export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl, active [`nav-item-isActive`]: isActive, }); const buttonDataTestSubj = classNames(`panelOpener`, `panelOpener-${path}`, { + [`panelOpener-id-${id}`]: id, [`panelOpener-deepLinkId-${deepLink?.id}`]: !!deepLink, }); diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx index ff79824176268..19757bc533d68 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx @@ -19,6 +19,17 @@ import classNames from 'classnames'; import { usePanel } from './context'; import { getNavPanelStyles, getPanelWrapperStyles } from './styles'; +import { PanelNavNode } from './types'; + +const getTestSubj = (selectedNode: PanelNavNode | null): string | undefined => { + if (!selectedNode) return; + + const deeplinkId = selectedNode.deepLink?.id; + return classNames(`sideNavPanel`, { + [`sideNavPanel-id-${selectedNode.id}`]: selectedNode.id, + [`sideNavPanel-deepLinkId-${deeplinkId}`]: !!deeplinkId, + }); +}; export const NavigationPanel: FC = () => { const { euiTheme } = useEuiTheme(); @@ -67,7 +78,7 @@ export const NavigationPanel: FC = () => { hasShadow borderRadius="none" paddingSize="m" - data-test-subj="sideNavPanel" + data-test-subj={getTestSubj(selectedNode)} > {getContent()} diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/panel/types.ts b/packages/shared-ux/chrome/navigation/src/ui/components/panel/types.ts index 25b2e00c83a81..04ebf2ec0b76b 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/panel/types.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/components/panel/types.ts @@ -27,7 +27,7 @@ export type ContentProvider = (nodeId: string) => PanelContent | void; export type PanelNavNode = Pick< ChromeProjectNavigationNode, - 'id' | 'children' | 'path' | 'sideNavStatus' + 'id' | 'children' | 'path' | 'sideNavStatus' | 'deepLink' > & { title: string | ReactNode; }; diff --git a/renovate.json b/renovate.json index 31f8630a3ad87..233505d4012de 100644 --- a/renovate.json +++ b/renovate.json @@ -1,9 +1,24 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:recommended", "helpers:pinGitHubActionDigests", "helpers:pinGitHubActionDigestsToSemver"], - "ignorePaths": ["**/__fixtures__/**", "**/fixtures/**"], - "enabledManagers": ["npm", "github-actions", "custom.regex"], - "baseBranches": ["main", "7.17"], + "extends": [ + "config:recommended", + "helpers:pinGitHubActionDigests", + "helpers:pinGitHubActionDigestsToSemver" + ], + "ignorePaths": [ + "**/__fixtures__/**", + "**/fixtures/**" + ], + "enabledManagers": [ + "npm", + "github-actions", + "custom.regex", + "devcontainer" + ], + "baseBranches": [ + "main", + "7.17" + ], "prConcurrentLimit": 0, "prHourlyLimit": 0, "separateMajorMinor": false, @@ -17,20 +32,51 @@ }, "packageRules": [ { - "matchDepPatterns": [".*"], - "enabled": false + "enabled": false, + "matchDepNames": [ + "/.*/" + ] + }, + { + "groupName": "devcontainer", + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip", + "backport:current-major" + ], + "enabled": true, + "matchManagers": [ + "devcontainer" + ] }, { "groupName": "chainguard", - "matchPackageNames": ["docker.elastic.co/wolfi/chainguard-base"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "matchPackageNames": [ + "docker.elastic.co/wolfi/chainguard-base" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "enabled": true }, { "groupName": "operations actions", - "matchManagers": ["github-actions"], + "matchManagers": [ + "github-actions" + ], "matchPackageNames": [ "actions/checkout", "elastic/github-actions/project-assigner", @@ -39,168 +85,367 @@ "sergeysova/jq-action", "sourenlouv/backport" ], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "backport:all-open", "release_note:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "backport:all-open", + "release_note:skip" + ], "enabled": true }, { "groupName": "@elastic/charts", - "matchDepNames": ["@elastic/charts"], - "reviewers": ["team:visualizations", "markov00", "nickofthyme"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "Team:Visualizations"], + "matchDepNames": [ + "@elastic/charts" + ], + "reviewers": [ + "team:visualizations", + "markov00", + "nickofthyme" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip", + "Team:Visualizations" + ], "enabled": true }, { "groupName": "@elastic/elasticsearch", - "matchDepNames": ["@elastic/elasticsearch"], - "reviewers": ["team:kibana-operations", "team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "Team:Operations", "Team:Core"], + "matchDepNames": [ + "@elastic/elasticsearch" + ], + "reviewers": [ + "team:kibana-operations", + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip", + "Team:Operations", + "Team:Core" + ], "enabled": true }, { "groupName": "@elastic/elasticsearch", - "matchDepNames": ["@elastic/elasticsearch"], - "reviewers": ["team:kibana-operations", "team:kibana-core"], - "matchBaseBranches": ["7.17"], - "labels": ["release_note:skip", "Team:Operations", "Team:Core", "backport:skip"], + "matchDepNames": [ + "@elastic/elasticsearch" + ], + "reviewers": [ + "team:kibana-operations", + "team:kibana-core" + ], + "matchBaseBranches": [ + "7.17" + ], + "labels": [ + "release_note:skip", + "Team:Operations", + "Team:Core", + "backport:skip" + ], "enabled": true }, { "groupName": "LaunchDarkly", - "matchDepNames": ["launchdarkly-js-client-sdk", "@launchdarkly/node-server-sdk", "launchdarkly/find-code-references"], - "reviewers": ["team:kibana-security", "team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "Team:Security", "Team:Core", "backport:prev-minor"], + "matchDepNames": [ + "launchdarkly-js-client-sdk", + "@launchdarkly/node-server-sdk", + "launchdarkly/find-code-references" + ], + "reviewers": [ + "team:kibana-security", + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "Team:Security", + "Team:Core", + "backport:prev-minor" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "APM", - "matchDepNames": ["elastic-apm-node", "@elastic/apm-rum", "@elastic/apm-rum-react"], - "reviewers": ["team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "Team:Core", "backport:skip"], + "matchDepNames": [ + "elastic-apm-node", + "@elastic/apm-rum", + "@elastic/apm-rum-react" + ], + "reviewers": [ + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "Team:Core", + "backport:skip" + ], "enabled": true }, { "groupName": "@elastic/ebt", - "matchDepNames": ["@elastic/ebt"], - "reviewers": ["team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "Team:Core", "backport:skip"], + "matchDepNames": [ + "@elastic/ebt" + ], + "reviewers": [ + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "Team:Core", + "backport:skip" + ], "enabled": true }, { "groupName": "ansi-regex", - "matchDepNames": ["ansi-regex"], - "reviewers": ["team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "Team:Core", "backport:skip"], + "matchDepNames": [ + "ansi-regex" + ], + "reviewers": [ + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "Team:Core", + "backport:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "OpenAPI Spec", - "matchDepNames": ["@redocly/cli"], - "reviewers": ["team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "Team:Core", "backport:skip"], + "matchDepNames": [ + "@redocly/cli" + ], + "reviewers": [ + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "Team:Core", + "backport:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "babel", - "matchDepNames": ["@types/babel__core"], - "matchDepPatterns": ["^@babel", "^babel-plugin"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "matchDepNames": [ + "@types/babel__core", + "/^@babel/", + "/^babel-plugin/" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "typescript", - "matchDepNames": ["typescript", "@types/jsdom"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "matchDepNames": [ + "typescript", + "@types/jsdom" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "prettier", - "matchDepNames": ["prettier", "eslint-plugin-prettier", "eslint-config-prettier"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "matchDepNames": [ + "prettier", + "eslint-plugin-prettier", + "eslint-config-prettier" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "allowedVersions": "<3.0", "enabled": true }, { "groupName": "typescript-eslint", - "matchDepPatterns": ["^@typescript-eslint"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", - "enabled": true + "enabled": true, + "matchDepNames": [ + "/^@typescript-eslint/" + ] }, { "groupName": "eslint-plugin-depend", - "matchDepPatterns": ["eslint-plugin-depend"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", - "enabled": true + "enabled": true, + "matchDepNames": [ + "/eslint-plugin-depend/" + ] }, { "groupName": "polyfills", - "matchDepNames": ["core-js"], - "matchDepPatterns": ["polyfill"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "matchDepNames": [ + "core-js", + "/polyfill/" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "CLI tooling", - "matchDepNames": ["listr2"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "backport:all-open", "release_note:skip"], + "matchDepNames": [ + "listr2" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "backport:all-open", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "vega related modules", - "matchDepNames": ["vega", "vega-lite", "vega-schema-url-parser", "vega-tooltip"], - "reviewers": ["team:kibana-visualizations"], - "matchBaseBranches": ["main"], - "labels": ["Feature:Vega", "Team:Visualizations"], + "matchDepNames": [ + "vega", + "vega-lite", + "vega-schema-url-parser", + "vega-tooltip" + ], + "reviewers": [ + "team:kibana-visualizations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Feature:Vega", + "Team:Visualizations" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "cypress", - "matchDepPatterns": ["cypress"], - "reviewers": ["Team:apm", "Team: SecuritySolution"], - "matchBaseBranches": ["main"], - "labels": ["buildkite-ci", "ci:all-cypress-suites"], + "reviewers": [ + "Team:apm", + "Team: SecuritySolution" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "buildkite-ci", + "ci:all-cypress-suites" + ], "minimumReleaseAge": "7 days", - "enabled": true + "enabled": true, + "matchDepNames": [ + "/cypress/" + ] }, { "groupName": "security solution modules", - "matchDepNames": ["zod", "langchain"], - "reviewers": ["Team: SecuritySolution"], - "matchBaseBranches": ["main"], - "labels": ["Team: SecuritySolution"], + "matchDepNames": [ + "zod", + "langchain" + ], + "reviewers": [ + "Team: SecuritySolution" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team: SecuritySolution" + ], "minimumReleaseAge": "7 days", "enabled": true }, @@ -218,9 +463,17 @@ "@types/xml-crypto", "@kayahr/text-encoding" ], - "reviewers": ["team:kibana-security"], - "matchBaseBranches": ["main"], - "labels": ["Team:Security", "release_note:skip", "backport:all-open"], + "reviewers": [ + "team:kibana-security" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Security", + "release_note:skip", + "backport:all-open" + ], "minimumReleaseAge": "7 days", "enabled": true }, @@ -230,9 +483,17 @@ "github/codeql-action/analyze", "github/codeql-action/init" ], - "reviewers": ["team:kibana-security"], - "matchBaseBranches": ["main"], - "labels": ["Team:Security", "release_note:skip", "backport:all-open"], + "reviewers": [ + "team:kibana-security" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Security", + "release_note:skip", + "backport:all-open" + ], "minimumReleaseAge": "7 days", "enabled": true }, @@ -246,27 +507,54 @@ "ms-chromium-edge-driver", "selenium-webdriver" ], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "scss", - "matchDepNames": ["sass-embedded"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip", "backport:all-open"], + "matchDepNames": [ + "sass-embedded" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip", + "backport:all-open" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "minify", - "matchDepNames": ["gulp-terser", "terser"], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "matchDepNames": [ + "gulp-terser", + "terser" + ], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, @@ -280,9 +568,16 @@ "@testing-library/user-event", "@types/testing-library__jest-dom" ], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, @@ -304,36 +599,68 @@ "jest-runtime", "jest-snapshot" ], - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "labels": ["Team:Operations", "release_note:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "@storybook", - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "matchDepPatterns": ["^@storybook"], - "excludeDepNames": ["@storybook/testing-react"], - "labels": ["Team:Operations", "release_note:skip", "ci:build-storybooks", "backport:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Operations", + "release_note:skip", + "ci:build-storybooks", + "backport:skip" + ], "minimumReleaseAge": "7 days", "allowedVersions": "<7.0", - "enabled": true + "enabled": true, + "matchDepNames": [ + "/^@storybook/", + "!@storybook/testing-react" + ] }, { "groupName": "@storybook/testing-react", - "reviewers": ["team:kibana-operations"], - "matchBaseBranches": ["main"], - "matchDepNames": ["@storybook/testing-react"], - "labels": ["Team:Operations", "release_note:skip", "ci:build-storybooks", "backport:skip"], + "reviewers": [ + "team:kibana-operations" + ], + "matchBaseBranches": [ + "main" + ], + "matchDepNames": [ + "@storybook/testing-react" + ], + "labels": [ + "Team:Operations", + "release_note:skip", + "ci:build-storybooks", + "backport:skip" + ], "minimumReleaseAge": "7 days", "allowedVersions": "<2.0", "enabled": true }, { "groupName": "react-query", - "matchDepNames": ["@tanstack/react-query", "@tanstack/react-query-devtools"], + "matchDepNames": [ + "@tanstack/react-query", + "@tanstack/react-query-devtools" + ], "reviewers": [ "team:response-ops", "team:kibana-cloud-security-posture", @@ -342,23 +669,43 @@ "team:awp-platform", "team:security-onboarding-and-lifecycle-mgt" ], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "ci:all-cypress-suites"], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip", + "ci:all-cypress-suites" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "react-hook-form", - "matchDepNames": ["react-hook-form"], - "reviewers": ["team:security-asset-management", "team:uptime"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "ci:all-cypress-suites"], + "matchDepNames": [ + "react-hook-form" + ], + "reviewers": [ + "team:security-asset-management", + "team:uptime" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip", + "ci:all-cypress-suites" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "redux", - "matchDepNames": ["redux", "react-redux"], + "matchDepNames": [ + "redux", + "react-redux" + ], "reviewers": [ "team:search-kibana", "team:kibana-presentation", @@ -367,115 +714,241 @@ "team:kibana-gis", "team:security-solution" ], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "ci:all-cypress-suites"], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip", + "ci:all-cypress-suites" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "Profiling", - "matchDepNames": ["peggy", "@types/dagre"], - "reviewers": ["team:obs-ux-infra_services-team"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip"], + "matchDepNames": [ + "peggy", + "@types/dagre" + ], + "reviewers": [ + "team:obs-ux-infra_services-team" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "TTY Output", - "matchDepNames": ["xterm", "byte-size", "@types/byte-size"], - "reviewers": ["team:sec-cloudnative-integrations"], - "matchBaseBranches": ["main"], - "labels": ["Team: AWP: Visualization", "release_note:skip", "backport:skip"], + "matchDepNames": [ + "xterm", + "byte-size", + "@types/byte-size" + ], + "reviewers": [ + "team:sec-cloudnative-integrations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team: AWP: Visualization", + "release_note:skip", + "backport:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "Cloud Defend", - "matchDepNames": ["monaco-yaml"], - "reviewers": ["team:sec-cloudnative-integrations"], - "matchBaseBranches": ["main"], - "labels": ["Team: Cloud Native Integrations", "release_note:skip", "backport:skip"], + "matchDepNames": [ + "monaco-yaml" + ], + "reviewers": [ + "team:sec-cloudnative-integrations" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team: Cloud Native Integrations", + "release_note:skip", + "backport:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "JSON Web Token", - "matchDepNames": ["jsonwebtoken"], - "reviewers": ["team:response-ops", "team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:all-open"], + "matchDepNames": [ + "jsonwebtoken" + ], + "reviewers": [ + "team:response-ops", + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:all-open" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "XState", - "matchDepNames": ["xstate"], - "matchDepPrefixes": ["@xstate/"], - "reviewers": ["team:obs-ux-logs-team"], - "matchBaseBranches": ["main"], - "labels": ["Team:Obs UX Logs", "release_note:skip"], + "matchDepNames": [ + "xstate", + "@xstate/{/,}**" + ], + "reviewers": [ + "team:obs-ux-logs-team" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Obs UX Logs", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "OpenTelemetry modules", - "matchDepPrefixes": ["@opentelemetry/"], - "reviewers": ["team:stack-monitoring"], - "matchBaseBranches": ["main"], - "labels": ["Team:Monitoring"], + "reviewers": [ + "team:stack-monitoring" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:Monitoring" + ], "minimumReleaseAge": "7 days", - "enabled": true + "enabled": true, + "matchDepNames": [ + "@opentelemetry/{/,}**" + ] }, { "groupName": "csp", - "matchDepNames": ["content-security-policy-parser"], - "reviewers": ["team:kibana-security", "team:kibana-core"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:skip", "ci:serverless-test-all"], + "matchDepNames": [ + "content-security-policy-parser" + ], + "reviewers": [ + "team:kibana-security", + "team:kibana-core" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:skip", + "ci:serverless-test-all" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "AlertingEmails", - "matchDepNames": ["nodemailer"], - "reviewers": ["team:response-ops"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:prev-minor"], + "matchDepNames": [ + "nodemailer" + ], + "reviewers": [ + "team:response-ops" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:prev-minor" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "Kibana ES|QL Team", - "matchDepNames": ["recast"], - "reviewers": ["team:kibana-esql"], - "matchBaseBranches": ["main"], - "labels": ["Team:ESQL", "release_note:skip"], + "matchDepNames": [ + "recast" + ], + "reviewers": [ + "team:kibana-esql" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team:ESQL", + "release_note:skip" + ], "minimumReleaseAge": "7 days", "enabled": true }, { "groupName": "MSW", - "matchPackageNames": ["msw"], - "reviewers": ["team:kibana-cloud-security-posture"], - "matchBaseBranches": ["main"], - "labels": ["Team: Cloud Security", "release_note:skip", "backport:skip"], + "matchPackageNames": [ + "msw" + ], + "reviewers": [ + "team:kibana-cloud-security-posture" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "Team: Cloud Security", + "release_note:skip", + "backport:skip" + ], "enabled": true }, { "groupName": "re2js", - "matchDepNames": ["re2js"], - "reviewers": ["team:visualizations", "dej611"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "backport:all-open", "Team:Visualizations"], + "matchDepNames": [ + "re2js" + ], + "reviewers": [ + "team:visualizations", + "dej611" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "backport:all-open", + "Team:Visualizations" + ], "enabled": true }, { "groupName": "Serve swagger docs", - "matchDepNames": ["express", "swagger-jsdoc", "swagger-ui-express"], - "reviewers": ["team:obs-entities"], - "matchBaseBranches": ["main"], - "labels": ["release_note:skip", "team:obs-entities"], + "matchDepNames": [ + "express", + "swagger-jsdoc", + "swagger-ui-express" + ], + "reviewers": [ + "team:obs-entities" + ], + "matchBaseBranches": [ + "main" + ], + "labels": [ + "release_note:skip", + "team:obs-entities" + ], "enabled": true } ], @@ -504,4 +977,4 @@ "datasourceTemplate": "docker" } ] -} +} \ No newline at end of file diff --git a/scripts/check_prod_native_modules.js b/scripts/check_prod_native_modules.js new file mode 100644 index 0000000000000..f47bcc4946c85 --- /dev/null +++ b/scripts/check_prod_native_modules.js @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../src/setup_node_env'); +require('@kbn/check-prod-native-modules-cli'); diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 75237f0ea3594..e2ffab235f34e 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -412,7 +412,11 @@ kibana_vars=( xpack.securitySolution.packagerTaskInterval xpack.securitySolution.prebuiltRulesPackageVersion xpack.spaces.maxSpaces + xpack.task_manager.capacity xpack.task_manager.claim_strategy + xpack.task_manager.discovery.active_nodes_lookback + xpack.task_manager.discovery.interval + xpack.task_manager.kibanas_per_partition xpack.task_manager.max_attempts xpack.task_manager.max_workers xpack.task_manager.monitored_aggregated_stats_refresh_rate diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 0ea6dbb3d8b58..f89d32ac555b7 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -112,6 +112,7 @@ export const IGNORE_DIRECTORY_GLOBS = [ 'packages/*', 'packages/core/*/*', 'packages/kbn-pm/src/utils/__fixtures__/*', + 'packages/kbn-check-prod-native-modules-cli/integration_tests/__fixtures__/*/node_modules/*', 'x-pack/dev-tools', 'packages/kbn-optimizer/src/__fixtures__/mock_repo/x-pack', 'typings/*', diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx index 0e1c1472ac556..4ceae12fe8929 100644 --- a/src/plugins/discover/public/application/main/discover_main_route.tsx +++ b/src/plugins/discover/public/application/main/discover_main_route.tsx @@ -354,7 +354,10 @@ export function DiscoverMainRoute({ <> - + {mainContent} diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx index 747bada5b0284..2d30aeee2e2c3 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_data_source_profile/profile.tsx @@ -7,7 +7,7 @@ */ import { EuiBadge } from '@elastic/eui'; -import type { DataTableRecord } from '@kbn/discover-utils'; +import { getFieldValue } from '@kbn/discover-utils'; import type { RowControlColumn } from '@kbn/unified-data-table'; import { isOfAggregateQueryType } from '@kbn/es-query'; import { getIndexPatternFromESQLQuery } from '@kbn/esql-utils'; @@ -19,6 +19,7 @@ import { DataSourceCategory, DataSourceProfileProvider } from '../../profiles'; export const exampleDataSourceProfileProvider: DataSourceProfileProvider = { profileId: 'example-data-source-profile', + isExperimental: true, profile: { getCellRenderers: (prev) => () => ({ ...prev(), @@ -137,8 +138,3 @@ export const exampleDataSourceProfileProvider: DataSourceProfileProvider = { }; }, }; - -const getFieldValue = (record: DataTableRecord, field: string) => { - const value = record.flattened[field]; - return Array.isArray(value) ? value[0] : value; -}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts index 9739430e08000..61045fe37c342 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_document_profile/profile.ts @@ -6,11 +6,12 @@ * Side Public License, v 1. */ -import type { DataTableRecord } from '@kbn/discover-utils'; +import { getFieldValue } from '@kbn/discover-utils'; import { DocumentProfileProvider, DocumentType } from '../../profiles'; export const exampleDocumentProfileProvider: DocumentProfileProvider = { profileId: 'example-document-profile', + isExperimental: true, profile: {}, resolve: (params) => { if (getFieldValue(params.record, 'data_stream.type') !== 'example') { @@ -25,8 +26,3 @@ export const exampleDocumentProfileProvider: DocumentProfileProvider = { }; }, }; - -const getFieldValue = (record: DataTableRecord, field: string) => { - const value = record.flattened[field]; - return Array.isArray(value) ? value[0] : value; -}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx index 389059c518217..4d00318018a48 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/example_root_pofile/profile.tsx @@ -13,6 +13,7 @@ import { RootProfileProvider, SolutionType } from '../../profiles'; export const exampleRootProfileProvider: RootProfileProvider = { profileId: 'example-root-profile', + isExperimental: true, profile: { getCellRenderers: (prev) => () => ({ ...prev(), diff --git a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts index 78048cdcbad60..de404317b1a39 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.test.ts @@ -12,34 +12,51 @@ import { exampleDataSourceProfileProvider } from './example_data_source_profile' import { exampleDocumentProfileProvider } from './example_document_profile'; import { exampleRootProfileProvider } from './example_root_pofile'; import { - registerEnabledProfileProviders, registerProfileProviders, + registerEnabledProfileProviders, } from './register_profile_providers'; describe('registerEnabledProfileProviders', () => { - it('should register enabled profile providers', async () => { + it('should register all profile providers', async () => { const { rootProfileServiceMock, rootProfileProviderMock } = createContextAwarenessMocks({ shouldRegisterProviders: false, }); registerEnabledProfileProviders({ profileService: rootProfileServiceMock, - availableProviders: [rootProfileProviderMock], - enabledProfileIds: ['root-profile'], + providers: [rootProfileProviderMock], + enabledExperimentalProfileIds: [], }); const context = await rootProfileServiceMock.resolve({ solutionNavId: null }); expect(rootProfileServiceMock.getProfile(context)).toBe(rootProfileProviderMock.profile); }); - it('should not register disabled profile providers', async () => { + it('should not register experimental profile providers by default', async () => { + const { rootProfileServiceMock } = createContextAwarenessMocks({ + shouldRegisterProviders: false, + }); + + registerEnabledProfileProviders({ + profileService: rootProfileServiceMock, + providers: [exampleRootProfileProvider], + enabledExperimentalProfileIds: [], + }); + const context = await rootProfileServiceMock.resolve({ solutionNavId: null }); + expect(rootProfileServiceMock.getProfile(context)).not.toBe(exampleRootProfileProvider.profile); + expect(rootProfileServiceMock.getProfile(context)).toMatchObject({}); + }); + + it('should register experimental profile providers when enabled by config', async () => { const { rootProfileServiceMock, rootProfileProviderMock } = createContextAwarenessMocks({ shouldRegisterProviders: false, }); + registerEnabledProfileProviders({ profileService: rootProfileServiceMock, - availableProviders: [rootProfileProviderMock], - enabledProfileIds: [], + providers: [exampleRootProfileProvider], + enabledExperimentalProfileIds: [exampleRootProfileProvider.profileId], }); const context = await rootProfileServiceMock.resolve({ solutionNavId: null }); + expect(rootProfileServiceMock.getProfile(context)).toBe(exampleRootProfileProvider.profile); expect(rootProfileServiceMock.getProfile(context)).not.toBe(rootProfileProviderMock.profile); }); }); @@ -54,7 +71,7 @@ describe('registerProfileProviders', () => { rootProfileService: rootProfileServiceMock, dataSourceProfileService: dataSourceProfileServiceMock, documentProfileService: documentProfileServiceMock, - experimentalProfileIds: [ + enabledExperimentalProfileIds: [ exampleRootProfileProvider.profileId, exampleDataSourceProfileProvider.profileId, exampleDocumentProfileProvider.profileId, @@ -93,7 +110,7 @@ describe('registerProfileProviders', () => { rootProfileService: rootProfileServiceMock, dataSourceProfileService: dataSourceProfileServiceMock, documentProfileService: documentProfileServiceMock, - experimentalProfileIds: [], + enabledExperimentalProfileIds: [], }); const rootContext = await rootProfileServiceMock.resolve({ solutionNavId: null }); const dataSourceContext = await dataSourceProfileServiceMock.resolve({ diff --git a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts index 22ed673cd9558..ffbad9bfe6f71 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/register_profile_providers.ts @@ -6,11 +6,9 @@ * Side Public License, v 1. */ -import { uniq } from 'lodash'; import type { DataSourceProfileService, DocumentProfileService, - RootProfileProvider, RootProfileService, } from '../profiles'; import type { BaseProfileProvider, BaseProfileService } from '../profile_service'; @@ -19,6 +17,7 @@ import { exampleDocumentProfileProvider } from './example_document_profile'; import { exampleRootProfileProvider } from './example_root_pofile'; import { createLogsDataSourceProfileProviders } from './logs_data_source_profile'; import { createLogDocumentProfileProvider } from './log_document_profile'; +import { createSecurityRootProfileProvider } from './security/security_root_profile'; import { createProfileProviderServices, ProfileProviderServices, @@ -28,40 +27,37 @@ export const registerProfileProviders = ({ rootProfileService, dataSourceProfileService, documentProfileService, - experimentalProfileIds, + enabledExperimentalProfileIds, }: { rootProfileService: RootProfileService; dataSourceProfileService: DataSourceProfileService; documentProfileService: DocumentProfileService; - experimentalProfileIds: string[]; + /** + * List of experimental profile Ids which are enabled in kibana config. + * */ + enabledExperimentalProfileIds: string[]; }) => { const providerServices = createProfileProviderServices(); const rootProfileProviders = createRootProfileProviders(providerServices); const dataSourceProfileProviders = createDataSourceProfileProviders(providerServices); const documentProfileProviders = createDocumentProfileProviders(providerServices); - const enabledProfileIds = uniq([ - ...extractProfileIds(rootProfileProviders), - ...extractProfileIds(dataSourceProfileProviders), - ...extractProfileIds(documentProfileProviders), - ...experimentalProfileIds, - ]); registerEnabledProfileProviders({ profileService: rootProfileService, - availableProviders: [exampleRootProfileProvider, ...rootProfileProviders], - enabledProfileIds, + providers: [...rootProfileProviders], + enabledExperimentalProfileIds, }); registerEnabledProfileProviders({ profileService: dataSourceProfileService, - availableProviders: [exampleDataSourceProfileProvider, ...dataSourceProfileProviders], - enabledProfileIds, + providers: [...dataSourceProfileProviders], + enabledExperimentalProfileIds, }); registerEnabledProfileProviders({ profileService: documentProfileService, - availableProviders: [exampleDocumentProfileProvider, ...documentProfileProviders], - enabledProfileIds, + providers: [...documentProfileProviders], + enabledExperimentalProfileIds, }); }; @@ -70,30 +66,37 @@ export const registerEnabledProfileProviders = < TService extends BaseProfileService >({ profileService, - availableProviders, - enabledProfileIds, + providers: availableProviders, + enabledExperimentalProfileIds = [], }: { profileService: TService; - availableProviders: TProvider[]; - enabledProfileIds: string[]; + providers: TProvider[]; + /** + * List of experimental profile Ids which are enabled in kibana config. + * */ + enabledExperimentalProfileIds?: string[]; }) => { for (const provider of availableProviders) { - if (enabledProfileIds.includes(provider.profileId)) { + const isProfileExperimental = provider.isExperimental ?? false; + const isProfileEnabled = + enabledExperimentalProfileIds.includes(provider.profileId) || !isProfileExperimental; + if (isProfileEnabled) { profileService.registerProvider(provider); } } }; -const extractProfileIds = (providers: Array>) => - providers.map(({ profileId }) => profileId); - -const createRootProfileProviders = (_providerServices: ProfileProviderServices) => - [] as RootProfileProvider[]; +const createRootProfileProviders = (_providerServices: ProfileProviderServices) => [ + exampleRootProfileProvider, + createSecurityRootProfileProvider(_providerServices), +]; const createDataSourceProfileProviders = (providerServices: ProfileProviderServices) => [ + exampleDataSourceProfileProvider, ...createLogsDataSourceProfileProviders(providerServices), ]; const createDocumentProfileProviders = (providerServices: ProfileProviderServices) => [ + exampleDocumentProfileProvider, createLogDocumentProfileProvider(providerServices), ]; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/index.ts b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/index.ts new file mode 100644 index 0000000000000..b6bf175abed4d --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { createSecurityRootProfileProvider } from './profile'; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx new file mode 100644 index 0000000000000..1bd58e361d88b --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { getDiscoverCellRenderer } from '@kbn/security-solution-common'; +import { RootProfileProvider, SolutionType } from '../../../profiles'; +import { ProfileProviderServices } from '../../profile_provider_services'; +import { SecurityProfileProviderFactory } from '../types'; + +export const createSecurityRootProfileProvider: SecurityProfileProviderFactory< + RootProfileProvider +> = (services: ProfileProviderServices) => ({ + profileId: 'security-root-profile', + isExperimental: true, + profile: { + getCellRenderers: (prev) => () => ({ + ...prev(), + 'host.name': (props) => { + const CellRenderer = getDiscoverCellRenderer({ + fieldName: 'host.name', + }); + return ; + }, + }), + }, + resolve: (params) => { + if (params.solutionNavId === SolutionType.Security) { + return { isMatch: true, context: { solutionType: SolutionType.Security } }; + } + + return { isMatch: false }; + }, +}); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/types.ts b/src/plugins/discover/public/context_awareness/profile_providers/security/types.ts new file mode 100644 index 0000000000000..f04ec6f00efb1 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/types.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. + */ + +import { ProfileProviderServices } from '../profile_provider_services'; + +export type SecurityProfileProviderFactory = (services: ProfileProviderServices) => T; diff --git a/src/plugins/discover/public/context_awareness/profile_service.ts b/src/plugins/discover/public/context_awareness/profile_service.ts index efc143e222414..ac4f4eacee42c 100644 --- a/src/plugins/discover/public/context_awareness/profile_service.ts +++ b/src/plugins/discover/public/context_awareness/profile_service.ts @@ -20,6 +20,18 @@ export type ContextWithProfileId = TContext & { profileId: string }; export interface BaseProfileProvider { profileId: string; profile: ComposableProfile; + /** + * isExperimental Flag can be used for any profile which is under development and should not be enabled by default. + * + * Experimental profiles can still be enabled in kibana config with option `discover.experimental.enabledProfiles` as shown in example below: + * + * ```yaml + * discover.experimental.enabledProfiles: + * - example-root-profile + * - example-data-source-profile + * ``` + */ + isExperimental?: boolean; } export interface ProfileProvider diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index d81bacb958d38..61a205be2cff5 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -306,13 +306,13 @@ export class DiscoverPlugin const rootProfileService = new RootProfileService(); const dataSourceProfileService = new DataSourceProfileService(); const documentProfileService = new DocumentProfileService(); - const experimentalProfileIds = this.experimentalFeatures.enabledProfiles ?? []; + const enabledExperimentalProfileIds = this.experimentalFeatures.enabledProfiles ?? []; registerProfileProviders({ rootProfileService, dataSourceProfileService, documentProfileService, - experimentalProfileIds, + enabledExperimentalProfileIds, }); return { rootProfileService, dataSourceProfileService, documentProfileService }; diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 526b3ea6ddf3c..a363981a5d731 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -94,7 +94,10 @@ "@kbn/search-types", "@kbn/presentation-containers", "@kbn/observability-ai-assistant-plugin", - "@kbn/fields-metadata-plugin" + "@kbn/fields-metadata-plugin", + "@kbn/security-solution-common" ], - "exclude": ["target/**/*"] + "exclude": [ + "target/**/*" + ] } diff --git a/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts b/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts index cbd29e6bf4c18..a4121ed4195d1 100644 --- a/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts +++ b/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.test.ts @@ -9,13 +9,12 @@ import type { Logger } from '@kbn/core/server'; import { set } from '@kbn/safer-lodash-set'; import { Readable } from 'stream'; -import { encode } from 'cbor-x'; +import { encode, decode } from '@kbn/cbor'; import { elasticsearchServiceMock, loggingSystemMock } from '@kbn/core/server/mocks'; import { ContentStream, ContentStreamEncoding, ContentStreamParameters } from './content_stream'; import type { GetResponse } from '@elastic/elasticsearch/lib/api/types'; import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { FileDocument } from '../../../../file_client/file_metadata_client/adapters/es_index'; -import * as cborx from 'cbor-x'; import { IndexRequest } from '@elastic/elasticsearch/lib/api/types'; describe('ContentStream', () => { @@ -415,7 +414,7 @@ describe('ContentStream', () => { stream.end('some data'); await new Promise((resolve) => stream.once('finish', resolve)); const docBuffer = (client.index.mock.calls[0][0] as IndexRequest).document as Buffer; - const docData = cborx.decode(docBuffer); + const docData = decode(docBuffer); expect(docData).toHaveProperty('@timestamp'); }); diff --git a/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts b/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts index 9c8fc7fbe84c7..1e1d4c9d21708 100644 --- a/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts +++ b/src/plugins/files/server/blob_storage_service/adapters/es/content_stream/content_stream.ts @@ -7,7 +7,7 @@ */ import { createId } from '@paralleldrive/cuid2'; -import * as cborx from 'cbor-x'; +import { encode, decode } from '@kbn/cbor'; import { errors as esErrors } from '@elastic/elasticsearch'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { ByteSizeValue } from '@kbn/config-schema'; @@ -144,7 +144,7 @@ export class ContentStream extends Duplex { } const buffer = Buffer.concat(chunks); const decodedChunkDoc: GetResponse | undefined = buffer.byteLength - ? (cborx.decode(buffer) as GetResponse) + ? (decode(buffer) as GetResponse) : undefined; // Because `asStream` was used in retrieving the document, errors are also not be processed @@ -245,7 +245,7 @@ export class ContentStream extends Duplex { id, index, op_type: 'create', - document: cborx.encode({ + document: encode({ data, bid, // Mark it as last? diff --git a/src/plugins/files/server/blob_storage_service/adapters/es/es.test.ts b/src/plugins/files/server/blob_storage_service/adapters/es/es.test.ts index 947d9eecd8fd0..2279b85165299 100644 --- a/src/plugins/files/server/blob_storage_service/adapters/es/es.test.ts +++ b/src/plugins/files/server/blob_storage_service/adapters/es/es.test.ts @@ -7,7 +7,7 @@ */ import { Readable } from 'stream'; -import { encode } from 'cbor-x'; +import { encode } from '@kbn/cbor'; import { promisify } from 'util'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; diff --git a/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts b/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts index 981810e968f65..922c84fa015d3 100644 --- a/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts +++ b/src/plugins/files/server/blob_storage_service/adapters/es/integration_tests/es.test.ts @@ -107,7 +107,7 @@ describe('Elasticsearch blob storage', () => { esBlobStorage = createEsBlobStorage({ chunkSize: '1024B' }); const { id } = await esBlobStorage.upload(Readable.from([fileString])); expect(await getAllDocCount()).toMatchObject({ count: 37 }); - esRefreshIndexSpy.mockReset(); + esRefreshIndexSpy.mockClear(); const rs = await esBlobStorage.download({ id }); expect(esRefreshIndexSpy).toHaveBeenCalled(); // Make sure we refresh the index before downloading the chunks const chunks: string[] = []; @@ -141,7 +141,7 @@ describe('Elasticsearch blob storage', () => { const { id } = await esBlobStorage.upload(Readable.from([fileString])); const { id: id2 } = await esBlobStorage.upload(Readable.from([fileString2])); expect(await getAllDocCount()).toMatchObject({ count: 10 }); - esRefreshIndexSpy.mockReset(); + esRefreshIndexSpy.mockClear(); await esBlobStorage.delete(id); expect(esRefreshIndexSpy).toHaveBeenCalled(); // Make sure we refresh the index before deleting the chunks expect(await getAllDocCount()).toMatchObject({ count: 2 }); diff --git a/src/plugins/files/tsconfig.json b/src/plugins/files/tsconfig.json index 29f7281340dd0..c31650d197ba2 100644 --- a/src/plugins/files/tsconfig.json +++ b/src/plugins/files/tsconfig.json @@ -33,6 +33,7 @@ "@kbn/logging", "@kbn/core-http-common", "@kbn/core-lifecycle-server-internal", + "@kbn/cbor", ], "exclude": [ "target/**/*", diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_degraded_fields.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_degraded_fields.tsx index 976ef71c6b647..2ff0d6a224af2 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_degraded_fields.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_logs_overview/logs_overview_degraded_fields.tsx @@ -23,7 +23,10 @@ import { import { i18n } from '@kbn/i18n'; import { orderBy } from 'lodash'; import { getRouterLinkProps } from '@kbn/router-utils'; -import { DATA_QUALITY_LOCATOR_ID, DataQualityLocatorParams } from '@kbn/deeplinks-observability'; +import { + DATA_QUALITY_DETAILS_LOCATOR_ID, + DataQualityDetailsLocatorParams, +} from '@kbn/deeplinks-observability'; import { BrowserUrlService } from '@kbn/share-plugin/public'; import { getUnifiedDocViewerServices } from '../../plugin'; @@ -39,13 +42,6 @@ interface DegradedField { values: string[]; } -interface ParamsForLocator { - dataStreamType: string; - dataStreamName: string; - dataStreamNamespace: string; - rawName: string; -} - interface TableOptions { page: { index: number; @@ -117,7 +113,7 @@ export const LogsOverviewDegradedFields = ({ rawDoc }: { rawDoc: DataTableRecord const columns = getDegradedFieldsColumns(); const tableData = getDataFormattedForTable(ignoredFieldValues); - const paramsForLocator = getParamsForLocator(sourceFields); + const dataStream = getDataStreamRawName(sourceFields); const accordionId = useGeneratedHtmlId({ prefix: qualityIssuesAccordionTitle, @@ -194,9 +190,7 @@ export const LogsOverviewDegradedFields = ({ rawDoc }: { rawDoc: DataTableRecord buttonContent={accordionTitle} paddingSize="m" initialIsOpen={false} - extraAction={ - - } + extraAction={} data-test-subj="unifiedDocViewLogsOverviewDegradedFieldsAccordion" > { +): string | undefined => { if (sourceFields) { const dataStreamTypeArr = sourceFields['data_stream.type']; const dataStreamType = dataStreamTypeArr ? dataStreamTypeArr[0] : undefined; @@ -256,49 +250,35 @@ const getParamsForLocator = ( const dataStreamName = dataStreamNameArr ? dataStreamNameArr[0] : undefined; const dataStreamNamespaceArr = sourceFields['data_stream.namespace']; const dataStreamNamespace = dataStreamNamespaceArr ? dataStreamNamespaceArr[0] : undefined; - let rawName; + let dataStream; if (dataStreamType && dataStreamName && dataStreamNamespace) { - rawName = `${dataStreamType}-${dataStreamName}-${dataStreamNamespace}`; + dataStream = `${dataStreamType}-${dataStreamName}-${dataStreamNamespace}`; } - if (rawName) { - return { - dataStreamType, - dataStreamName, - dataStreamNamespace, - rawName, - }; - } + return dataStream; } }; const DatasetQualityLink = React.memo( ({ urlService, - paramsForLocator, + dataStream, }: { urlService: BrowserUrlService; - paramsForLocator?: ParamsForLocator; + dataStream: string | undefined; }) => { - const locator = urlService.locators.get(DATA_QUALITY_LOCATOR_ID); - const locatorParams: DataQualityLocatorParams = paramsForLocator - ? { - flyout: { - dataset: { - rawName: paramsForLocator.rawName, - type: paramsForLocator.dataStreamType, - name: paramsForLocator.dataStreamName, - namespace: paramsForLocator.dataStreamNamespace, - }, - }, - } - : {}; - - const datasetQualityUrl = locator?.getRedirectUrl(locatorParams); + if (!dataStream) { + return null; + } + const locator = urlService.locators.get( + DATA_QUALITY_DETAILS_LOCATOR_ID + ); + + const datasetQualityUrl = locator?.getRedirectUrl({ dataStream }); const navigateToDatasetQuality = () => { - locator?.navigate(locatorParams); + locator?.navigate({ dataStream }); }; const datasetQualityLinkProps = getRouterLinkProps({ @@ -306,7 +286,7 @@ const DatasetQualityLink = React.memo( onClick: navigateToDatasetQuality, }); - return paramsForLocator ? ( + return ( {datasetQualityLinkTitle} - ) : null; + ); } ); diff --git a/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx b/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx index 003f8181bfefb..559174711af3b 100644 --- a/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx +++ b/src/plugins/unified_search/public/dataview_picker/dataview_list.tsx @@ -149,6 +149,7 @@ export function DataViewsList({ searchProps={{ id: searchListInputId, compressed: true, + autoFocus: true, placeholder: strings.editorAndPopover.search.getSearchPlaceholder(), 'data-test-subj': 'indexPattern-switcher--input', ...(selectableProps ? selectableProps.searchProps : undefined), diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile.test.ts index 885a2b16b44cc..e8f8fe266f78a 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile.test.ts @@ -226,7 +226,9 @@ describe('convertToPercentileColumns', () => { if (expected === null) { expect(convertToPercentileColumns(...input)).toBeNull(); } else if (Array.isArray(expected)) { - expect(convertToPercentileColumns(...input)).toEqual(expected.map(expect.objectContaining)); + expect(convertToPercentileColumns(...input)).toEqual( + expected.map((el) => (el === null ? null : expect.objectContaining(el))) + ); } else { expect(convertToPercentileColumns(...input)).toEqual(expect.objectContaining(expected)); } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile_rank.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile_rank.test.ts index 25c047f8a19be..a1b09b57119b2 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile_rank.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/percentile_rank.test.ts @@ -202,7 +202,7 @@ describe('convertToPercentileRankColumns', () => { expect(convertToPercentileRankColumns(...input)).toBeNull(); } else if (Array.isArray(expected)) { expect(convertToPercentileRankColumns(...input)).toEqual( - expected.map(expect.objectContaining) + expected.map((el) => (el === null ? null : expect.objectContaining(el))) ); } else { expect(convertToPercentileRankColumns(...input)).toEqual(expect.objectContaining(expected)); diff --git a/src/setup_node_env/harden/index.js b/src/setup_node_env/harden/index.js index 7c3c1528ec2d9..170821a7da21e 100644 --- a/src/setup_node_env/harden/index.js +++ b/src/setup_node_env/harden/index.js @@ -9,6 +9,7 @@ var ritm = require('require-in-the-middle'); var lodashPatch = require('./lodash_template'); var patchChildProcess = require('./child_process'); +var hardenPrototypes = require('./prototype'); // the performance cost of using require-in-the-middle is atm directly related to the number of // registered hooks (as require is patched once for EACH hook) @@ -39,3 +40,9 @@ new ritm.Hook( return module; } ); + +// Use of the `KBN_UNSAFE_DISABLE_PROTOTYPE_HARDENING` environment variable is discouraged, and should only be set to facilitate testing +// specific scenarios. This should never be set in production. +if (!process.env.KBN_UNSAFE_DISABLE_PROTOTYPE_HARDENING) { + hardenPrototypes(); +} diff --git a/src/setup_node_env/harden/prototype.js b/src/setup_node_env/harden/prototype.js new file mode 100644 index 0000000000000..664697af7a34b --- /dev/null +++ b/src/setup_node_env/harden/prototype.js @@ -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. + */ + +function hardenPrototypes() { + // @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal + // > The Object.seal() static method seals an object. + // > Sealing an object prevents extensions and makes existing properties non-configurable. + // > A sealed object has a fixed set of properties: new properties cannot be added, existing properties cannot be removed, + // > their enumerability and configurability cannot be changed, and its prototype cannot be re-assigned. + // > Values of existing properties can still be changed as long as they are writable. + // Object.freeze would take this one step further, and prevent the values of the properties from being changed as well. + // This is not currently feasible for Kibana, as this functionality is required for some of the libraries that we use, such as react-dom/server. + // While Object.seal() is not a silver bullet, it does provide a good balance between security and compatibility. + // The goal is to prevent a majority of prototype pollution vulnerabilities that can be exploited by an attacker. + + Object.seal(Object.prototype); + Object.seal(Number.prototype); + Object.seal(String.prototype); + Object.seal(Function.prototype); + + // corejs currently manipulates Array.prototype, so we cannot seal it. +} + +module.exports = hardenPrototypes; diff --git a/test/functional/page_objects/embedded_console.ts b/test/functional/page_objects/embedded_console.ts new file mode 100644 index 0000000000000..3f656969e79e2 --- /dev/null +++ b/test/functional/page_objects/embedded_console.ts @@ -0,0 +1,49 @@ +/* + * Copyright 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 { FtrProviderContext } from '../ftr_provider_context'; + +export function EmbeddedConsoleProvider(ctx: FtrProviderContext) { + const testSubjects = ctx.getService('testSubjects'); + + return { + async expectEmbeddedConsoleControlBarExists() { + await testSubjects.existOrFail('consoleEmbeddedSection'); + }, + async expectEmbeddedConsoleToBeOpen() { + await testSubjects.existOrFail('consoleEmbeddedBody'); + }, + async expectEmbeddedConsoleToBeClosed() { + await testSubjects.missingOrFail('consoleEmbeddedBody'); + }, + async clickEmbeddedConsoleControlBar() { + await testSubjects.click('consoleEmbeddedControlBar'); + }, + async expectEmbeddedConsoleNotebooksButtonExists() { + await testSubjects.existOrFail('consoleEmbeddedNotebooksButton'); + }, + async clickEmbeddedConsoleNotebooksButton() { + await testSubjects.click('consoleEmbeddedNotebooksButton'); + }, + async expectEmbeddedConsoleNotebooksToBeOpen() { + await testSubjects.existOrFail('consoleEmbeddedNotebooksContainer'); + }, + async expectEmbeddedConsoleNotebooksToBeClosed() { + await testSubjects.missingOrFail('consoleEmbeddedNotebooksContainer'); + }, + async expectEmbeddedConsoleNotebookListItemToBeAvailable(id: string) { + await testSubjects.existOrFail(`console-embedded-notebook-select-btn-${id}`); + }, + async clickEmbeddedConsoleNotebook(id: string) { + await testSubjects.click(`console-embedded-notebook-select-btn-${id}`); + }, + async expectEmbeddedConsoleNotebookToBeAvailable(id: string) { + await testSubjects.click(`console-embedded-notebook-select-btn-${id}`); + }, + }; +} diff --git a/test/functional/page_objects/index.ts b/test/functional/page_objects/index.ts index 34859cfe943d3..00947dfc33695 100644 --- a/test/functional/page_objects/index.ts +++ b/test/functional/page_objects/index.ts @@ -36,6 +36,8 @@ import { UnifiedSearchPageObject } from './unified_search_page'; import { UnifiedFieldListPageObject } from './unified_field_list'; import { FilesManagementPageObject } from './files_management'; import { AnnotationEditorPageObject } from './annotation_library_editor_page'; +import { SolutionNavigationProvider } from './solution_navigation'; +import { EmbeddedConsoleProvider } from './embedded_console'; export const pageObjects = { annotationEditor: AnnotationEditorPageObject, @@ -46,12 +48,14 @@ export const pageObjects = { dashboardControls: DashboardPageControls, dashboardLinks: DashboardPageLinks, discover: DiscoverPageObject, + embeddedConsole: EmbeddedConsoleProvider, error: ErrorPageObject, header: HeaderPageObject, home: HomePageObject, newsfeed: NewsfeedPageObject, settings: SettingsPageObject, share: SharePageObject, + solutionNavigation: SolutionNavigationProvider, legacyDataTableVis: LegacyDataTableVisPageObject, login: LoginPageObject, timelion: TimelionPageObject, @@ -69,3 +73,5 @@ export const pageObjects = { unifiedFieldList: UnifiedFieldListPageObject, filesManagement: FilesManagementPageObject, }; + +export { SolutionNavigationProvider } from './solution_navigation'; diff --git a/test/functional/page_objects/solution_navigation.ts b/test/functional/page_objects/solution_navigation.ts new file mode 100644 index 0000000000000..d42cad60641e9 --- /dev/null +++ b/test/functional/page_objects/solution_navigation.ts @@ -0,0 +1,338 @@ +/* + * Copyright 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 type { AppDeepLinkId } from '@kbn/core-chrome-browser'; + +import type { NavigationID as MlNavId } from '@kbn/default-nav-ml'; +import type { NavigationID as AlNavId } from '@kbn/default-nav-analytics'; +import type { NavigationID as MgmtNavId } from '@kbn/default-nav-management'; +import type { NavigationID as DevNavId } from '@kbn/default-nav-devtools'; + +// use this for nicer type suggestions, but allow any string anyway +type NavigationId = MlNavId | AlNavId | MgmtNavId | DevNavId | string; + +import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +const getSectionIdTestSubj = (sectionId: NavigationId) => `~nav-item-${sectionId}`; + +const TIMEOUT_CHECK = 3000; + +export function SolutionNavigationProvider(ctx: Pick) { + const testSubjects = ctx.getService('testSubjects'); + const browser = ctx.getService('browser'); + const retry = ctx.getService('retry'); + const log = ctx.getService('log'); + + async function getByVisibleText( + selector: string | (() => Promise), + text: string + ) { + const subjects = + typeof selector === 'string' ? await testSubjects.findAll(selector) : await selector(); + let found: WebElementWrapper | null = null; + for (const subject of subjects) { + const visibleText = await subject.getVisibleText(); + if (visibleText === text) { + found = subject; + break; + } + } + return found; + } + + return { + // check that chrome ui is in project/solution mode + async expectExists() { + await testSubjects.existOrFail('kibanaProjectHeader'); + }, + async clickLogo() { + await testSubjects.click('nav-header-logo'); + }, + // side nav related actions + sidenav: { + async expectLinkExists( + by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } + ) { + if ('deepLinkId' in by) { + await testSubjects.existOrFail(`~nav-item-deepLinkId-${by.deepLinkId}`, { + timeout: TIMEOUT_CHECK, + }); + } else if ('navId' in by) { + await testSubjects.existOrFail(`~nav-item-id-${by.navId}`, { timeout: TIMEOUT_CHECK }); + } else { + expect(await getByVisibleText('~nav-item', by.text)).not.be(null); + } + }, + async expectLinkMissing( + by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } + ) { + if ('deepLinkId' in by) { + await testSubjects.missingOrFail(`~nav-item-deepLinkId-${by.deepLinkId}`, { + timeout: TIMEOUT_CHECK, + }); + } else if ('navId' in by) { + await testSubjects.missingOrFail(`~nav-item-id-${by.navId}`, { timeout: TIMEOUT_CHECK }); + } else { + expect(await getByVisibleText('~nav-item', by.text)).be(null); + } + }, + async expectLinkActive( + by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } + ) { + await this.expectLinkExists(by); + if ('deepLinkId' in by) { + await testSubjects.existOrFail( + `~nav-item-deepLinkId-${by.deepLinkId} & ~nav-item-isActive`, + { timeout: TIMEOUT_CHECK } + ); + } else if ('navId' in by) { + await testSubjects.existOrFail(`~nav-item-id-${by.navId} & ~nav-item-isActive`, { + timeout: TIMEOUT_CHECK, + }); + } else { + await retry.try(async () => { + const link = await getByVisibleText('~nav-item', by.text); + expect(await link!.elementHasClass(`nav-item-isActive`)).to.be(true); + }); + } + }, + async clickLink(by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string }) { + await this.expectLinkExists(by); + if ('deepLinkId' in by) { + await testSubjects.click(`~nav-item-deepLinkId-${by.deepLinkId}`); + } else if ('navId' in by) { + await testSubjects.click(`~nav-item-id-${by.navId}`); + } else { + await retry.try(async () => { + const link = await getByVisibleText('~nav-item', by.text); + await link!.click(); + }); + } + }, + async findLink(by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string }) { + await this.expectLinkExists(by); + if ('deepLinkId' in by) { + return testSubjects.find(`~nav-item-deepLinkId-${by.deepLinkId}`); + } else if ('navId' in by) { + return testSubjects.find(`~nav-item-id-${by.navId}`); + } else { + return retry.try(async () => { + const link = await getByVisibleText('~nav-item', by.text); + return link; + }); + } + }, + async expectSectionExists(sectionId: NavigationId) { + log.debug('SolutionNavigation.sidenav.expectSectionExists', sectionId); + await testSubjects.existOrFail(getSectionIdTestSubj(sectionId), { timeout: TIMEOUT_CHECK }); + }, + async isSectionOpen(sectionId: NavigationId) { + await this.expectSectionExists(sectionId); + const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); + const isExpanded = await collapseBtn.getAttribute('aria-expanded'); + return isExpanded === 'true'; + }, + async expectSectionOpen(sectionId: NavigationId) { + log.debug('SolutionNavigation.sidenav.expectSectionOpen', sectionId); + await this.expectSectionExists(sectionId); + await retry.waitFor(`section ${sectionId} to be open`, async () => { + const isOpen = await this.isSectionOpen(sectionId); + return isOpen; + }); + }, + async expectSectionClosed(sectionId: NavigationId) { + await this.expectSectionExists(sectionId); + await retry.waitFor(`section ${sectionId} to be closed`, async () => { + const isOpen = await this.isSectionOpen(sectionId); + return !isOpen; + }); + }, + async openSection(sectionId: NavigationId) { + log.debug('SolutionNavigation.sidenav.openSection', sectionId); + await this.expectSectionExists(sectionId); + const isOpen = await this.isSectionOpen(sectionId); + if (isOpen) return; + const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`, TIMEOUT_CHECK); + await collapseBtn.click(); + await this.expectSectionOpen(sectionId); + }, + async closeSection(sectionId: NavigationId) { + await this.expectSectionExists(sectionId); + const isOpen = await this.isSectionOpen(sectionId); + if (!isOpen) return; + const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`, TIMEOUT_CHECK); + await collapseBtn.click(); + await this.expectSectionClosed(sectionId); + }, + async expectPanelExists(sectionId: NavigationId) { + log.debug('SolutionNavigation.sidenav.expectPanelExists', sectionId); + await testSubjects.existOrFail(`~sideNavPanel-id-${sectionId}`, { + timeout: TIMEOUT_CHECK, + }); + }, + async isPanelOpen(sectionId: NavigationId) { + try { + const panel = await testSubjects.find(`~sideNavPanel-id-${sectionId}`, TIMEOUT_CHECK); + return !!panel; + } catch (err) { + return false; + } + }, + async openPanel(sectionId: NavigationId) { + log.debug('SolutionNavigation.sidenav.openPanel', sectionId); + + const isOpen = await this.isPanelOpen(sectionId); + if (isOpen) return; + + const panelOpenerBtn = await testSubjects.find( + `~panelOpener-id-${sectionId}`, + TIMEOUT_CHECK + ); + + await panelOpenerBtn.click(); + }, + async isCollapsed() { + const collapseNavBtn = await testSubjects.find('euiCollapsibleNavButton', TIMEOUT_CHECK); + return (await collapseNavBtn.getAttribute('aria-expanded')) === 'false'; + }, + async isExpanded() { + return !(await this.isCollapsed()); + }, + /** + * Toggles collapsed state of sidenav + */ + async toggle(collapsed?: boolean) { + const currentlyCollapsed = await this.isCollapsed(); + const shouldBeCollapsed = collapsed ?? !currentlyCollapsed; + + if (currentlyCollapsed !== shouldBeCollapsed) { + log.debug( + 'SolutionNavigation.sidenav.toggle', + shouldBeCollapsed ? 'Collapsing' : 'Expanding' + ); + + const collapseNavBtn = await testSubjects.find('euiCollapsibleNavButton', TIMEOUT_CHECK); + await collapseNavBtn.click(); + } + }, + }, + breadcrumbs: { + async expectExists() { + await testSubjects.existOrFail('breadcrumbs', { timeout: TIMEOUT_CHECK }); + }, + async clickBreadcrumb(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + if ('deepLinkId' in by) { + await testSubjects.click(`~breadcrumb-deepLinkId-${by.deepLinkId}`); + } else { + await (await getByVisibleText('~breadcrumb', by.text))?.click(); + } + }, + getBreadcrumb(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + if ('deepLinkId' in by) { + return testSubjects.find(`~breadcrumb-deepLinkId-${by.deepLinkId}`, TIMEOUT_CHECK); + } else { + return getByVisibleText('~breadcrumb', by.text); + } + }, + async expectBreadcrumbExists(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + log.debug('SolutionNavigation.breadcrumbs.expectBreadcrumbExists', JSON.stringify(by)); + if ('deepLinkId' in by) { + await testSubjects.existOrFail(`~breadcrumb-deepLinkId-${by.deepLinkId}`, { + timeout: TIMEOUT_CHECK, + }); + } else { + await retry.try(async () => { + expect(await getByVisibleText('~breadcrumb', by.text)).not.be(null); + }); + } + }, + async expectBreadcrumbMissing(by: { deepLinkId: AppDeepLinkId } | { text: string }) { + if ('deepLinkId' in by) { + await testSubjects.missingOrFail(`~breadcrumb-deepLinkId-${by.deepLinkId}`, { + timeout: TIMEOUT_CHECK, + }); + } else { + await retry.try(async () => { + expect(await getByVisibleText('~breadcrumb', by.text)).be(null); + }); + } + }, + async expectBreadcrumbTexts(expectedBreadcrumbTexts: string[]) { + log.debug( + 'SolutionNavigation.breadcrumbs.expectBreadcrumbTexts', + JSON.stringify(expectedBreadcrumbTexts) + ); + await retry.try(async () => { + const breadcrumbsContainer = await testSubjects.find('breadcrumbs', TIMEOUT_CHECK); + const breadcrumbs = await breadcrumbsContainer.findAllByTestSubject('~breadcrumb'); + breadcrumbs.shift(); // remove home + expect(expectedBreadcrumbTexts.length).to.eql(breadcrumbs.length); + const texts = await Promise.all(breadcrumbs.map((b) => b.getVisibleText())); + expect(expectedBreadcrumbTexts).to.eql(texts); + }); + }, + }, + recent: { + async expectExists() { + await testSubjects.existOrFail('nav-item-recentlyAccessed', { timeout: TIMEOUT_CHECK }); + }, + async expectHidden() { + await testSubjects.missingOrFail('nav-item-recentlyAccessed', { timeout: TIMEOUT_CHECK }); + }, + async expectLinkExists(text: string) { + await this.expectExists(); + let foundLink: WebElementWrapper | null = null; + await retry.try(async () => { + foundLink = await getByVisibleText( + async () => + ( + await testSubjects.find('nav-item-recentlyAccessed', TIMEOUT_CHECK) + ).findAllByTagName('a'), + text + ); + expect(!!foundLink).to.be(true); + }); + + return foundLink!; + }, + async clickLink(text: string) { + const link = await this.expectLinkExists(text); + await link!.click(); + }, + }, + + // helper to assert that the page did not reload + async createNoPageReloadCheck() { + const trackReloadTs = Date.now(); + await browser.execute( + ({ ts }) => { + // @ts-ignore + window.__testTrackReload__ = ts; + }, + { + ts: trackReloadTs, + } + ); + + return async () => { + const noReload = await browser.execute( + ({ ts }) => { + // @ts-ignore + return window.__testTrackReload__ && window.__testTrackReload__ === ts; + }, + { + ts: trackReloadTs, + } + ); + expect(noReload).to.be(true); + }; + }, + }; +} diff --git a/test/functional/services/filter_bar.ts b/test/functional/services/filter_bar.ts index be4abf4e0daf2..c508410739db0 100644 --- a/test/functional/services/filter_bar.ts +++ b/test/functional/services/filter_bar.ts @@ -133,10 +133,11 @@ export class FilterBarService extends FtrService { * @param key field name */ public async removeFilter(key: string): Promise { - await this.retry.try(async () => { + await this.retry.waitFor('filter pill context menu is open', async () => { await this.testSubjects.click(`~filter & ~filter-key-${key}`); - await this.testSubjects.click(`deleteFilter`); + return await this.testSubjects.exists('deleteFilter'); }); + await this.testSubjects.click(`deleteFilter`); await this.header.awaitGlobalLoadingIndicatorHidden(); } diff --git a/test/harden/child_process.js b/test/harden/child_process.js index 029b1a038fcbf..2f33a1b0172dc 100644 --- a/test/harden/child_process.js +++ b/test/harden/child_process.js @@ -6,6 +6,9 @@ * Side Public License, v 1. */ +// We must disable prototype hardening to test the pollution +process.env.KBN_UNSAFE_DISABLE_PROTOTYPE_HARDENING = 'true'; + require('../../src/setup_node_env'); const cp = require('child_process'); diff --git a/test/harden/lodash_template.js b/test/harden/lodash_template.js index 49cf7351972e8..c6dc240ffbb63 100644 --- a/test/harden/lodash_template.js +++ b/test/harden/lodash_template.js @@ -6,6 +6,9 @@ * Side Public License, v 1. */ +// We must disable prototype hardening to test the pollution +process.env.KBN_UNSAFE_DISABLE_PROTOTYPE_HARDENING = 'true'; + require('../../src/setup_node_env'); const _ = require('lodash'); // eslint-disable-next-line no-restricted-modules diff --git a/test/harden/prototype.js b/test/harden/prototype.js new file mode 100644 index 0000000000000..dcd5386a17af3 --- /dev/null +++ b/test/harden/prototype.js @@ -0,0 +1,205 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../../src/setup_node_env'); + +const test = require('tape'); + +test('Object.prototype', (t) => { + t.test('Prevents new properties from being added to the prototype', (t) => { + Object.prototype.test = 'whoops'; // eslint-disable-line no-extend-native + t.equal({}.test, undefined); + t.end(); + }); + + t.test('Permits overriding Object.prototype.toString', (t) => { + let originalToString; + t.test('setup', (t) => { + originalToString = Object.prototype.toString; + t.end(); + }); + + t.test('test', (t) => { + // Assert native toString behavior + t.equal({}.toString(), '[object Object]'); + + const { + writable: originalWritable, + enumerable: originalEnumerable, + configurable: originalConfigurable, + } = Object.getOwnPropertyDescriptor(Object.prototype, 'toString'); + + // eslint-disable-next-line no-extend-native + Object.prototype.toString = function toString() { + return 'my new toString function'; + }; + t.equal({}.toString(), 'my new toString function'); + + const toStringDescriptor = Object.getOwnPropertyDescriptor(Object.prototype, 'toString'); + + // Overwriting a property should not change its descriptor. + t.equal(toStringDescriptor.writable, originalWritable); + t.equal(toStringDescriptor.enumerable, originalEnumerable); + t.equal(toStringDescriptor.configurable, originalConfigurable); + + t.end(); + }); + + t.test('teardown', (t) => { + // eslint-disable-next-line no-extend-native + Object.prototype.toString = originalToString; + t.end(); + }); + }); +}); + +test('Number.prototype', (t) => { + t.test('Prevents new properties from being added to the prototype', (t) => { + Number.prototype.test = 'whoops'; // eslint-disable-line no-extend-native + t.equal((12).test, undefined); + t.end(); + }); + + t.test('Permits overriding Number.prototype.toString', (t) => { + let originalToString; + t.test('setup', (t) => { + originalToString = Number.prototype.toString; + t.end(); + }); + + t.test('test', (t) => { + // Assert native toString behavior + t.equal((1).toString(), '1'); + + const { + writable: originalWritable, + enumerable: originalEnumerable, + configurable: originalConfigurable, + } = Object.getOwnPropertyDescriptor(Number.prototype, 'toString'); + + // eslint-disable-next-line no-extend-native + Number.prototype.toString = function toString() { + return 'my new Number.toString function'; + }; + t.equal((12).toString(), 'my new Number.toString function'); + + const toStringDescriptor = Object.getOwnPropertyDescriptor(Number.prototype, 'toString'); + + // Overwriting a property should not change its descriptor. + t.equal(toStringDescriptor.writable, originalWritable); + t.equal(toStringDescriptor.enumerable, originalEnumerable); + t.equal(toStringDescriptor.configurable, originalConfigurable); + + t.end(); + }); + + t.test('teardown', (t) => { + // eslint-disable-next-line no-extend-native + Number.prototype.toString = originalToString; + t.end(); + }); + }); +}); + +test('String.prototype', (t) => { + t.test('Prevents new properties from being added to the prototype', (t) => { + String.prototype.test = 'whoops'; // eslint-disable-line no-extend-native + t.equal('hello'.test, undefined); + t.end(); + }); + + t.test('Permits overriding String.prototype.toString', (t) => { + let originalToString; + t.test('setup', (t) => { + originalToString = String.prototype.toString; + t.end(); + }); + + t.test('test', (t) => { + // Assert native toString behavior + t.equal((1).toString(), '1'); + + const { + writable: originalWritable, + enumerable: originalEnumerable, + configurable: originalConfigurable, + } = Object.getOwnPropertyDescriptor(String.prototype, 'toString'); + + // eslint-disable-next-line no-extend-native + String.prototype.toString = function toString() { + return 'my new String.toString function'; + }; + t.equal('test'.toString(), 'my new String.toString function'); + + const toStringDescriptor = Object.getOwnPropertyDescriptor(String.prototype, 'toString'); + + // Overwriting a property should not change its descriptor. + t.equal(toStringDescriptor.writable, originalWritable); + t.equal(toStringDescriptor.enumerable, originalEnumerable); + t.equal(toStringDescriptor.configurable, originalConfigurable); + + t.end(); + }); + + t.test('teardown', (t) => { + // eslint-disable-next-line no-extend-native + String.prototype.toString = originalToString; + t.end(); + }); + }); +}); + +test('Function.prototype', (t) => { + t.test('Prevents new properties from being added to the prototype', (t) => { + Function.prototype.test = 'whoops'; // eslint-disable-line no-extend-native + const fn = function testFn() {}; + t.equal(fn.test, undefined); + t.end(); + }); + + t.test('Permits overriding Function.prototype.toString', (t) => { + let originalToString; + t.test('setup', (t) => { + originalToString = Function.prototype.toString; + t.end(); + }); + + t.test('test', (t) => { + // Assert native toString behavior + const fn = function testFn() {}; + t.equal(fn.toString(), 'function testFn() {}'); + + const { + writable: originalWritable, + enumerable: originalEnumerable, + configurable: originalConfigurable, + } = Object.getOwnPropertyDescriptor(Function.prototype, 'toString'); + + // eslint-disable-next-line no-extend-native + Function.prototype.toString = function toString() { + return 'my new Function.toString function'; + }; + t.equal(fn.toString(), 'my new Function.toString function'); + + const toStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, 'toString'); + + // Overwriting a property should not change its descriptor. + t.equal(toStringDescriptor.writable, originalWritable); + t.equal(toStringDescriptor.enumerable, originalEnumerable); + t.equal(toStringDescriptor.configurable, originalConfigurable); + + t.end(); + }); + + t.test('teardown', (t) => { + // eslint-disable-next-line no-extend-native + Function.prototype.toString = originalToString; + t.end(); + }); + }); +}); diff --git a/test/plugin_functional/config.ts b/test/plugin_functional/config.ts index 7b967b8591bf4..5ed34a69bae01 100644 --- a/test/plugin_functional/config.ts +++ b/test/plugin_functional/config.ts @@ -19,6 +19,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('./test_suites/telemetry'), require.resolve('./test_suites/core'), require.resolve('./test_suites/custom_visualizations'), + require.resolve('./test_suites/hardening'), require.resolve('./test_suites/panel_actions'), require.resolve('./test_suites/core_plugins'), require.resolve('./test_suites/management'), @@ -26,6 +27,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('./test_suites/data_plugin'), require.resolve('./test_suites/saved_objects_management'), require.resolve('./test_suites/saved_objects_hidden_type'), + require.resolve('./test_suites/shared_ux'), ], services: { ...functionalConfig.get('services'), diff --git a/test/plugin_functional/plugins/eui_provider_dev_warning/kibana.jsonc b/test/plugin_functional/plugins/eui_provider_dev_warning/kibana.jsonc new file mode 100644 index 0000000000000..970c25a20d596 --- /dev/null +++ b/test/plugin_functional/plugins/eui_provider_dev_warning/kibana.jsonc @@ -0,0 +1,13 @@ +{ + "type": "plugin", + "id": "@kbn/eui-provider-dev-warning", + "owner": "@elastic/appex-sharedux", + "plugin": { + "id": "euiProviderDevWarning", + "server": false, + "browser": true, + "configPath": [ + "eui_provider_dev_warning" + ] + } +} diff --git a/test/plugin_functional/plugins/eui_provider_dev_warning/package.json b/test/plugin_functional/plugins/eui_provider_dev_warning/package.json new file mode 100644 index 0000000000000..97def81d81579 --- /dev/null +++ b/test/plugin_functional/plugins/eui_provider_dev_warning/package.json @@ -0,0 +1,14 @@ +{ + "name": "@kbn/eui-provider-dev-warning", + "version": "1.0.0", + "main": "target/test/plugin_functional/plugins/eui_provider_dev_warning", + "kibana": { + "version": "kibana", + "templateVersion": "1.0.0" + }, + "license": "SSPL-1.0 OR Elastic License 2.0", + "scripts": { + "kbn": "node ../../../../scripts/kbn.js", + "build": "rm -rf './target' && ../../../../node_modules/.bin/tsc" + } +} diff --git a/test/plugin_functional/plugins/eui_provider_dev_warning/public/application.tsx b/test/plugin_functional/plugins/eui_provider_dev_warning/public/application.tsx new file mode 100644 index 0000000000000..64541566c26a5 --- /dev/null +++ b/test/plugin_functional/plugins/eui_provider_dev_warning/public/application.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { EuiPageTemplate, EuiTitle, EuiText } from '@elastic/eui'; +import ReactDOM from 'react-dom'; +import { AppMountParameters, CoreStart } from '@kbn/core/public'; + +export const renderApp = (_core: CoreStart, { element }: AppMountParameters) => { + ReactDOM.render( + + + +

EuiProvider is missing

+
+
+ + +

Goal of this page

+
+ +

+ The goal of this page is to create a UI that attempts to render EUI React components + without wrapping the rendering tree in EuiProvider. +

+
+
+
, + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/test/plugin_functional/plugins/eui_provider_dev_warning/public/index.ts b/test/plugin_functional/plugins/eui_provider_dev_warning/public/index.ts new file mode 100644 index 0000000000000..8241ab91ba378 --- /dev/null +++ b/test/plugin_functional/plugins/eui_provider_dev_warning/public/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { EuiProviderDevWarningPlugin } from './plugin'; + +export function plugin() { + return new EuiProviderDevWarningPlugin(); +} diff --git a/test/plugin_functional/plugins/eui_provider_dev_warning/public/plugin.ts b/test/plugin_functional/plugins/eui_provider_dev_warning/public/plugin.ts new file mode 100644 index 0000000000000..a524ff6c2095c --- /dev/null +++ b/test/plugin_functional/plugins/eui_provider_dev_warning/public/plugin.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { AppMountParameters, CoreSetup, Plugin } from '@kbn/core/public'; + +export class EuiProviderDevWarningPlugin + implements Plugin +{ + public setup(core: CoreSetup) { + core.application.register({ + id: 'euiProviderDevWarning', + title: 'EUI Provider Dev Warning', + async mount(params: AppMountParameters) { + const { renderApp } = await import('./application'); + const [coreStart] = await core.getStartServices(); + coreStart.chrome.docTitle.change('EuiProvider test'); + return renderApp(coreStart, params); + }, + }); + + // Return methods that should be available to other plugins + return {}; + } + + public start() {} + public stop() {} +} + +export type EuiProviderDevWarningPluginSetup = ReturnType; +export type EuiProviderDevWarningPluginStart = ReturnType; diff --git a/test/plugin_functional/plugins/eui_provider_dev_warning/tsconfig.json b/test/plugin_functional/plugins/eui_provider_dev_warning/tsconfig.json new file mode 100644 index 0000000000000..db7cf2bb2089d --- /dev/null +++ b/test/plugin_functional/plugins/eui_provider_dev_warning/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "index.ts", + "public/**/*.ts", + "public/**/*.tsx", + "../../../../typings/**/*" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/core" + ] +} diff --git a/test/plugin_functional/plugins/hardening/kibana.jsonc b/test/plugin_functional/plugins/hardening/kibana.jsonc new file mode 100644 index 0000000000000..c5680af0dd35e --- /dev/null +++ b/test/plugin_functional/plugins/hardening/kibana.jsonc @@ -0,0 +1,13 @@ +{ + "type": "plugin", + "id": "@kbn/hardening-plugin", + "owner": "@elastic/kibana-security", + "plugin": { + "id": "hardeningPlugin", + "server": true, + "browser": false, + "configPath": [ + "hardening_plugin" + ] + } +} diff --git a/test/plugin_functional/plugins/hardening/package.json b/test/plugin_functional/plugins/hardening/package.json new file mode 100644 index 0000000000000..c33feeb7a4f52 --- /dev/null +++ b/test/plugin_functional/plugins/hardening/package.json @@ -0,0 +1,14 @@ +{ + "name": "@kbn/hardening-plugin", + "version": "1.0.0", + "main": "target/test/plugin_functional/plugins/hardening", + "kibana": { + "version": "kibana", + "templateVersion": "1.0.0" + }, + "license": "SSPL-1.0 OR Elastic License 2.0", + "scripts": { + "kbn": "node ../../../../scripts/kbn.js", + "build": "rm -rf './target' && ../../../../node_modules/.bin/tsc" + } +} \ No newline at end of file diff --git a/test/plugin_functional/plugins/hardening/server/index.ts b/test/plugin_functional/plugins/hardening/server/index.ts new file mode 100644 index 0000000000000..cafadea796f5e --- /dev/null +++ b/test/plugin_functional/plugins/hardening/server/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { HardeningPlugin } from './plugin'; + +export const plugin = async () => new HardeningPlugin(); diff --git a/test/plugin_functional/plugins/hardening/server/plugin.ts b/test/plugin_functional/plugins/hardening/server/plugin.ts new file mode 100644 index 0000000000000..451f4e233169f --- /dev/null +++ b/test/plugin_functional/plugins/hardening/server/plugin.ts @@ -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 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 { Plugin, CoreSetup } from '@kbn/core/server'; + +export class HardeningPlugin implements Plugin { + public setup(core: CoreSetup, deps: {}) { + core.http.createRouter().get( + { + path: '/api/hardening/_pollute_prototypes', + validate: false, + }, + async (context, request, response) => { + const result: Record; error?: string }> = { + object: {}, + number: {}, + string: {}, + fn: {}, + array: {}, + }; + // Attempt to pollute Object.prototype + try { + (({}) as any).__proto__.polluted = true; + } catch (e) { + result.object.error = e.message; + } finally { + result.object.prototype = { ...Object.keys(Object.getPrototypeOf({})) }; + } + + // Attempt to pollute String.prototype + try { + ('asdf' as any).__proto__.polluted = true; + } catch (e) { + result.string.error = e.message; + } finally { + result.string.prototype = { ...Object.keys(Object.getPrototypeOf('asf')) }; + } + + // Attempt to pollute Number.prototype + try { + (12 as any).__proto__.polluted = true; + } catch (e) { + result.number.error = e.message; + } finally { + result.number.prototype = { ...Object.keys(Object.getPrototypeOf(12)) }; + } + + // Attempt to pollute Function.prototype + const fn = function fn() {}; + try { + (fn as any).__proto__.polluted = true; + } catch (e) { + result.fn.error = e.message; + } finally { + result.fn.prototype = { ...Object.keys(Object.getPrototypeOf(fn)) }; + } + + // Attempt to pollute Array.prototype + try { + ([] as any).__proto__.polluted = true; + } catch (e) { + result.array.error = e.message; + } finally { + result.array.prototype = { ...Object.keys(Object.getPrototypeOf([])) }; + } + + return response.ok({ body: result }); + } + ); + } + + public start() {} + public stop() {} +} diff --git a/test/plugin_functional/plugins/hardening/tsconfig.json b/test/plugin_functional/plugins/hardening/tsconfig.json new file mode 100644 index 0000000000000..bf146797a42ee --- /dev/null +++ b/test/plugin_functional/plugins/hardening/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "index.ts", + "server/**/*.ts", + "../../../../typings/**/*", + ], + "exclude": [ + "target/**/*", + ], + "kbn_references": [ + "@kbn/core" + ] +} diff --git a/test/plugin_functional/snapshots/baseline/hardening/prototype.json b/test/plugin_functional/snapshots/baseline/hardening/prototype.json new file mode 100644 index 0000000000000..4e3a9d8219492 --- /dev/null +++ b/test/plugin_functional/snapshots/baseline/hardening/prototype.json @@ -0,0 +1 @@ +{"object":{"error":"Cannot add property polluted, object is not extensible","prototype":{}},"number":{"error":"Cannot add property polluted, object is not extensible","prototype":{}},"string":{"error":"Cannot add property polluted, object is not extensible","prototype":{}},"fn":{"error":"Cannot add property polluted, object is not extensible","prototype":{}},"array":{"prototype":{"0":"polluted"}}} \ No newline at end of file diff --git a/test/plugin_functional/test_suites/hardening/index.ts b/test/plugin_functional/test_suites/hardening/index.ts new file mode 100644 index 0000000000000..b4eedb16495fe --- /dev/null +++ b/test/plugin_functional/test_suites/hardening/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginFunctionalProviderContext } from '../../services'; + +export default function ({ loadTestFile }: PluginFunctionalProviderContext) { + describe('hardening', function () { + loadTestFile(require.resolve('./prototype')); + }); +} diff --git a/test/plugin_functional/test_suites/hardening/prototype.ts b/test/plugin_functional/test_suites/hardening/prototype.ts new file mode 100644 index 0000000000000..823667a009544 --- /dev/null +++ b/test/plugin_functional/test_suites/hardening/prototype.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 type { PluginFunctionalProviderContext } from '../../services'; + +export default function ({ getService }: PluginFunctionalProviderContext) { + const supertest = getService('supertest'); + const snapshots = getService('snapshots'); + + describe('prototype', function () { + it('does not allow polluting most prototypes', async () => { + const response = await supertest + .get('/api/hardening/_pollute_prototypes') + .set('kbn-xsrf', 'true') + .expect(200); + + await snapshots.compareAgainstBaseline('hardening/prototype', response.body); + }); + }); +} diff --git a/test/plugin_functional/test_suites/shared_ux/eui_provider.ts b/test/plugin_functional/test_suites/shared_ux/eui_provider.ts new file mode 100644 index 0000000000000..b378939741f34 --- /dev/null +++ b/test/plugin_functional/test_suites/shared_ux/eui_provider.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 expect from '@kbn/expect'; +import { PluginFunctionalProviderContext } from '../../services'; + +export default function ({ getPageObjects, getService }: PluginFunctionalProviderContext) { + const PageObjects = getPageObjects(['common', 'header']); + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + + describe('EUI Provider Dev Warning', () => { + it('shows error toast to developer', async () => { + const pageTitle = 'EuiProvider test - Elastic'; + + await PageObjects.common.navigateToApp('euiProviderDevWarning'); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await browser.getTitle()).eql(pageTitle); + await testSubjects.existOrFail('core-chrome-euiDevProviderWarning-toast'); + + // check that the error has been detected and stored in session storage + const euiProviderWarning = await browser.getSessionStorageItem('dev.euiProviderWarning'); + const { + message: errorMessage, + stack: errorStack, + pageHref: errorPageHref, + pageTitle: errorPageTitle, + } = JSON.parse(euiProviderWarning!); + expect(errorMessage).to.not.be.empty(); + expect(errorStack).to.not.be.empty(); + expect(errorPageHref).to.not.be.empty(); + expect(errorPageTitle).to.be(pageTitle); + }); + + after(async () => { + // clean up to ensure test suite will pass + await browser.removeSessionStorageItem('dev.euiProviderWarning'); + }); + }); +} diff --git a/test/plugin_functional/test_suites/shared_ux/index.ts b/test/plugin_functional/test_suites/shared_ux/index.ts new file mode 100644 index 0000000000000..a42a855ea4b3f --- /dev/null +++ b/test/plugin_functional/test_suites/shared_ux/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginFunctionalProviderContext } from '../../services'; + +export default function ({ loadTestFile }: PluginFunctionalProviderContext) { + describe('SharedUX', () => { + loadTestFile(require.resolve('./eui_provider')); + }); +} diff --git a/test/tsconfig.json b/test/tsconfig.json index 0f120b831abe7..b03067c0440ae 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -73,5 +73,10 @@ "@kbn/monaco", "@kbn/search-types", "@kbn/console-plugin", + "@kbn/core-chrome-browser", + "@kbn/default-nav-ml", + "@kbn/default-nav-analytics", + "@kbn/default-nav-management", + "@kbn/default-nav-devtools", ] } diff --git a/tsconfig.base.json b/tsconfig.base.json index 8eb24fb127bb8..d6b0733743929 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -130,6 +130,8 @@ "@kbn/cases-components/*": ["packages/kbn-cases-components/*"], "@kbn/cases-plugin": ["x-pack/plugins/cases"], "@kbn/cases-plugin/*": ["x-pack/plugins/cases/*"], + "@kbn/cbor": ["packages/kbn-cbor"], + "@kbn/cbor/*": ["packages/kbn-cbor/*"], "@kbn/cell-actions": ["packages/kbn-cell-actions"], "@kbn/cell-actions/*": ["packages/kbn-cell-actions/*"], "@kbn/chart-expressions-common": ["src/plugins/chart_expressions/common"], @@ -140,6 +142,8 @@ "@kbn/charts-plugin/*": ["src/plugins/charts/*"], "@kbn/check-mappings-update-cli": ["packages/kbn-check-mappings-update-cli"], "@kbn/check-mappings-update-cli/*": ["packages/kbn-check-mappings-update-cli/*"], + "@kbn/check-prod-native-modules-cli": ["packages/kbn-check-prod-native-modules-cli"], + "@kbn/check-prod-native-modules-cli/*": ["packages/kbn-check-prod-native-modules-cli/*"], "@kbn/ci-stats-core": ["packages/kbn-ci-stats-core"], "@kbn/ci-stats-core/*": ["packages/kbn-ci-stats-core/*"], "@kbn/ci-stats-performance-metrics": ["packages/kbn-ci-stats-performance-metrics"], @@ -840,6 +844,8 @@ "@kbn/esql-validation-autocomplete/*": ["packages/kbn-esql-validation-autocomplete/*"], "@kbn/esql-validation-example-plugin": ["examples/esql_validation_example"], "@kbn/esql-validation-example-plugin/*": ["examples/esql_validation_example/*"], + "@kbn/eui-provider-dev-warning": ["test/plugin_functional/plugins/eui_provider_dev_warning"], + "@kbn/eui-provider-dev-warning/*": ["test/plugin_functional/plugins/eui_provider_dev_warning/*"], "@kbn/event-annotation-common": ["packages/kbn-event-annotation-common"], "@kbn/event-annotation-common/*": ["packages/kbn-event-annotation-common/*"], "@kbn/event-annotation-components": ["packages/kbn-event-annotation-components"], @@ -976,6 +982,8 @@ "@kbn/handlebars/*": ["packages/kbn-handlebars/*"], "@kbn/hapi-mocks": ["packages/kbn-hapi-mocks"], "@kbn/hapi-mocks/*": ["packages/kbn-hapi-mocks/*"], + "@kbn/hardening-plugin": ["test/plugin_functional/plugins/hardening"], + "@kbn/hardening-plugin/*": ["test/plugin_functional/plugins/hardening/*"], "@kbn/health-gateway-server": ["packages/kbn-health-gateway-server"], "@kbn/health-gateway-server/*": ["packages/kbn-health-gateway-server/*"], "@kbn/hello-world-plugin": ["examples/hello_world"], @@ -1510,6 +1518,8 @@ "@kbn/security-plugin-types-server/*": ["x-pack/packages/security/plugin_types_server/*"], "@kbn/security-role-management-model": ["x-pack/packages/security/role_management_model"], "@kbn/security-role-management-model/*": ["x-pack/packages/security/role_management_model/*"], + "@kbn/security-solution-common": ["x-pack/packages/security-solution/common"], + "@kbn/security-solution-common/*": ["x-pack/packages/security-solution/common/*"], "@kbn/security-solution-distribution-bar": ["x-pack/packages/security-solution/distribution_bar"], "@kbn/security-solution-distribution-bar/*": ["x-pack/packages/security-solution/distribution_bar/*"], "@kbn/security-solution-ess": ["x-pack/plugins/security_solution_ess"], diff --git a/typings/borc.d.ts b/typings/borc.d.ts new file mode 100644 index 0000000000000..7c194a7ee39e8 --- /dev/null +++ b/typings/borc.d.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +declare module 'borc'; diff --git a/x-pack/packages/kbn-cloud-security-posture-common/constants.ts b/x-pack/packages/kbn-cloud-security-posture-common/constants.ts new file mode 100644 index 0000000000000..935e747b20fa8 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture-common/constants.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. + */ +export const KSPM_POLICY_TEMPLATE = 'kspm'; +export const CSPM_POLICY_TEMPLATE = 'cspm'; +export const CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN = + 'logs-cloud_security_posture.findings_latest-default'; +export const CDR_LATEST_THIRD_PARTY_MISCONFIGURATIONS_INDEX_PATTERN = + 'logs-*_latest_misconfigurations_cdr'; +export const CDR_MISCONFIGURATIONS_INDEX_PATTERN = `${CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN},${CDR_LATEST_THIRD_PARTY_MISCONFIGURATIONS_INDEX_PATTERN}`; +export const LATEST_FINDINGS_RETENTION_POLICY = '26h'; +export const MAX_FINDINGS_TO_LOAD = 500; +export const CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH = + '/internal/cloud_security_posture/rules/_get_states'; +export const CSP_GET_BENCHMARK_RULES_STATE_API_CURRENT_VERSION = '1'; +export const STATUS_ROUTE_PATH = '/internal/cloud_security_posture/status'; +export const STATUS_API_CURRENT_VERSION = '1'; diff --git a/x-pack/packages/kbn-cloud-security-posture-common/index.ts b/x-pack/packages/kbn-cloud-security-posture-common/index.ts new file mode 100644 index 0000000000000..f4d7ac2e34dd9 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture-common/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Careful of exporting anything from this file as any file(s) you export here will cause your page bundle size to increase. +// If you're using functions/types/etc... internally or within integration tests it's best to import directly from their paths +// than expose the functions/types/etc... here. You should _only_ expose functions/types/etc... that need to be shared with other plugins here. + +export type { + CspStatusCode, + IndexStatus, + IndexDetails, + BaseCspSetupBothPolicy, + BaseCspSetupStatus, + CspSetupStatus, + CspFinding, +} from './types'; +export * from './constants'; +export type { CspBenchmarkRuleMetadata, CspBenchmarkRulesStates } from './schema/rules'; diff --git a/x-pack/packages/kbn-cloud-security-posture-common/schema/index.ts b/x-pack/packages/kbn-cloud-security-posture-common/schema/index.ts new file mode 100644 index 0000000000000..981633d2a3fad --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture-common/schema/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { ruleStateAttributes, cspBenchmarkRuleMetadataSchema, rulesStates } from './rules'; diff --git a/x-pack/packages/kbn-cloud-security-posture-common/schema/rules.ts b/x-pack/packages/kbn-cloud-security-posture-common/schema/rules.ts new file mode 100644 index 0000000000000..67bb37e4e1702 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture-common/schema/rules.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { TypeOf, schema } from '@kbn/config-schema'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../constants'; + +export type CspBenchmarkRuleMetadata = TypeOf; + +export const cspBenchmarkRuleMetadataSchema = schema.object({ + audit: schema.string(), + benchmark: schema.object({ + name: schema.string(), + posture_type: schema.maybe( + schema.oneOf([schema.literal(CSPM_POLICY_TEMPLATE), schema.literal(KSPM_POLICY_TEMPLATE)]) + ), + id: schema.string(), + version: schema.string(), + rule_number: schema.maybe(schema.string()), + }), + default_value: schema.maybe(schema.string()), + description: schema.string(), + id: schema.string(), + impact: schema.maybe(schema.string()), + name: schema.string(), + profile_applicability: schema.string(), + rationale: schema.string(), + references: schema.maybe(schema.string()), + rego_rule_id: schema.string(), + remediation: schema.string(), + section: schema.string(), + tags: schema.arrayOf(schema.string()), + version: schema.string(), +}); + +export const ruleStateAttributes = schema.object({ + muted: schema.boolean(), + benchmark_id: schema.string(), + benchmark_version: schema.string(), + rule_number: schema.string(), + rule_id: schema.string(), +}); + +export const rulesStates = schema.recordOf(schema.string(), ruleStateAttributes); + +export type CspBenchmarkRulesStates = TypeOf; diff --git a/x-pack/packages/kbn-cloud-security-posture-common/tsconfig.json b/x-pack/packages/kbn-cloud-security-posture-common/tsconfig.json new file mode 100644 index 0000000000000..1eb47d23c1542 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture-common/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/config-schema", + ] +} diff --git a/x-pack/plugins/cloud_security_posture/common/schemas/csp_finding.ts b/x-pack/packages/kbn-cloud-security-posture-common/types.ts similarity index 54% rename from x-pack/plugins/cloud_security_posture/common/schemas/csp_finding.ts rename to x-pack/packages/kbn-cloud-security-posture-common/types.ts index 7ac4e79393f01..7a9d5fee09c8f 100644 --- a/x-pack/plugins/cloud_security_posture/common/schemas/csp_finding.ts +++ b/x-pack/packages/kbn-cloud-security-posture-common/types.ts @@ -4,10 +4,46 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -// TODO: this needs to be defined in a versioned schema import type { EcsDataStream, EcsEvent } from '@elastic/ecs'; -import { CspBenchmarkRuleMetadata } from '../types/latest'; +import type { CspBenchmarkRuleMetadata } from './schema/rules'; + +export type CspStatusCode = + | 'indexed' // latest findings index exists and has results + | 'indexing' // index timeout was not surpassed since installation, assumes data is being indexed + | 'unprivileged' // user lacks privileges for the latest findings index + | 'index-timeout' // index timeout was surpassed since installation + | 'not-deployed' // no healthy agents were deployed + | 'not-installed' // number of installed csp integrations is 0; + | 'waiting_for_results'; // have healthy agents but no findings at all, assumes data is being indexed for the 1st time + +export type IndexStatus = + | 'not-empty' // Index contains documents + | 'empty' // Index doesn't contain documents (or doesn't exist) + | 'unprivileged'; // User doesn't have access to query the index + +export interface IndexDetails { + index: string; + status: IndexStatus; +} + +export interface BaseCspSetupBothPolicy { + status: CspStatusCode; + installedPackagePolicies: number; + healthyAgents: number; +} + +export interface BaseCspSetupStatus { + indicesDetails: IndexDetails[]; + latestPackageVersion: string; + cspm: BaseCspSetupBothPolicy; + kspm: BaseCspSetupBothPolicy; + vuln_mgmt: BaseCspSetupBothPolicy; + isPluginInitialized: boolean; + installedPackageVersion?: string | undefined; + hasMisconfigurationsFindings?: boolean; +} + +export type CspSetupStatus = BaseCspSetupStatus; export interface CspFinding { '@timestamp': string; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/index.tsx b/x-pack/packages/kbn-cloud-security-posture/index.ts similarity index 90% rename from x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/index.tsx rename to x-pack/packages/kbn-cloud-security-posture/index.ts index 6a2c75f0054a7..a0e4ba8dbc1b2 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/index.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './flyout'; +export * from './type'; diff --git a/x-pack/packages/kbn-cloud-security-posture/tsconfig.json b/x-pack/packages/kbn-cloud-security-posture/tsconfig.json new file mode 100644 index 0000000000000..a2652215c4e79 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture/tsconfig.json @@ -0,0 +1,37 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/core", + "@kbn/licensing-plugin", + "@kbn/data-views-plugin", + "@kbn/unified-search-plugin", + "@kbn/ui-actions-plugin", + "@kbn/field-formats-plugin", + "@kbn/data-view-field-editor-plugin", + "@kbn/data-plugin", + "@kbn/kibana-utils-plugin", + "@kbn/charts-plugin", + "@kbn/discover-plugin", + "@kbn/fleet-plugin", + "@kbn/usage-collection-plugin", + "@kbn/share-plugin", + "@kbn/es-query", + "@kbn/cloud-plugin", + "@kbn/spaces-plugin", + ] +} diff --git a/x-pack/packages/kbn-cloud-security-posture/type.ts b/x-pack/packages/kbn-cloud-security-posture/type.ts new file mode 100644 index 0000000000000..70daabecf67d3 --- /dev/null +++ b/x-pack/packages/kbn-cloud-security-posture/type.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CloudSetup } from '@kbn/cloud-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; +import { DataViewsServicePublic } from '@kbn/data-views-plugin/public'; +import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { IndexPatternFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { ToastsStart } from '@kbn/core/public'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; + +import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; +import type { DiscoverStart } from '@kbn/discover-plugin/public'; +import type { FleetStart } from '@kbn/fleet-plugin/public'; +import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; +import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; + +import type { BoolQuery } from '@kbn/es-query'; +export interface FindingsBaseEsQuery { + query?: { + bool: BoolQuery; + }; +} + +export interface CspClientPluginStartDeps { + // required + data: DataPublicPluginStart; + dataViews: DataViewsServicePublic; + dataViewFieldEditor: IndexPatternFieldEditorStart; + unifiedSearch: UnifiedSearchPublicPluginStart; + uiActions: UiActionsStart; + fieldFormats: FieldFormatsStart; + toastNotifications: ToastsStart; + charts: ChartsPluginStart; + discover: DiscoverStart; + fleet: FleetStart; + licensing: LicensingPluginStart; + share: SharePluginStart; + storage: Storage; + spaces: SpacesPluginStart; + cloud: CloudSetup; + + // optional + usageCollection?: UsageCollectionStart; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/types.ts b/x-pack/packages/security-solution/common/index.ts similarity index 60% rename from x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/types.ts rename to x-pack/packages/security-solution/common/index.ts index 97d82b862428d..ba5d797648f13 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/types.ts +++ b/x-pack/packages/security-solution/common/index.ts @@ -5,9 +5,7 @@ * 2.0. */ -import { FlyoutDataset } from '../../state_machines/dataset_quality_controller'; +export { HostDetailsButton } from './src/cells/renderers/host'; -export interface FlyoutProps { - dataset: FlyoutDataset; - closeFlyout: () => void; -} +export * from './src/flyout'; +export * from './src/cells/renderers'; diff --git a/x-pack/packages/security-solution/common/jest.config.js b/x-pack/packages/security-solution/common/jest.config.js new file mode 100644 index 0000000000000..7047e229df092 --- /dev/null +++ b/x-pack/packages/security-solution/common/jest.config.js @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../..', + roots: ['/x-pack/packages/security-solution/common'], +}; diff --git a/x-pack/packages/security-solution/common/kibana.jsonc b/x-pack/packages/security-solution/common/kibana.jsonc new file mode 100644 index 0000000000000..708feab435425 --- /dev/null +++ b/x-pack/packages/security-solution/common/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-browser", + "id": "@kbn/security-solution-common", + "owner": "@elastic/security-threat-hunting-investigations" +} diff --git a/x-pack/packages/security-solution/common/package.json b/x-pack/packages/security-solution/common/package.json new file mode 100644 index 0000000000000..ce355e927c3df --- /dev/null +++ b/x-pack/packages/security-solution/common/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/security-solution-common", + "version": "1.0.0", + "description": "security solution common components which can be used in multiple plugins such as custom discover and timeline", + "license": "Elastic License 2.0", + "private": true, + "sideEffects": false +} \ No newline at end of file diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/discover.ts b/x-pack/packages/security-solution/common/src/cells/renderers/discover.ts new file mode 100644 index 0000000000000..8d0393a3c6f2b --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/discover.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 { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import { ComponentType, PropsWithChildren } from 'react'; +import { HostCellWithFlyoutRenderer } from './host'; + +export type DiscoverCellRenderer = ComponentType>; + +const RENDERERS: Record = { + 'host.name': HostCellWithFlyoutRenderer, +}; + +interface GetRendererArgs { + fieldName: string; +} + +export const getDiscoverCellRenderer = ({ fieldName }: GetRendererArgs) => { + return RENDERERS[fieldName]; +}; diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/get.ts b/x-pack/packages/security-solution/common/src/cells/renderers/get.ts new file mode 100644 index 0000000000000..3102c520e31db --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/get.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 { getDiscoverCellRenderer } from './discover'; +export type { DiscoverCellRenderer } from './discover'; diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/host/button.test.tsx b/x-pack/packages/security-solution/common/src/cells/renderers/host/button.test.tsx new file mode 100644 index 0000000000000..d49af3ed50518 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/host/button.test.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { HostDetailsButton } from './button'; +import { render, screen } from '@testing-library/react'; + +const onClickMock = jest.fn(); +const TestComponent = () => { + return {'Test'}; +}; + +describe('Host Button', () => { + it('should render as button with link formatting', () => { + render(); + expect(screen.getByTestId('host-details-button')).toBeVisible(); + expect(screen.getByTestId('host-details-button')).toHaveAttribute('type', 'button'); + expect(screen.getByTestId('host-details-button')).toHaveClass('euiLink'); + }); + + it('should perform onClick Correctly', () => { + render(); + screen.getByTestId('host-details-button').click(); + expect(onClickMock).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/host/button.tsx b/x-pack/packages/security-solution/common/src/cells/renderers/host/button.tsx new file mode 100644 index 0000000000000..b478ee17bf9d4 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/host/button.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { SyntheticEvent } from 'react'; +import { EuiLink } from '@elastic/eui'; + +interface HostDetailsButtonProps { + children?: React.ReactNode; + onClick?: (e: SyntheticEvent) => void; + title?: string; +} + +export const HostDetailsButton: React.FC = ({ + children, + onClick, + title, +}) => { + return ( + + {children} + + ); +}; diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/host/index.tsx b/x-pack/packages/security-solution/common/src/cells/renderers/host/index.tsx new file mode 100644 index 0000000000000..a39397b233d60 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/host/index.tsx @@ -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 * from './button'; +export * from './with_expandable_flyout'; diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/host/with_expandable_flyout.test.tsx b/x-pack/packages/security-solution/common/src/cells/renderers/host/with_expandable_flyout.test.tsx new file mode 100644 index 0000000000000..0568c656cdbe5 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/host/with_expandable_flyout.test.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + HostCellWithFlyoutRenderer, + HostCellWithFlyoutRendererProps, +} from './with_expandable_flyout'; +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +const renderTestComponents = (props?: Partial) => { + const finalProps: HostCellWithFlyoutRendererProps = { + rowIndex: 0, + columnId: 'test', + setCellProps: jest.fn(), + isExpandable: false, + isExpanded: true, + isDetails: false, + colIndex: 0, + fieldFormats: {} as HostCellWithFlyoutRendererProps['fieldFormats'], + dataView: {} as HostCellWithFlyoutRendererProps['dataView'], + closePopover: jest.fn(), + row: { + id: '1', + raw: { + _source: { + host: { + name: 'test-host-name', + }, + }, + }, + flattened: { + 'host.name': 'test-host-name', + }, + }, + ...props, + }; + return render(); +}; + +describe('With Expandable Flyout', () => { + it('should open Expandable Flyout on Click', () => { + renderTestComponents(); + + expect(screen.getByTestId('host-details-button')).toBeVisible(); + screen.getByTestId('host-details-button').click(); + expect(screen.getByTestId('host-name-flyout')).toBeVisible(); + expect(screen.getByText('Host Flyout Header - test-host-name')).toBeVisible(); + }); +}); diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/host/with_expandable_flyout.tsx b/x-pack/packages/security-solution/common/src/cells/renderers/host/with_expandable_flyout.tsx new file mode 100644 index 0000000000000..f870fd9f7d04e --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/host/with_expandable_flyout.tsx @@ -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 React, { useCallback, useMemo } from 'react'; +import { getFieldValue } from '@kbn/discover-utils'; +import type { PropsWithChildren } from 'react'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import { + ExpandableFlyout, + type ExpandableFlyoutProps, + useExpandableFlyoutApi, + withExpandableFlyoutProvider, +} from '@kbn/expandable-flyout'; +import { HostRightPanel, HostRightPanelProps } from '../../../flyout/panels'; +import { HostDetailsButton } from './button'; + +export type HostCellWithFlyoutRendererProps = PropsWithChildren; + +const HostCellWithFlyoutRendererComp = React.memo(function HostCellWithFlyoutRendererComp( + props: HostCellWithFlyoutRendererProps +) { + const hostName = getFieldValue(props.row, 'host.name'); + + const { openFlyout } = useExpandableFlyoutApi(); + + const onClick = useCallback(() => { + openFlyout({ + right: { + id: `host-panel-${hostName}-${props.rowIndex}`, + params: { + hostName, + }, + } as HostRightPanelProps, + }); + }, [openFlyout, hostName, props.rowIndex]); + + const panels: ExpandableFlyoutProps['registeredPanels'] = useMemo(() => { + return [ + { + key: `host-panel-${hostName}-${props.rowIndex}`, + component: (panelProps) => { + return ; + }, + }, + ]; + }, [hostName, props.rowIndex]); + + return ( + <> + + {hostName} + + ); +}); + +export const HostCellWithFlyoutRenderer = withExpandableFlyoutProvider( + HostCellWithFlyoutRendererComp +); diff --git a/x-pack/packages/security-solution/common/src/cells/renderers/index.ts b/x-pack/packages/security-solution/common/src/cells/renderers/index.ts new file mode 100644 index 0000000000000..e42333a710c04 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/cells/renderers/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './get'; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.stories.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.stories.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.stories.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.stories.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.test.tsx similarity index 97% rename from x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.test.tsx index 483ee3d378bbd..cc282eb1156b5 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.test.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.test.tsx @@ -13,12 +13,12 @@ import { EXPANDABLE_PANEL_CONTENT_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from './test_ids'; -import { ThemeProvider } from 'styled-components'; -import { getMockTheme } from '../../../common/lib/kibana/kibana_react.mock'; +} from '../test_ids'; +import { ThemeProvider } from '@emotion/react'; import { ExpandablePanel } from './expandable_panel'; -const mockTheme = getMockTheme({ eui: { euiColorMediumShade: '#ece' } }); +const mockTheme = { eui: { euiColorMediumShade: '#ece' } }; + const TEST_ID = 'test-id'; const defaultProps = { header: { diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.tsx similarity index 97% rename from x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.tsx index aa97446f701e1..4f1890e58554f 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/expandable_panel.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/expandable_panel.tsx @@ -102,7 +102,7 @@ export const ExpandablePanel: FC> = > = diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_body.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_body.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_body.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_body.test.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_body.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_body.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_body.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_body.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.stories.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.stories.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.stories.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.stories.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.test.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.test.tsx index e58d586a063b5..f0565fe1df43f 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.test.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { render } from '@testing-library/react'; import { FlyoutError } from './flyout_error'; -import { FLYOUT_ERROR_TEST_ID } from './test_ids'; +import { FLYOUT_ERROR_TEST_ID } from '../test_ids'; describe('', () => { it('should render error title and body', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.tsx similarity index 84% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.tsx index 9ebef345540fe..f319d80dafe12 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_error.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_error.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiEmptyPrompt, EuiFlexItem } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { FLYOUT_ERROR_TEST_ID } from './test_ids'; +import { FLYOUT_ERROR_TEST_ID } from '../test_ids'; /** * Use this when you need to show an error state in the flyout @@ -21,7 +21,7 @@ export const FlyoutError: React.VFC = () => ( title={

@@ -30,7 +30,7 @@ export const FlyoutError: React.VFC = () => ( body={

diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_footer.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_footer.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_footer.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_footer.test.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_footer.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_footer.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_footer.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_footer.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header.test.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header_tabs.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header_tabs.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header_tabs.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header_tabs.test.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header_tabs.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header_tabs.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_header_tabs.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_header_tabs.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.stories.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.stories.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.stories.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.stories.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.test.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.test.tsx index a164db8a6ce01..d55e85b3e978b 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.test.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { FLYOUT_LOADING_TEST_ID } from './test_ids'; +import { FLYOUT_LOADING_TEST_ID } from '../test_ids'; import { FlyoutLoading } from './flyout_loading'; describe('', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.tsx index 0c98957dd929b..cffe17c8ccbf1 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_loading.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_loading.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import { css } from '@emotion/react'; -import { FLYOUT_LOADING_TEST_ID } from './test_ids'; +import { FLYOUT_LOADING_TEST_ID } from '../test_ids'; export interface FlyoutLoadingProps { /** diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.stories.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.stories.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.stories.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.stories.tsx diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.test.tsx similarity index 78% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.test.tsx index 321245ccde86e..d010796008880 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.test.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.test.tsx @@ -8,39 +8,61 @@ import type { FC, PropsWithChildren } from 'react'; import React from 'react'; import { act, render } from '@testing-library/react'; -import { TestProviders } from '../../../common/mock'; import { FlyoutNavigation } from './flyout_navigation'; import { COLLAPSE_DETAILS_BUTTON_TEST_ID, EXPAND_DETAILS_BUTTON_TEST_ID, HEADER_ACTIONS_TEST_ID, -} from './test_ids'; -import type { ExpandableFlyoutState } from '@kbn/expandable-flyout'; +} from '../test_ids'; import { + ExpandableFlyoutApi, + ExpandableFlyoutProvider, + ExpandableFlyoutState, useExpandableFlyoutApi, - type ExpandableFlyoutApi, useExpandableFlyoutState, } from '@kbn/expandable-flyout'; +import { I18nProvider } from '@kbn/i18n-react'; const expandDetails = jest.fn(); - -const ExpandableFlyoutTestProviders: FC> = ({ children }) => { - return {children}; -}; +const mockFlyoutCloseLeftPanel = jest.fn(); jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), + useExpandableFlyoutApi: jest.fn(() => { + return { + closeFlyout: jest.fn(), + closeLeftPanel: jest.fn(), + closePreviewPanel: jest.fn(), + closeRightPanel: jest.fn(), + previousPreviewPanel: jest.fn(), + openFlyout: jest.fn(), + openLeftPanel: jest.fn(), + openPreviewPanel: jest.fn(), + openRightPanel: jest.fn(), + }; + }), useExpandableFlyoutState: jest.fn(), ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, + withExpandableFlyoutProvider: (Component: React.ComponentType) => { + return (props: T) => { + return ; + }; + }, + ExpandableFlyout: jest.fn(), })); -const flyoutContextValue = { - closeLeftPanel: jest.fn(), -} as unknown as ExpandableFlyoutApi; +const ExpandableFlyoutTestProviders: FC> = ({ children }) => { + return ( + + {children} + + ); +}; describe('', () => { beforeEach(() => { - jest.mocked(useExpandableFlyoutApi).mockReturnValue(flyoutContextValue); + jest.mocked(useExpandableFlyoutApi).mockReturnValue({ + closeLeftPanel: mockFlyoutCloseLeftPanel, + } as unknown as ExpandableFlyoutApi); jest.mocked(useExpandableFlyoutState).mockReturnValue({} as unknown as ExpandableFlyoutState); }); @@ -75,7 +97,7 @@ describe('', () => { expect(queryByTestId(EXPAND_DETAILS_BUTTON_TEST_ID)).not.toBeInTheDocument(); getByTestId(COLLAPSE_DETAILS_BUTTON_TEST_ID).click(); - expect(flyoutContextValue.closeLeftPanel).toHaveBeenCalled(); + expect(mockFlyoutCloseLeftPanel).toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.tsx similarity index 91% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.tsx index 35e684e35613a..c67f20119031e 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_navigation.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_navigation.tsx @@ -23,7 +23,7 @@ import { COLLAPSE_DETAILS_BUTTON_TEST_ID, EXPAND_DETAILS_BUTTON_TEST_ID, HEADER_NAVIGATION_BUTTON_TEST_ID, -} from './test_ids'; +} from '../test_ids'; export interface FlyoutNavigationProps { /** @@ -62,14 +62,14 @@ export const FlyoutNavigation: FC = memo( size="s" data-test-subj={COLLAPSE_DETAILS_BUTTON_TEST_ID} aria-label={i18n.translate( - 'xpack.securitySolution.flyout.right.header.collapseDetailButtonAriaLabel', + 'securitySolutionPackages.flyout.right.header.collapseDetailButtonAriaLabel', { defaultMessage: 'Collapse details', } )} > @@ -86,14 +86,14 @@ export const FlyoutNavigation: FC = memo( size="s" data-test-subj={EXPAND_DETAILS_BUTTON_TEST_ID} aria-label={i18n.translate( - 'xpack.securitySolution.flyout.right.header.expandDetailButtonAriaLabel', + 'securitySolutionPackages.flyout.right.header.expandDetailButtonAriaLabel', { defaultMessage: 'Expand details', } )} > diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.stories.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.stories.tsx similarity index 98% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.stories.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.stories.tsx index 063e9fe9ef38f..867430167a349 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.stories.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.stories.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { Story } from '@storybook/react'; import { EuiLink } from '@elastic/eui'; -import styled from 'styled-components'; +import styled from '@emotion/styled'; import { FlyoutTitle } from './flyout_title'; const FixWidthWrapper = styled.div` diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.test.tsx similarity index 98% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.test.tsx index 1f2d0c128f411..3fde2b034219b 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.test.tsx +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.test.tsx @@ -12,7 +12,7 @@ import { TITLE_HEADER_ICON_TEST_ID, TITLE_HEADER_TEXT_TEST_ID, TITLE_LINK_ICON_TEST_ID, -} from './test_ids'; +} from '../test_ids'; const title = 'test title'; const TEST_ID = 'test'; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.tsx b/x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/flyout/shared/components/flyout_title.tsx rename to x-pack/packages/security-solution/common/src/flyout/common/components/flyout_title.tsx diff --git a/x-pack/packages/security-solution/common/src/flyout/common/components/index.ts b/x-pack/packages/security-solution/common/src/flyout/common/components/index.ts new file mode 100644 index 0000000000000..4624ae2f70c55 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/flyout/common/components/index.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. + */ + +export { FlyoutFooter } from './flyout_footer'; +export { FlyoutError } from './flyout_error'; +export { FlyoutLoading } from './flyout_loading'; +export { FlyoutNavigation } from './flyout_navigation'; +export { FlyoutTitle } from './flyout_title'; +export { FlyoutBody } from './flyout_body'; +export { FlyoutHeader } from './flyout_header'; +export { FlyoutHeaderTabs } from './flyout_header_tabs'; +export { ExpandablePanel } from './expandable_panel'; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/test_ids.ts b/x-pack/packages/security-solution/common/src/flyout/common/test_ids.ts similarity index 97% rename from x-pack/plugins/security_solution/public/flyout/shared/components/test_ids.ts rename to x-pack/packages/security-solution/common/src/flyout/common/test_ids.ts index 9df26dbfb694d..60ccb0a234fde 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/test_ids.ts +++ b/x-pack/packages/security-solution/common/src/flyout/common/test_ids.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PREFIX } from '../test_ids'; +export const PREFIX = 'securitySolutionFlyout' as const; export const FLYOUT_ERROR_TEST_ID = `${PREFIX}Error` as const; export const FLYOUT_LOADING_TEST_ID = `${PREFIX}Loading` as const; diff --git a/x-pack/packages/security-solution/common/src/flyout/index.tsx b/x-pack/packages/security-solution/common/src/flyout/index.tsx new file mode 100644 index 0000000000000..e919538d497c6 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/flyout/index.tsx @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './common/components'; +export * from './common/test_ids'; +export { HostRightPanel } from './panels'; diff --git a/x-pack/packages/security-solution/common/src/flyout/panels/host/right/index.tsx b/x-pack/packages/security-solution/common/src/flyout/panels/host/right/index.tsx new file mode 100644 index 0000000000000..d877695f5b170 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/flyout/panels/host/right/index.tsx @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import React from 'react'; +import { + FlyoutBody, + FlyoutFooter, + FlyoutHeader, + FlyoutNavigation, +} from '../../../common/components'; +// import { getEntityTableColumns } from './columns'; +// import type { BasicEntityData, EntityTableRows } from './types'; + +export interface HostRightPanelParamProps extends Record { + hostName: string; +} + +export interface HostRightPanelProps extends FlyoutPanelProps { + key: 'host'; + params: HostRightPanelParamProps; +} + +export const HostRightPanel = (props: HostRightPanelParamProps) => { + return ( + <> + + {`Host Flyout Header - ${props.hostName}`} + {'Host Flyout'} + {'Host Flyout Footer'} + + ); +}; diff --git a/x-pack/packages/security-solution/common/src/flyout/panels/index.ts b/x-pack/packages/security-solution/common/src/flyout/panels/index.ts new file mode 100644 index 0000000000000..3134078ebdf7f --- /dev/null +++ b/x-pack/packages/security-solution/common/src/flyout/panels/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 * from './host/right'; +export * from './keys'; diff --git a/x-pack/packages/security-solution/common/src/flyout/panels/keys.ts b/x-pack/packages/security-solution/common/src/flyout/panels/keys.ts new file mode 100644 index 0000000000000..fe06cf652d016 --- /dev/null +++ b/x-pack/packages/security-solution/common/src/flyout/panels/keys.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 HOST_PANEL = 'host-panel'; diff --git a/x-pack/packages/security-solution/common/tsconfig.json b/x-pack/packages/security-solution/common/tsconfig.json new file mode 100644 index 0000000000000..fb0d3709961d8 --- /dev/null +++ b/x-pack/packages/security-solution/common/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react", + "@testing-library/jest-dom", + "@testing-library/react", + "@emotion/react/types/css-prop" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx" + ], + "kbn_references": [ + "@kbn/unified-data-table", + "@kbn/discover-utils", + "@kbn/expandable-flyout", + "@kbn/i18n", + "@kbn/i18n-react" + ], + "exclude": [ + "target/**/*" + ] +} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/allowed_values/helpers.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/allowed_values/helpers.test.tsx deleted file mode 100644 index 7fd0a3f3b133d..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/allowed_values/helpers.test.tsx +++ /dev/null @@ -1,152 +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 { EcsFlatTyped } from '../../constants'; -import { getUnallowedValueRequestItems, getValidValues, hasAllowedValues } from './helpers'; - -describe('helpers', () => { - describe('hasAllowedValues', () => { - test('it returns true for a field that has `allowed_values`', () => { - expect( - hasAllowedValues({ - ecsMetadata: EcsFlatTyped, - fieldName: 'event.category', - }) - ).toBe(true); - }); - - test('it returns false for a field that does NOT have `allowed_values`', () => { - expect( - hasAllowedValues({ - ecsMetadata: EcsFlatTyped, - fieldName: 'host.name', - }) - ).toBe(false); - }); - - test('it returns false for a field that does NOT exist in `ecsMetadata`', () => { - expect( - hasAllowedValues({ - ecsMetadata: EcsFlatTyped, - fieldName: 'does.NOT.exist', - }) - ).toBe(false); - }); - }); - - describe('getValidValues', () => { - test('it returns the expected valid values', () => { - expect(getValidValues(EcsFlatTyped['event.category'])).toEqual( - expect.arrayContaining([ - 'authentication', - 'configuration', - 'database', - 'driver', - 'email', - 'file', - 'host', - 'iam', - 'intrusion_detection', - 'malware', - 'network', - 'package', - 'process', - 'registry', - 'session', - 'threat', - 'vulnerability', - 'web', - ]) - ); - }); - - test('it returns an empty array when the `field` does NOT have `allowed_values`', () => { - expect(getValidValues(EcsFlatTyped['host.name'])).toEqual([]); - }); - - test('it returns an empty array when `field` is undefined', () => { - expect(getValidValues(undefined)).toEqual([]); - }); - }); - - describe('getUnallowedValueRequestItems', () => { - test('it returns the expected request items', () => { - expect( - getUnallowedValueRequestItems({ - ecsMetadata: EcsFlatTyped, - indexName: 'auditbeat-*', - }) - ).toEqual([ - { - indexName: 'auditbeat-*', - indexFieldName: 'event.category', - allowedValues: expect.arrayContaining([ - 'authentication', - 'configuration', - 'database', - 'driver', - 'email', - 'file', - 'host', - 'iam', - 'intrusion_detection', - 'malware', - 'network', - 'package', - 'process', - 'registry', - 'session', - 'threat', - 'vulnerability', - 'web', - ]), - }, - { - indexName: 'auditbeat-*', - indexFieldName: 'event.kind', - allowedValues: expect.arrayContaining([ - 'alert', - 'enrichment', - 'event', - 'metric', - 'state', - 'pipeline_error', - 'signal', - ]), - }, - { - indexName: 'auditbeat-*', - indexFieldName: 'event.outcome', - allowedValues: expect.arrayContaining(['failure', 'success', 'unknown']), - }, - { - indexName: 'auditbeat-*', - indexFieldName: 'event.type', - allowedValues: expect.arrayContaining([ - 'access', - 'admin', - 'allowed', - 'change', - 'connection', - 'creation', - 'deletion', - 'denied', - 'end', - 'error', - 'group', - 'indicator', - 'info', - 'installation', - 'protocol', - 'start', - 'user', - ]), - }, - ]); - }); - }); -}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/index.test.tsx deleted file mode 100644 index 595c17e16faaa..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/index.test.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render, screen, waitFor } from '@testing-library/react'; -import React from 'react'; - -import { - TestDataQualityProviders, - TestExternalProviders, -} from '../../mock/test_providers/test_providers'; -import { Body } from '.'; - -describe('IndexInvalidValues', () => { - test('it renders the data quality summary', async () => { - render( - - - - - - ); - - await waitFor(() => { - expect(screen.getByTestId('dataQualitySummary')).toBeInTheDocument(); - }); - }); - - describe('patterns', () => { - const patterns = ['.alerts-security.alerts-default', 'auditbeat-*', 'logs-*', 'packetbeat-*']; - - test(`it renders the '${patterns.join(', ')}' patterns`, async () => { - render( - - - - - - ); - - for (const pattern of patterns) { - await waitFor(() => { - expect(screen.getByTestId(`${pattern}PatternPanel`)).toBeInTheDocument(); - }); - } - }); - }); -}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/index.tsx deleted file mode 100644 index a8ceecdc76c09..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import React from 'react'; - -import { DataQualityDetails } from './data_quality_details'; -import { DataQualitySummary } from '../data_quality_summary'; - -const BodyComponent: React.FC = () => { - return ( - - - - - - - - - - - ); -}; - -export const Body = React.memo(BodyComponent); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.test.ts deleted file mode 100644 index 0058e2436a526..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.test.ts +++ /dev/null @@ -1,1537 +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 { IlmExplainLifecycleLifecycleExplain } from '@elastic/elasticsearch/lib/api/types'; -import { omit } from 'lodash/fp'; - -import { - FieldType, - getDocsCount, - getErrorSummary, - getErrorSummaries, - getErrorSummariesForRollup, - getEnrichedFieldMetadata, - getFieldTypes, - getPatternIlmPhaseDescription, - getIlmPhaseDescription, - getIndexNames, - getIsInSameFamily, - getMissingTimestampFieldMetadata, - getPartitionedFieldMetadata, - getPartitionedFieldMetadataStats, - getSizeInBytes, - getTotalDocsCount, - getTotalPatternIncompatible, - getTotalPatternIndicesChecked, - getTotalPatternSameFamily, - getTotalSizeInBytes, - isMappingCompatible, - postStorageResult, - getStorageResults, - StorageResult, - formatStorageResult, -} from './helpers'; -import { - hostNameWithTextMapping, - hostNameKeyword, - someField, - someFieldKeyword, - sourceIpWithTextMapping, - sourceIpKeyword, - sourcePort, - timestamp, - eventCategoryWithUnallowedValues, -} from './mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { mockIlmExplain } from './mock/ilm_explain/mock_ilm_explain'; -import { mockMappingsProperties } from './mock/mappings_properties/mock_mappings_properties'; -import { alertIndexNoResults } from './mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { - packetbeatNoResults, - packetbeatWithSomeErrors, -} from './mock/pattern_rollup/mock_packetbeat_pattern_rollup'; -import { - auditbeatNoResults, - auditbeatWithAllResults, -} from './mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { mockStats } from './mock/stats/mock_stats'; -import { mockStatsAuditbeatIndex } from './mock/stats/mock_stats_packetbeat_index'; -import { mockStatsPacketbeatIndex } from './mock/stats/mock_stats_auditbeat_index'; -import { - COLD_DESCRIPTION, - FROZEN_DESCRIPTION, - HOT_DESCRIPTION, - UNMANAGED_DESCRIPTION, - WARM_DESCRIPTION, -} from './translations'; -import { - DataQualityCheckResult, - EnrichedFieldMetadata, - PartitionedFieldMetadata, - PatternRollup, - UnallowedValueCount, -} from './types'; -import { httpServiceMock } from '@kbn/core-http-browser-mocks'; -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -import { EcsFlatTyped } from './constants'; -import { mockPartitionedFieldMetadataWithSameFamily } from './mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family'; - -describe('helpers', () => { - describe('getTotalPatternSameFamily', () => { - const baseResult: DataQualityCheckResult = { - docsCount: 4, - error: null, - ilmPhase: 'unmanaged', - incompatible: 3, - indexName: 'auditbeat-custom-index-1', - markdownComments: [ - '### auditbeat-custom-index-1\n', - '| Result | Index | Docs | Incompatible fields | ILM Phase |\n|--------|-------|------|---------------------|-----------|\n| ❌ | auditbeat-custom-index-1 | 4 (0.0%) | 3 | `unmanaged` |\n\n', - '### **Incompatible fields** `3` **Custom fields** `4` **ECS compliant fields** `2` **All fields** `9`\n', - "#### 3 incompatible fields, 0 fields with mappings in the same family\n\nFields are incompatible with ECS when index mappings, or the values of the fields in the index, don't conform to the Elastic Common Schema (ECS), version 8.6.1.\n\nIncompatible fields with mappings in the same family have exactly the same search behavior but may have different space usage or performance characteristics.\n\nWhen an incompatible field is not in the same family:\n❌ Detection engine rules referencing these fields may not match them correctly\n❌ Pages may not display some events or fields due to unexpected field mappings or values\n❌ Mappings or field values that don't comply with ECS are not supported\n", - '\n#### Incompatible field mappings - auditbeat-custom-index-1\n\n\n| Field | ECS mapping type (expected) | Index mapping type (actual) | \n|-------|-----------------------------|-----------------------------|\n| host.name | `keyword` | `text` |\n| source.ip | `ip` | `text` |\n\n#### Incompatible field values - auditbeat-custom-index-1\n\n\n| Field | ECS values (expected) | Document values (actual) | \n|-------|-----------------------|--------------------------|\n| event.category | `authentication`, `configuration`, `database`, `driver`, `email`, `file`, `host`, `iam`, `intrusion_detection`, `malware`, `network`, `package`, `process`, `registry`, `session`, `threat`, `vulnerability`, `web` | `an_invalid_category` (2),\n`theory` (1) |\n\n', - ], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }; - - it('returns undefined when results is undefined', () => { - expect(getTotalPatternSameFamily(undefined)).toBeUndefined(); - }); - - it('returns 0 when results is an empty object', () => { - expect(getTotalPatternSameFamily({})).toBe(0); - }); - - it('should sum sameFamily values and return the total', () => { - const results: Record = { - a: { - ...baseResult, - indexName: 'a', - markdownComments: [], - pattern: 'pattern', - sameFamily: 2, - }, - b: { - ...baseResult, - indexName: 'b', - markdownComments: [], - pattern: 'pattern', - sameFamily: 3, - }, - c: { ...baseResult, indexName: 'c', markdownComments: [], pattern: 'pattern' }, - }; - - expect(getTotalPatternSameFamily(results)).toBe(5); - }); - - it('handles a mix of defined and undefined sameFamily values', () => { - const results: Record = { - a: { - ...baseResult, - indexName: 'a', - markdownComments: [], - pattern: 'pattern', - sameFamily: 1, - }, - b: { - ...baseResult, - indexName: 'b', - markdownComments: [], - pattern: 'pattern', - sameFamily: undefined, - }, - c: { - ...baseResult, - indexName: 'c', - markdownComments: [], - pattern: 'pattern', - sameFamily: 2, - }, - }; - - expect(getTotalPatternSameFamily(results)).toBe(3); - }); - }); - - describe('getIndexNames', () => { - const isILMAvailable = true; - const ilmPhases = ['hot', 'warm', 'unmanaged']; - - test('returns the expected index names when they have an ILM phase included in the ilmPhases list', () => { - expect( - getIndexNames({ - ilmExplain: mockIlmExplain, // <-- the mock indexes have 'hot' ILM phases - ilmPhases, - isILMAvailable, - stats: mockStats, - }) - ).toEqual([ - '.ds-packetbeat-8.6.1-2023.02.04-000001', - '.ds-packetbeat-8.5.3-2023.02.04-000001', - 'auditbeat-custom-index-1', - ]); - }); - - test('returns the expected filtered index names when they do NOT have an ILM phase included in the ilmPhases list', () => { - expect( - getIndexNames({ - ilmExplain: mockIlmExplain, // <-- the mock indexes have 'hot' and 'unmanaged' ILM phases... - ilmPhases: ['warm', 'unmanaged'], // <-- ...but we don't ask for 'hot' - isILMAvailable, - stats: mockStats, - }) - ).toEqual(['auditbeat-custom-index-1']); // <-- the 'unmanaged' index - }); - - test('returns the expected index names when the `ilmExplain` is missing a record for an index', () => { - // the following `ilmExplain` is missing a record for one of the two packetbeat indexes: - const ilmExplainWithMissingIndex: Record = omit( - '.ds-packetbeat-8.6.1-2023.02.04-000001', - mockIlmExplain - ); - - expect( - getIndexNames({ - ilmExplain: ilmExplainWithMissingIndex, // <-- the mock indexes have 'hot' ILM phases... - ilmPhases: ['hot', 'warm', 'unmanaged'], - isILMAvailable, - stats: mockStats, - }) - ).toEqual(['.ds-packetbeat-8.5.3-2023.02.04-000001', 'auditbeat-custom-index-1']); // <-- only includes two of the three indices, because the other one is missing an ILM explain record - }); - - test('returns empty index names when `ilmPhases` is empty', () => { - expect( - getIndexNames({ - ilmExplain: mockIlmExplain, - ilmPhases: [], - isILMAvailable, - stats: mockStats, - }) - ).toEqual([]); - }); - - test('returns empty index names when they have an ILM phase that matches', () => { - expect( - getIndexNames({ - ilmExplain: null, - ilmPhases, - isILMAvailable, - stats: mockStats, - }) - ).toEqual([]); - }); - - test('returns empty index names when just `stats` is null', () => { - expect( - getIndexNames({ - ilmExplain: mockIlmExplain, - ilmPhases, - isILMAvailable, - stats: null, - }) - ).toEqual([]); - }); - - test('returns empty index names when both `ilmExplain` and `stats` are null', () => { - expect( - getIndexNames({ - ilmExplain: null, - ilmPhases, - isILMAvailable, - stats: null, - }) - ).toEqual([]); - }); - }); - - describe('getFieldTypes', () => { - const expected = [ - { - field: '@timestamp', - type: 'date', - }, - { - field: 'event.category', - type: 'keyword', - }, - { - field: 'host.name', - type: 'text', - }, - { - field: 'host.name.keyword', - type: 'keyword', - }, - { - field: 'some.field', - type: 'text', - }, - { - field: 'some.field.keyword', - type: 'keyword', - }, - { - field: 'source.ip', - type: 'text', - }, - { - field: 'source.ip.keyword', - type: 'keyword', - }, - { - field: 'source.port', - type: 'long', - }, - ]; - - test('it flattens the field names and types in the mapping properties', () => { - expect(getFieldTypes(mockMappingsProperties)).toEqual(expected); - }); - - test('it throws a type error when mappingsProperties is not flatten-able', () => { - // @ts-expect-error - const invalidType: Record = []; // <-- this is an array, NOT a valid Record - - expect(() => getFieldTypes(invalidType)).toThrowError('Root value is not flatten-able'); - }); - }); - - describe('getIsInSameFamily', () => { - test('it returns false when ecsExpectedType is undefined', () => { - expect(getIsInSameFamily({ ecsExpectedType: undefined, type: 'keyword' })).toBe(false); - }); - - const expectedFamilyMembers: { - [key: string]: string[]; - } = { - constant_keyword: ['keyword', 'wildcard'], // `keyword` and `wildcard` in the same family as `constant_keyword` - keyword: ['constant_keyword', 'wildcard'], - match_only_text: ['text'], - text: ['match_only_text'], - wildcard: ['keyword', 'constant_keyword'], - }; - - const ecsExpectedTypes = Object.keys(expectedFamilyMembers); - - ecsExpectedTypes.forEach((ecsExpectedType) => { - const otherMembersOfSameFamily = expectedFamilyMembers[ecsExpectedType]; - - otherMembersOfSameFamily.forEach((type) => - test(`it returns true for ecsExpectedType '${ecsExpectedType}' when given '${type}', a type in the same family`, () => { - expect(getIsInSameFamily({ ecsExpectedType, type })).toBe(true); - }) - ); - - test(`it returns false for ecsExpectedType '${ecsExpectedType}' when given 'date', a type NOT in the same family`, () => { - expect(getIsInSameFamily({ ecsExpectedType, type: 'date' })).toBe(false); - }); - }); - }); - - describe('isMappingCompatible', () => { - test('it returns true for an exact match', () => { - expect(isMappingCompatible({ ecsExpectedType: 'keyword', type: 'keyword' })).toBe(true); - }); - - test("it returns false when both types don't exactly match", () => { - expect(isMappingCompatible({ ecsExpectedType: 'wildcard', type: 'keyword' })).toBe(false); - }); - }); - - describe('getEnrichedFieldMetadata', () => { - /** - * The ECS schema - * https://raw.githubusercontent.com/elastic/ecs/main/generated/ecs/ecs_flat.yml - * defines a handful of fields that have `allowed_values`. For these - * fields, the documents in an index should only have specific values. - * - * This instance of the type `Record` - * represents an index that doesn't have any unallowed values, for the - * specified keys in the map, i.e. `event.category`, `event.kind`, etc. - * - * This will be used to test the happy path. Variants of this - * value will be used to test unhappy paths. - */ - const noUnallowedValues: Record = { - 'event.category': [], - 'event.kind': [], - 'event.outcome': [], - 'event.type': [], - }; - - /** - * Represents an index that has unallowed values, for the - * `event.category` field. The other fields in the collection, - * i.e. `event.kind`, don't have any unallowed values. - * - * This instance will be used to test paths where a field is - * NOT ECS complaint, because the index has unallowed values. - */ - const unallowedValues: Record = { - 'event.category': [ - { - count: 2, - fieldName: 'an_invalid_category', - }, - { - count: 1, - fieldName: 'theory', - }, - ], - 'event.kind': [], - 'event.outcome': [], - 'event.type': [], - }; - - /** - * This instance of a `FieldType` has the correct mapping for the - * `event.category` field. - * - * This instance will be used to test paths where the index has - * a valid mapping for the `event.category` field. - */ - const fieldMetadataCorrectMappingType: FieldType = { - field: 'event.category', - type: 'keyword', // <-- this index has the correct mapping type - }; - - /** - * This `EnrichedFieldMetadata` for the `event.category` field, - * represents a happy path result, where the index being checked: - * - * 1) The `type` of the field in the index, `keyword`, matches the expected - * `type` of the `event.category` field, as defined by the `EcsMetadata` - * 2) The index doesn't have any unallowed values for the `event.category` field - * - * Since this is a happy path result, it has the following values: - * `indexInvalidValues` is an empty array, because the index does not contain any invalid values - * `isEcsCompliant` is true, because the index has the expected mapping type, and no unallowed values - */ - const happyPathResultSample: EnrichedFieldMetadata = { - dashed_name: 'event-category', - description: - 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy.\n`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory.\nThis field is an array. This will allow proper categorization of some events that fall in multiple categories.', - example: 'authentication', - flat_name: 'event.category', - ignore_above: 1024, - level: 'core', - name: 'category', - normalize: ['array'], - short: 'Event category. The second categorization field in the hierarchy.', - type: 'keyword', - indexFieldName: 'event.category', - indexFieldType: 'keyword', // a valid mapping, because the `type` property from the `ecsMetadata` is also `keyword` - indexInvalidValues: [], // empty array, because the index does not contain any invalid values - hasEcsMetadata: true, - isEcsCompliant: true, // because the index has the expected mapping type, and no unallowed values - isInSameFamily: false, - }; - - /** - * Creates expected result matcher based on the happy path result sample. Please, add similar `expect` based assertions to it if anything breaks - * with an ECS upgrade, instead of hardcoding the values. - */ - const expectedResult = (extraFields: Record = {}) => - expect.objectContaining({ - ...happyPathResultSample, - ...extraFields, - allowed_values: expect.arrayContaining([ - expect.objectContaining({ - description: expect.any(String), - name: expect.any(String), - expected_event_types: expect.any(Array), - }), - ]), - }); - - test('it returns the happy path result when the index has no mapping conflicts, and no unallowed values', () => { - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: fieldMetadataCorrectMappingType, // no mapping conflicts for `event.category` in this index - unallowedValues: noUnallowedValues, // no unallowed values for `event.category` in this index - }) - ).toEqual(expectedResult()); - }); - - test('it returns the happy path result when the index has no mapping conflicts, and the unallowedValues map does not contain an entry for the field', () => { - // create an `unallowedValues` that doesn't have an entry for `event.category`: - const noEntryForEventCategory: Record = omit( - 'event.category', - unallowedValues - ); - - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: fieldMetadataCorrectMappingType, // no mapping conflicts for `event.category` in this index - unallowedValues: noEntryForEventCategory, // a lookup in this map for the `event.category` field will return undefined - }) - ).toEqual(expectedResult()); - }); - - test('it returns a result with the expected `indexInvalidValues` and `isEcsCompliant` when the index has no mapping conflict, but it has unallowed values', () => { - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: fieldMetadataCorrectMappingType, // no mapping conflicts for `event.category` in this index - unallowedValues, // this index has unallowed values for the event.category field - }) - ).toEqual( - expectedResult({ - indexInvalidValues: [ - { - count: 2, - fieldName: 'an_invalid_category', - }, - { - count: 1, - fieldName: 'theory', - }, - ], - isEcsCompliant: false, // because there are unallowed values - }) - ); - }); - - test('it returns a result with the expected `isEcsCompliant` and `isInSameFamily` when the index type does not match ECS, but NO unallowed values', () => { - const indexFieldType = 'text'; - - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: { - field: 'event.category', // `event.category` is a `keyword`, per the ECS spec - type: indexFieldType, // this index has a mapping of `text` instead - }, - unallowedValues: noUnallowedValues, // no unallowed values for `event.category` in this index - }) - ).toEqual( - expectedResult({ - indexFieldType, - isEcsCompliant: false, // `keyword` !== `text` - isInSameFamily: false, // `keyword` and `text` are not in the same family - }) - ); - }); - - test('it returns a result with the expected `isEcsCompliant` and `isInSameFamily` when the mapping is is in the same family', () => { - const indexFieldType = 'wildcard'; - - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: { - field: 'event.category', // `event.category` is a `keyword` per the ECS spec - type: indexFieldType, // this index has a mapping of `wildcard` instead - }, - unallowedValues: noUnallowedValues, // no unallowed values for `event.category` in this index - }) - ).toEqual( - expectedResult({ - indexFieldType, - isEcsCompliant: false, // `wildcard` !== `keyword` - isInSameFamily: true, // `wildcard` and `keyword` are in the same family - }) - ); - }); - - test('it returns a result with the expected `indexInvalidValues`,`isEcsCompliant`, and `isInSameFamily` when the index has BOTH mapping conflicts, and unallowed values', () => { - const indexFieldType = 'text'; - - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: { - field: 'event.category', // `event.category` is a `keyword` per the ECS spec - type: indexFieldType, // this index has a mapping of `text` instead - }, - unallowedValues, // this index also has unallowed values for the event.category field - }) - ).toEqual( - expectedResult({ - indexFieldType, - indexInvalidValues: [ - { - count: 2, - fieldName: 'an_invalid_category', - }, - { - count: 1, - fieldName: 'theory', - }, - ], - isEcsCompliant: false, // because there are BOTH mapping conflicts and unallowed values - isInSameFamily: false, // `text` and `keyword` are not in the same family - }) - ); - }); - - test('it returns the expected result for a custom field, i.e. a field that does NOT have an entry in `ecsMetadata`', () => { - const field = 'a_custom_field'; // not defined by ECS - const indexFieldType = 'keyword'; - - expect( - getEnrichedFieldMetadata({ - ecsMetadata: EcsFlatTyped, - fieldMetadata: { - field, - type: indexFieldType, // no mapping conflict, because ECS doesn't define this field - }, - unallowedValues: noUnallowedValues, // no unallowed values for `a_custom_field` in this index - }) - ).toEqual({ - indexFieldName: field, - indexFieldType, - indexInvalidValues: [], - hasEcsMetadata: false, - isEcsCompliant: false, - isInSameFamily: false, // custom fields are never in the same family - }); - }); - }); - - describe('getMissingTimestampFieldMetadata', () => { - test('it returns the expected `EnrichedFieldMetadata`', () => { - expect(getMissingTimestampFieldMetadata()).toEqual({ - ...EcsFlatTyped['@timestamp'], - hasEcsMetadata: true, - indexFieldName: '@timestamp', - indexFieldType: '-', // the index did NOT define a mapping for @timestamp - indexInvalidValues: [], - isEcsCompliant: false, // an index must define the @timestamp mapping - isInSameFamily: false, // `date` is not a member of any families - }); - }); - }); - - describe('getPartitionedFieldMetadata', () => { - test('it places all the `EnrichedFieldMetadata` in the expected categories', () => { - const enrichedFieldMetadata: EnrichedFieldMetadata[] = [ - timestamp, - eventCategoryWithUnallowedValues, - hostNameWithTextMapping, - hostNameKeyword, - someField, - someFieldKeyword, - sourceIpWithTextMapping, - sourceIpKeyword, - sourcePort, - ]; - const expected: PartitionedFieldMetadata = { - all: [ - timestamp, - eventCategoryWithUnallowedValues, - hostNameWithTextMapping, - hostNameKeyword, - someField, - someFieldKeyword, - sourceIpWithTextMapping, - sourceIpKeyword, - sourcePort, - ], - ecsCompliant: [timestamp, sourcePort], - custom: [hostNameKeyword, someField, someFieldKeyword, sourceIpKeyword], - incompatible: [ - eventCategoryWithUnallowedValues, - hostNameWithTextMapping, - sourceIpWithTextMapping, - ], - sameFamily: [], - }; - - expect(getPartitionedFieldMetadata(enrichedFieldMetadata)).toEqual(expected); - }); - }); - - describe('getPartitionedFieldMetadataStats', () => { - test('it returns the expected stats', () => { - const partitionedFieldMetadata: PartitionedFieldMetadata = { - all: [ - timestamp, - eventCategoryWithUnallowedValues, - hostNameWithTextMapping, - hostNameKeyword, - someField, - someFieldKeyword, - sourceIpWithTextMapping, - sourceIpKeyword, - sourcePort, - ], - ecsCompliant: [timestamp, sourcePort], - custom: [hostNameKeyword, someField, someFieldKeyword, sourceIpKeyword], - incompatible: [ - eventCategoryWithUnallowedValues, - hostNameWithTextMapping, - sourceIpWithTextMapping, - ], - sameFamily: [], - }; - - expect(getPartitionedFieldMetadataStats(partitionedFieldMetadata)).toEqual({ - all: 9, - custom: 4, - ecsCompliant: 2, - incompatible: 3, - sameFamily: 0, - }); - }); - }); - - describe('getDocsCount', () => { - test('it returns the expected docs count when `stats` contains the `indexName`', () => { - const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; - const expectedCount = mockStatsPacketbeatIndex[indexName].num_docs; - - expect( - getDocsCount({ - indexName, - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(expectedCount); - }); - - test('it returns zero when `stats` does NOT contain the `indexName`', () => { - const indexName = 'not-gonna-find-it'; - - expect( - getDocsCount({ - indexName, - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(0); - }); - - test('it returns zero when `stats` is null', () => { - const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; - - expect( - getDocsCount({ - indexName, - stats: null, - }) - ).toEqual(0); - }); - - test('it returns the expected total for a green index, where `primaries.docs.count` and `total.docs.count` have different values', () => { - const indexName = 'auditbeat-custom-index-1'; - - expect( - getDocsCount({ - indexName, - stats: mockStatsAuditbeatIndex, - }) - ).toEqual(mockStatsAuditbeatIndex[indexName].num_docs); - }); - }); - - describe('getSizeInBytes', () => { - test('it returns the expected size when `stats` contains the `indexName`', () => { - const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; - const expectedCount = mockStatsPacketbeatIndex[indexName].size_in_bytes; - - expect( - getSizeInBytes({ - indexName, - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(expectedCount); - }); - - test('it returns undefined when `stats` does NOT contain the `indexName`', () => { - const indexName = 'not-gonna-find-it'; - - expect( - getSizeInBytes({ - indexName, - stats: mockStatsPacketbeatIndex, - }) - ).toBeUndefined(); - }); - - test('it returns undefined when `stats` is null', () => { - const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; - - expect( - getSizeInBytes({ - indexName, - stats: null, - }) - ).toBeUndefined(); - }); - - test('it returns the expected size for a green index, where `primaries.store.size_in_bytes` and `total.store.size_in_bytes` have different values', () => { - const indexName = 'auditbeat-custom-index-1'; - - expect( - getSizeInBytes({ - indexName, - stats: mockStatsAuditbeatIndex, - }) - ).toEqual(mockStatsAuditbeatIndex[indexName].size_in_bytes); - }); - }); - - describe('getTotalDocsCount', () => { - test('it returns the expected total given a subset of index names in the stats', () => { - const indexName = '.ds-packetbeat-8.5.3-2023.02.04-000001'; - const expectedCount = mockStatsPacketbeatIndex[indexName].num_docs; - - expect( - getTotalDocsCount({ - indexNames: [indexName], - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(expectedCount); - }); - - test('it returns the expected total given all index names in the stats', () => { - const allIndexNamesInStats = [ - '.ds-packetbeat-8.6.1-2023.02.04-000001', - '.ds-packetbeat-8.5.3-2023.02.04-000001', - ]; - - expect( - getTotalDocsCount({ - indexNames: allIndexNamesInStats, - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(3258632); - }); - - test('it returns zero given an empty collection of index names', () => { - expect( - getTotalDocsCount({ - indexNames: [], // <-- empty - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(0); - }); - - test('it returns the expected total for a green index', () => { - const indexName = 'auditbeat-custom-index-1'; - const expectedCount = mockStatsAuditbeatIndex[indexName].num_docs; - - expect( - getTotalDocsCount({ - indexNames: [indexName], - stats: mockStatsAuditbeatIndex, - }) - ).toEqual(expectedCount); - }); - }); - - describe('getTotalSizeInBytes', () => { - test('it returns the expected total given a subset of index names in the stats', () => { - const indexName = '.ds-packetbeat-8.5.3-2023.02.04-000001'; - const expectedCount = mockStatsPacketbeatIndex[indexName].size_in_bytes; - - expect( - getTotalSizeInBytes({ - indexNames: [indexName], - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(expectedCount); - }); - - test('it returns the expected total given all index names in the stats', () => { - const allIndexNamesInStats = [ - '.ds-packetbeat-8.6.1-2023.02.04-000001', - '.ds-packetbeat-8.5.3-2023.02.04-000001', - ]; - - expect( - getTotalSizeInBytes({ - indexNames: allIndexNamesInStats, - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(1464758182); - }); - - test('it returns undefined given an empty collection of index names', () => { - expect( - getTotalSizeInBytes({ - indexNames: [], // <-- empty - stats: mockStatsPacketbeatIndex, - }) - ).toBeUndefined(); - }); - - test('it returns undefined if sizeInByte in not an integer', () => { - const indexName = 'auditbeat-custom-index-1'; - - expect( - getTotalSizeInBytes({ - indexNames: [indexName], - stats: { [indexName]: { ...mockStatsAuditbeatIndex[indexName], size_in_bytes: null } }, - }) - ).toBeUndefined(); - }); - - test('it returns the expected total for an index', () => { - const indexName = 'auditbeat-custom-index-1'; - const expectedCount = mockStatsAuditbeatIndex[indexName].size_in_bytes; - - expect( - getTotalSizeInBytes({ - indexNames: [indexName], - stats: mockStatsAuditbeatIndex, - }) - ).toEqual(expectedCount); - }); - - test('it returns the expected total for indices', () => { - const expectedCount = Object.values(mockStatsPacketbeatIndex).reduce( - (acc, { size_in_bytes: sizeInBytes }) => { - return acc + (sizeInBytes ?? 0); - }, - 0 - ); - - expect( - getTotalSizeInBytes({ - indexNames: [ - '.ds-packetbeat-8.6.1-2023.02.04-000001', - '.ds-packetbeat-8.5.3-2023.02.04-000001', - ], - stats: mockStatsPacketbeatIndex, - }) - ).toEqual(expectedCount); - }); - }); - - describe('getIlmPhaseDescription', () => { - const phases: Array<{ - phase: string; - expected: string; - }> = [ - { - phase: 'hot', - expected: HOT_DESCRIPTION, - }, - { - phase: 'warm', - expected: WARM_DESCRIPTION, - }, - { - phase: 'cold', - expected: COLD_DESCRIPTION, - }, - { - phase: 'frozen', - expected: FROZEN_DESCRIPTION, - }, - { - phase: 'unmanaged', - expected: UNMANAGED_DESCRIPTION, - }, - { - phase: 'something-else', - expected: ' ', - }, - ]; - - phases.forEach(({ phase, expected }) => { - test(`it returns ${expected} when phase is ${phase}`, () => { - expect(getIlmPhaseDescription(phase)).toBe(expected); - }); - }); - }); - - describe('getPatternIlmPhaseDescription', () => { - const phases: Array<{ - expected: string; - indices: number; - pattern: string; - phase: string; - }> = [ - { - expected: - '1 index matching the .alerts-security.alerts-default pattern is hot. Hot indices are actively being updated and queried.', - indices: 1, - pattern: '.alerts-security.alerts-default', - phase: 'hot', - }, - { - expected: - '2 indices matching the .alerts-security.alerts-default pattern are hot. Hot indices are actively being updated and queried.', - indices: 2, - pattern: '.alerts-security.alerts-default', - phase: 'hot', - }, - { - expected: - '1 index matching the .alerts-security.alerts-default pattern is warm. Warm indices are no longer being updated but are still being queried.', - indices: 1, - pattern: '.alerts-security.alerts-default', - phase: 'warm', - }, - { - expected: - '2 indices matching the .alerts-security.alerts-default pattern are warm. Warm indices are no longer being updated but are still being queried.', - indices: 2, - pattern: '.alerts-security.alerts-default', - phase: 'warm', - }, - { - expected: - '1 index matching the .alerts-security.alerts-default pattern is cold. Cold indices are no longer being updated and are queried infrequently. The information still needs to be searchable, but it’s okay if those queries are slower.', - indices: 1, - pattern: '.alerts-security.alerts-default', - phase: 'cold', - }, - { - expected: - '2 indices matching the .alerts-security.alerts-default pattern are cold. Cold indices are no longer being updated and are queried infrequently. The information still needs to be searchable, but it’s okay if those queries are slower.', - indices: 2, - pattern: '.alerts-security.alerts-default', - phase: 'cold', - }, - { - expected: - "1 index matching the .alerts-security.alerts-default pattern is frozen. Frozen indices are no longer being updated and are queried rarely. The information still needs to be searchable, but it's okay if those queries are extremely slow.", - indices: 1, - pattern: '.alerts-security.alerts-default', - phase: 'frozen', - }, - { - expected: - "2 indices matching the .alerts-security.alerts-default pattern are frozen. Frozen indices are no longer being updated and are queried rarely. The information still needs to be searchable, but it's okay if those queries are extremely slow.", - indices: 2, - pattern: '.alerts-security.alerts-default', - phase: 'frozen', - }, - { - expected: - '1 index matching the .alerts-security.alerts-default pattern is unmanaged by Index Lifecycle Management (ILM)', - indices: 1, - pattern: '.alerts-security.alerts-default', - phase: 'unmanaged', - }, - { - expected: - '2 indices matching the .alerts-security.alerts-default pattern are unmanaged by Index Lifecycle Management (ILM)', - indices: 2, - pattern: '.alerts-security.alerts-default', - phase: 'unmanaged', - }, - { - expected: '', - indices: 1, - pattern: '.alerts-security.alerts-default', - phase: 'some-other-phase', - }, - { - expected: '', - indices: 2, - pattern: '.alerts-security.alerts-default', - phase: 'some-other-phase', - }, - ]; - - phases.forEach(({ expected, indices, pattern, phase }) => { - test(`it returns the expected description when indices is ${indices}, pattern is ${pattern}, and phase is ${phase}`, () => { - expect(getPatternIlmPhaseDescription({ indices, pattern, phase })).toBe(expected); - }); - }); - }); - - describe('getTotalPatternIncompatible', () => { - test('it returns zero when multiple indices in the results results have a count of zero', () => { - const results: Record = { - '.ds-packetbeat-8.5.3-2023.02.04-000001': { - docsCount: 1630289, - error: null, - ilmPhase: 'hot', - incompatible: 0, - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'packetbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - '.ds-packetbeat-8.6.1-2023.02.04-000001': { - docsCount: 1628343, - error: null, - ilmPhase: 'hot', - incompatible: 0, - indexName: '.ds-packetbeat-8.6.1-2023.02.04-000001', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'packetbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - }; - - expect(getTotalPatternIncompatible(results)).toEqual(0); - }); - - test("it returns the expected total when some indices have incompatible fields, but others don't", () => { - const results: Record = { - '.ds-auditbeat-8.6.1-2023.02.07-000001': { - docsCount: 18086, - error: null, - ilmPhase: 'hot', - incompatible: 0, - indexName: '.ds-auditbeat-8.6.1-2023.02.07-000001', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - 'auditbeat-custom-index-1': { - docsCount: 4, - error: null, - ilmPhase: 'unmanaged', - incompatible: 3, - indexName: 'auditbeat-custom-index-1', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - 'auditbeat-custom-empty-index-1': { - docsCount: 0, - error: null, - ilmPhase: 'unmanaged', - incompatible: 1, - indexName: 'auditbeat-custom-empty-index-1', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - }; - - expect(getTotalPatternIncompatible(results)).toEqual(4); - }); - - test('it returns the expected total when some indices have undefined incompatible counts', () => { - const results: Record = { - '.ds-auditbeat-8.6.1-2023.02.07-000001': { - docsCount: 18086, - error: null, - ilmPhase: 'hot', - incompatible: undefined, // <-- this index has an undefined `incompatible` - indexName: '.ds-auditbeat-8.6.1-2023.02.07-000001', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - 'auditbeat-custom-index-1': { - docsCount: 4, - error: null, - ilmPhase: 'unmanaged', - incompatible: 3, - indexName: 'auditbeat-custom-index-1', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - 'auditbeat-custom-empty-index-1': { - docsCount: 0, - error: null, - ilmPhase: 'unmanaged', - incompatible: 1, - indexName: 'auditbeat-custom-empty-index-1', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'auditbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }, - }; - - expect(getTotalPatternIncompatible(results)).toEqual(4); - }); - - test('it returns zero when `results` is empty', () => { - expect(getTotalPatternIncompatible({})).toEqual(0); - }); - - test('it returns undefined when `results` is undefined', () => { - expect(getTotalPatternIncompatible(undefined)).toBeUndefined(); - }); - }); - - describe('getTotalPatternIndicesChecked', () => { - test('it returns zero when `patternRollup` is undefined', () => { - expect(getTotalPatternIndicesChecked(undefined)).toEqual(0); - }); - - test('it returns zero when `patternRollup` does NOT have any results', () => { - expect(getTotalPatternIndicesChecked(auditbeatNoResults)).toEqual(0); - }); - - test('it returns the expected total when all indices in `patternRollup` have results', () => { - expect(getTotalPatternIndicesChecked(auditbeatWithAllResults)).toEqual(3); - }); - - test('it returns the expected total when some indices in `patternRollup` have errors', () => { - expect(getTotalPatternIndicesChecked(packetbeatWithSomeErrors)).toEqual(1); - }); - }); - - describe('getErrorSummary', () => { - test('it returns the expected error summary', () => { - const resultWithError: DataQualityCheckResult = { - docsCount: 1630289, - error: - 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', - ilmPhase: 'hot', - incompatible: undefined, - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - markdownComments: ['foo', 'bar', 'baz'], - pattern: 'packetbeat-*', - sameFamily: 0, - checkedAt: Date.now(), - }; - - expect(getErrorSummary(resultWithError)).toEqual({ - error: - 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - pattern: 'packetbeat-*', - }); - }); - }); - - describe('getErrorSummariesForRollup', () => { - test('it returns the expected array of `ErrorSummary` when the `PatternRollup` contains errors', () => { - expect(getErrorSummariesForRollup(packetbeatWithSomeErrors)).toEqual([ - { - error: - 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - pattern: 'packetbeat-*', - }, - ]); - }); - - test('it returns the an empty array of `ErrorSummary` when the `PatternRollup` contains all results, with NO errors', () => { - expect(getErrorSummariesForRollup(auditbeatWithAllResults)).toEqual([]); - }); - - test('it returns the an empty array of `ErrorSummary` when the `PatternRollup` has NO results', () => { - expect(getErrorSummariesForRollup(auditbeatNoResults)).toEqual([]); - }); - - test('it returns the an empty array of `ErrorSummary` when the `PatternRollup` is undefined', () => { - expect(getErrorSummariesForRollup(undefined)).toEqual([]); - }); - - test('it returns BOTH the expected (root) pattern-level error, and an index-level error when `PatternRollup` has both', () => { - const withPatternLevelError: PatternRollup = { - ...packetbeatWithSomeErrors, - error: 'This is a pattern-level error', - }; - - expect(getErrorSummariesForRollup(withPatternLevelError)).toEqual([ - { - error: 'This is a pattern-level error', - indexName: null, - pattern: 'packetbeat-*', - }, - { - error: - 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - pattern: 'packetbeat-*', - }, - ]); - }); - - test('it returns the expected (root) pattern-level error when there are no index-level results', () => { - const withPatternLevelError: PatternRollup = { - ...auditbeatNoResults, - error: 'This is a pattern-level error', - }; - - expect(getErrorSummariesForRollup(withPatternLevelError)).toEqual([ - { - error: 'This is a pattern-level error', - indexName: null, - pattern: 'auditbeat-*', - }, - ]); - }); - }); - - describe('getErrorSummaries', () => { - test('it returns an empty array when patternRollups is empty', () => { - expect(getErrorSummaries({})).toEqual([]); - }); - - test('it returns an empty array when none of the patternRollups have errors', () => { - expect( - getErrorSummaries({ - '.alerts-security.alerts-default': alertIndexNoResults, - 'auditbeat-*': auditbeatWithAllResults, - 'packetbeat-*': packetbeatNoResults, - }) - ).toEqual([]); - }); - - test('it returns the expected array of `ErrorSummary` when some of the `PatternRollup` contain errors', () => { - expect( - getErrorSummaries({ - '.alerts-security.alerts-default': alertIndexNoResults, - 'auditbeat-*': auditbeatWithAllResults, - 'packetbeat-*': packetbeatWithSomeErrors, // <-- has errors - }) - ).toEqual([ - { - error: - 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - pattern: 'packetbeat-*', - }, - ]); - }); - - test('it returns the expected array of `ErrorSummary` when there are both pattern-level and index-level errors', () => { - const withPatternLevelError: PatternRollup = { - ...auditbeatNoResults, - error: 'This is a pattern-level error', - }; - - expect( - getErrorSummaries({ - '.alerts-security.alerts-default': alertIndexNoResults, - 'auditbeat-*': withPatternLevelError, // <-- has pattern-level errors - 'packetbeat-*': packetbeatWithSomeErrors, // <-- has index-level errors - }) - ).toEqual([ - { - error: 'This is a pattern-level error', - indexName: null, - pattern: 'auditbeat-*', - }, - { - error: - 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', - indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', - pattern: 'packetbeat-*', - }, - ]); - }); - - test('it returns the expected array of `ErrorSummary` when there are just pattern-level errors', () => { - const withPatternLevelError: PatternRollup = { - ...auditbeatNoResults, - error: 'This is a pattern-level error', - }; - - expect( - getErrorSummaries({ - '.alerts-security.alerts-default': alertIndexNoResults, - 'auditbeat-*': withPatternLevelError, // <-- has pattern-level errors - 'packetbeat-*': packetbeatNoResults, - }) - ).toEqual([ - { - error: 'This is a pattern-level error', - indexName: null, - pattern: 'auditbeat-*', - }, - ]); - }); - }); - - describe('formatStorageResult', () => { - it('should correctly format the input data into a StorageResult object', () => { - const inputData: Parameters[number] = { - result: { - indexName: 'testIndex', - pattern: 'testPattern', - checkedAt: 1627545600000, - docsCount: 100, - incompatible: 3, - sameFamily: 1, - ilmPhase: 'hot', - markdownComments: ['test comments'], - error: null, - }, - report: { - batchId: 'testBatch', - isCheckAll: true, - sameFamilyFields: ['agent.type'], - unallowedMappingFields: ['event.category', 'host.name', 'source.ip'], - unallowedValueFields: ['event.category'], - sizeInBytes: 5000, - ecsVersion: '1.0.0', - indexName: 'testIndex', - indexId: 'testIndexId', - }, - partitionedFieldMetadata: mockPartitionedFieldMetadataWithSameFamily, - }; - - const expectedResult: StorageResult = { - batchId: 'testBatch', - indexName: 'testIndex', - indexPattern: 'testPattern', - isCheckAll: true, - checkedAt: 1627545600000, - docsCount: 100, - totalFieldCount: 10, - ecsFieldCount: 2, - customFieldCount: 4, - incompatibleFieldCount: 3, - incompatibleFieldMappingItems: [ - { - fieldName: 'event.category', - expectedValue: 'keyword', - actualValue: 'constant_keyword', - description: - 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy.\n`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory.\nThis field is an array. This will allow proper categorization of some events that fall in multiple categories.', - }, - { - fieldName: 'host.name', - expectedValue: 'keyword', - actualValue: 'text', - description: - 'Name of the host.\nIt can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.', - }, - { - fieldName: 'source.ip', - expectedValue: 'ip', - actualValue: 'text', - description: 'IP address of the source (IPv4 or IPv6).', - }, - ], - incompatibleFieldValueItems: [ - { - fieldName: 'event.category', - expectedValues: [ - 'authentication', - 'configuration', - 'database', - 'driver', - 'email', - 'file', - 'host', - 'iam', - 'intrusion_detection', - 'malware', - 'network', - 'package', - 'process', - 'registry', - 'session', - 'threat', - 'vulnerability', - 'web', - ], - actualValues: [{ name: 'an_invalid_category', count: 2 }], - description: - 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy.\n`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory.\nThis field is an array. This will allow proper categorization of some events that fall in multiple categories.', - }, - ], - sameFamilyFieldCount: 1, - sameFamilyFields: ['agent.type'], - sameFamilyFieldItems: [ - { - fieldName: 'agent.type', - expectedValue: 'keyword', - actualValue: 'constant_keyword', - description: - 'Type of the agent.\nThe agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', - }, - ], - unallowedMappingFields: ['event.category', 'host.name', 'source.ip'], - unallowedValueFields: ['event.category'], - sizeInBytes: 5000, - ilmPhase: 'hot', - markdownComments: ['test comments'], - ecsVersion: '1.0.0', - indexId: 'testIndexId', - error: null, - }; - - expect(formatStorageResult(inputData)).toEqual(expectedResult); - }); - }); - - describe('postStorageResult', () => { - const { fetch } = httpServiceMock.createStartContract(); - const { toasts } = notificationServiceMock.createStartContract(); - beforeEach(() => { - fetch.mockClear(); - }); - - test('it posts the result', async () => { - const storageResult = { indexName: 'test' } as unknown as StorageResult; - await postStorageResult({ - storageResult, - httpFetch: fetch, - abortController: new AbortController(), - toasts, - }); - - expect(fetch).toHaveBeenCalledWith( - '/internal/ecs_data_quality_dashboard/results', - expect.objectContaining({ - method: 'POST', - body: JSON.stringify(storageResult), - }) - ); - }); - - test('it throws error', async () => { - const storageResult = { indexName: 'test' } as unknown as StorageResult; - fetch.mockRejectedValueOnce('test-error'); - await postStorageResult({ - httpFetch: fetch, - storageResult, - abortController: new AbortController(), - toasts, - }); - expect(toasts.addError).toHaveBeenCalledWith('test-error', { title: expect.any(String) }); - }); - }); - - describe('getStorageResults', () => { - const { fetch } = httpServiceMock.createStartContract(); - const { toasts } = notificationServiceMock.createStartContract(); - beforeEach(() => { - fetch.mockClear(); - }); - - test('it gets the results', async () => { - await getStorageResults({ - httpFetch: fetch, - abortController: new AbortController(), - pattern: 'auditbeat-*', - toasts, - }); - - expect(fetch).toHaveBeenCalledWith( - '/internal/ecs_data_quality_dashboard/results_latest/auditbeat-*', - expect.objectContaining({ - method: 'GET', - }) - ); - }); - - it('should catch error', async () => { - fetch.mockRejectedValueOnce('test-error'); - - const results = await getStorageResults({ - httpFetch: fetch, - abortController: new AbortController(), - pattern: 'auditbeat-*', - toasts, - }); - - expect(toasts.addError).toHaveBeenCalledWith('test-error', { title: expect.any(String) }); - expect(results).toEqual([]); - }); - }); -}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.ts deleted file mode 100644 index 9a56e00ba547a..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/helpers.ts +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { HttpHandler } from '@kbn/core-http-browser'; -import type { IlmExplainLifecycleLifecycleExplain } from '@elastic/elasticsearch/lib/api/types'; -import { has, sortBy } from 'lodash/fp'; -import { IToasts } from '@kbn/core-notifications-browser'; -import { getIlmPhase } from './data_quality_panel/pattern/helpers'; - -import * as i18n from './translations'; - -import type { - DataQualityCheckResult, - DataQualityIndexCheckedParams, - EcsBasedFieldMetadata, - EnrichedFieldMetadata, - ErrorSummary, - IlmPhase, - IncompatibleFieldMappingItem, - IncompatibleFieldValueItem, - MeteringStatsIndex, - PartitionedFieldMetadata, - PartitionedFieldMetadataStats, - PatternRollup, - SameFamilyFieldItem, - UnallowedValueCount, -} from './types'; -import { EcsFlatTyped } from './constants'; - -const EMPTY_INDEX_NAMES: string[] = []; -export const INTERNAL_API_VERSION = '1'; -export const getIndexNames = ({ - ilmExplain, - ilmPhases, - isILMAvailable, - stats, -}: { - ilmExplain: Record | null; - ilmPhases: string[]; - isILMAvailable: boolean; - stats: Record | null; -}): string[] => { - if (((isILMAvailable && ilmExplain != null) || !isILMAvailable) && stats != null) { - const allIndexNames = Object.keys(stats); - const filteredByIlmPhase = isILMAvailable - ? allIndexNames.filter((indexName) => - ilmPhases.includes(getIlmPhase(ilmExplain?.[indexName], isILMAvailable) ?? '') - ) - : allIndexNames; - - return filteredByIlmPhase; - } else { - return EMPTY_INDEX_NAMES; - } -}; - -export interface FieldType { - field: string; - type: string; -} - -function shouldReadKeys(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} - -const getNextPathWithoutProperties = ({ - key, - pathWithoutProperties, - value, -}: { - key: string; - pathWithoutProperties: string; - value: unknown; -}): string => { - if (!pathWithoutProperties) { - return key; - } - - if (shouldReadKeys(value) && (key === 'properties' || key === 'fields')) { - return `${pathWithoutProperties}`; - } else { - return `${pathWithoutProperties}.${key}`; - } -}; - -export function getFieldTypes(mappingsProperties: Record): FieldType[] { - if (!shouldReadKeys(mappingsProperties)) { - throw new TypeError(`Root value is not flatten-able, received ${mappingsProperties}`); - } - - const result: FieldType[] = []; - (function flatten(prefix, object, pathWithoutProperties) { - for (const [key, value] of Object.entries(object)) { - const path = prefix ? `${prefix}.${key}` : key; - - const nextPathWithoutProperties = getNextPathWithoutProperties({ - key, - pathWithoutProperties, - value, - }); - - if (shouldReadKeys(value)) { - flatten(path, value, nextPathWithoutProperties); - } else { - if (nextPathWithoutProperties.endsWith('.type')) { - const pathWithoutType = nextPathWithoutProperties.slice( - 0, - nextPathWithoutProperties.lastIndexOf('.type') - ); - - result.push({ - field: pathWithoutType, - type: `${value}`, - }); - } - } - } - })('', mappingsProperties, ''); - - return result; -} - -/** - * Per https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html#_core_datatypes - * - * ``` - * Field types are grouped by _family_. Types in the same family have exactly - * the same search behavior but may have different space usage or - * performance characteristics. - * - * Currently, there are two type families, `keyword` and `text`. Other type - * families have only a single field type. For example, the `boolean` type - * family consists of one field type: `boolean`. - * ``` - */ -export const fieldTypeFamilies: Record> = { - keyword: new Set(['keyword', 'constant_keyword', 'wildcard']), - text: new Set(['text', 'match_only_text']), -}; - -export const getIsInSameFamily = ({ - ecsExpectedType, - type, -}: { - ecsExpectedType: string | undefined; - type: string; -}): boolean => { - if (ecsExpectedType != null) { - const allFamilies = Object.values(fieldTypeFamilies); - - return allFamilies.reduce( - (acc, family) => (acc !== true ? family.has(ecsExpectedType) && family.has(type) : acc), - false - ); - } else { - return false; - } -}; - -export const isMappingCompatible = ({ - ecsExpectedType, - type, -}: { - ecsExpectedType: string | undefined; - type: string; -}): boolean => type === ecsExpectedType; - -export const getEnrichedFieldMetadata = ({ - ecsMetadata, - fieldMetadata, - unallowedValues, -}: { - ecsMetadata: EcsFlatTyped; - fieldMetadata: FieldType; - unallowedValues: Record; -}): EnrichedFieldMetadata => { - const { field, type } = fieldMetadata; - const indexInvalidValues = unallowedValues[field] ?? []; - - if (has(fieldMetadata.field, ecsMetadata)) { - const ecsExpectedType = ecsMetadata[field].type; - const isEcsCompliant = - isMappingCompatible({ ecsExpectedType, type }) && indexInvalidValues.length === 0; - - const isInSameFamily = - !isMappingCompatible({ ecsExpectedType, type }) && - indexInvalidValues.length === 0 && - getIsInSameFamily({ ecsExpectedType, type }); - - return { - ...ecsMetadata[field], - indexFieldName: field, - indexFieldType: type, - indexInvalidValues, - hasEcsMetadata: true, - isEcsCompliant, - isInSameFamily, - }; - } else { - return { - indexFieldName: field, - indexFieldType: type, - indexInvalidValues: [], - hasEcsMetadata: false, - isEcsCompliant: false, - isInSameFamily: false, // custom fields are never in the same family - }; - } -}; - -export const getMissingTimestampFieldMetadata = (): EcsBasedFieldMetadata => ({ - ...EcsFlatTyped['@timestamp'], - hasEcsMetadata: true, - indexFieldName: '@timestamp', - indexFieldType: '-', - indexInvalidValues: [], - isEcsCompliant: false, - isInSameFamily: false, // `date` is not a member of any families -}); - -export const getPartitionedFieldMetadata = ( - enrichedFieldMetadata: EnrichedFieldMetadata[] -): PartitionedFieldMetadata => - enrichedFieldMetadata.reduce( - (acc, x) => ({ - all: [...acc.all, x], - ecsCompliant: x.isEcsCompliant ? [...acc.ecsCompliant, x] : acc.ecsCompliant, - custom: !x.hasEcsMetadata ? [...acc.custom, x] : acc.custom, - incompatible: - x.hasEcsMetadata && !x.isEcsCompliant && !x.isInSameFamily - ? [...acc.incompatible, x] - : acc.incompatible, - sameFamily: x.isInSameFamily ? [...acc.sameFamily, x] : acc.sameFamily, - }), - { - all: [], - ecsCompliant: [], - custom: [], - incompatible: [], - sameFamily: [], - } - ); - -export const getPartitionedFieldMetadataStats = ( - partitionedFieldMetadata: PartitionedFieldMetadata -): PartitionedFieldMetadataStats => { - const { all, ecsCompliant, custom, incompatible, sameFamily } = partitionedFieldMetadata; - - return { - all: all.length, - ecsCompliant: ecsCompliant.length, - custom: custom.length, - incompatible: incompatible.length, - sameFamily: sameFamily.length, - }; -}; - -export const getDocsCount = ({ - indexName, - stats, -}: { - indexName: string; - stats: Record | null; -}): number => (stats && stats[indexName]?.num_docs) ?? 0; - -export const getIndexId = ({ - indexName, - stats, -}: { - indexName: string; - stats: Record | null; -}): string | null | undefined => stats && stats[indexName]?.uuid; - -export const getSizeInBytes = ({ - indexName, - stats, -}: { - indexName: string; - stats: Record | null; -}): number | undefined => (stats && stats[indexName]?.size_in_bytes) ?? undefined; - -export const getTotalDocsCount = ({ - indexNames, - stats, -}: { - indexNames: string[]; - stats: Record | null; -}): number => - indexNames.reduce( - (acc: number, indexName: string) => acc + getDocsCount({ stats, indexName }), - 0 - ); - -export const getTotalSizeInBytes = ({ - indexNames, - stats, -}: { - indexNames: string[]; - stats: Record | null; -}): number | undefined => { - let sum; - for (let i = 0; i < indexNames.length; i++) { - const currentSizeInBytes = getSizeInBytes({ stats, indexName: indexNames[i] }); - if (currentSizeInBytes != null) { - if (sum == null) { - sum = 0; - } - sum += currentSizeInBytes; - } else { - return undefined; - } - } - return sum; -}; - -export const EMPTY_STAT = '--'; - -/** - * Returns an i18n description of an an ILM phase - */ -export const getIlmPhaseDescription = (phase: string): string => { - switch (phase) { - case 'hot': - return i18n.HOT_DESCRIPTION; - case 'warm': - return i18n.WARM_DESCRIPTION; - case 'cold': - return i18n.COLD_DESCRIPTION; - case 'frozen': - return i18n.FROZEN_DESCRIPTION; - case 'unmanaged': - return i18n.UNMANAGED_DESCRIPTION; - default: - return ' '; - } -}; - -export const getPatternIlmPhaseDescription = ({ - indices, - pattern, - phase, -}: { - indices: number; - pattern: string; - phase: string; -}): string => { - switch (phase) { - case 'hot': - return i18n.HOT_PATTERN_TOOLTIP({ indices, pattern }); - case 'warm': - return i18n.WARM_PATTERN_TOOLTIP({ indices, pattern }); - case 'cold': - return i18n.COLD_PATTERN_TOOLTIP({ indices, pattern }); - case 'frozen': - return i18n.FROZEN_PATTERN_TOOLTIP({ indices, pattern }); - case 'unmanaged': - return i18n.UNMANAGED_PATTERN_TOOLTIP({ indices, pattern }); - default: - return ''; - } -}; - -export const getTotalPatternIncompatible = ( - results: Record | undefined -): number | undefined => { - if (results == null) { - return undefined; - } - - const allResults = Object.values(results); - - return allResults.reduce((acc, { incompatible }) => acc + (incompatible ?? 0), 0); -}; - -export const getTotalPatternIndicesChecked = (patternRollup: PatternRollup | undefined): number => { - if (patternRollup != null && patternRollup.results != null) { - const allResults = Object.values(patternRollup.results); - const nonErrorResults = allResults.filter(({ error }) => error == null); - - return nonErrorResults.length; - } else { - return 0; - } -}; - -export const getTotalPatternSameFamily = ( - results: Record | undefined -): number | undefined => { - if (results == null) { - return undefined; - } - - const allResults = Object.values(results); - - return allResults.reduce((acc, { sameFamily }) => acc + (sameFamily ?? 0), 0); -}; - -export const getIncompatibleStatBadgeColor = (incompatible: number | undefined): string => - incompatible != null && incompatible > 0 ? 'danger' : 'hollow'; - -export const getErrorSummary = ({ - error, - indexName, - pattern, -}: DataQualityCheckResult): ErrorSummary => ({ - error: String(error), - indexName, - pattern, -}); - -export const getErrorSummariesForRollup = ( - patternRollup: PatternRollup | undefined -): ErrorSummary[] => { - const maybePatternErrorSummary: ErrorSummary[] = - patternRollup != null && patternRollup.error != null - ? [{ pattern: patternRollup.pattern, indexName: null, error: patternRollup.error }] - : []; - - if (patternRollup != null && patternRollup.results != null) { - const unsortedResults: DataQualityCheckResult[] = Object.values(patternRollup.results); - const sortedResults = sortBy('indexName', unsortedResults); - - return sortedResults.reduce( - (acc, result) => [...acc, ...(result.error != null ? [getErrorSummary(result)] : [])], - maybePatternErrorSummary - ); - } else { - return maybePatternErrorSummary; - } -}; - -export const getErrorSummaries = ( - patternRollups: Record -): ErrorSummary[] => { - const allPatterns: string[] = Object.keys(patternRollups); - - // sort the patterns A-Z: - const sortedPatterns = [...allPatterns].sort((a, b) => { - return a.localeCompare(b); - }); - - return sortedPatterns.reduce( - (acc, pattern) => [...acc, ...getErrorSummariesForRollup(patternRollups[pattern])], - [] - ); -}; - -export const POST_INDEX_RESULTS = '/internal/ecs_data_quality_dashboard/results'; -export const GET_INDEX_RESULTS_LATEST = - '/internal/ecs_data_quality_dashboard/results_latest/{pattern}'; - -export interface StorageResult { - batchId: string; - indexName: string; - indexPattern: string; - isCheckAll: boolean; - checkedAt: number; - docsCount: number; - totalFieldCount: number; - ecsFieldCount: number; - customFieldCount: number; - incompatibleFieldCount: number; - incompatibleFieldMappingItems: IncompatibleFieldMappingItem[]; - incompatibleFieldValueItems: IncompatibleFieldValueItem[]; - sameFamilyFieldCount: number; - sameFamilyFields: string[]; - sameFamilyFieldItems: SameFamilyFieldItem[]; - unallowedMappingFields: string[]; - unallowedValueFields: string[]; - sizeInBytes: number; - ilmPhase?: IlmPhase; - markdownComments: string[]; - ecsVersion: string; - indexId: string; - error: string | null; -} - -export const formatStorageResult = ({ - result, - report, - partitionedFieldMetadata, -}: { - result: DataQualityCheckResult; - report: DataQualityIndexCheckedParams; - partitionedFieldMetadata: PartitionedFieldMetadata; -}): StorageResult => { - const incompatibleFieldMappingItems: IncompatibleFieldMappingItem[] = []; - const incompatibleFieldValueItems: IncompatibleFieldValueItem[] = []; - const sameFamilyFieldItems: SameFamilyFieldItem[] = []; - - partitionedFieldMetadata.incompatible.forEach((field) => { - if (field.type !== field.indexFieldType) { - incompatibleFieldMappingItems.push({ - fieldName: field.indexFieldName, - expectedValue: field.type, - actualValue: field.indexFieldType, - description: field.description, - }); - } - - if (field.indexInvalidValues.length > 0) { - incompatibleFieldValueItems.push({ - fieldName: field.indexFieldName, - expectedValues: field.allowed_values?.map((x) => x.name) ?? [], - actualValues: field.indexInvalidValues.map((v) => ({ name: v.fieldName, count: v.count })), - description: field.description, - }); - } - }); - - partitionedFieldMetadata.sameFamily.forEach((field) => { - sameFamilyFieldItems.push({ - fieldName: field.indexFieldName, - expectedValue: field.type, - actualValue: field.indexFieldType, - description: field.description, - }); - }); - - return { - batchId: report.batchId, - indexName: result.indexName, - indexPattern: result.pattern, - isCheckAll: report.isCheckAll, - checkedAt: result.checkedAt ?? Date.now(), - docsCount: result.docsCount ?? 0, - totalFieldCount: partitionedFieldMetadata.all.length, - ecsFieldCount: partitionedFieldMetadata.ecsCompliant.length, - customFieldCount: partitionedFieldMetadata.custom.length, - incompatibleFieldCount: partitionedFieldMetadata.incompatible.length, - incompatibleFieldMappingItems, - incompatibleFieldValueItems, - sameFamilyFieldCount: partitionedFieldMetadata.sameFamily.length, - sameFamilyFields: report.sameFamilyFields ?? [], - sameFamilyFieldItems, - unallowedMappingFields: report.unallowedMappingFields ?? [], - unallowedValueFields: report.unallowedValueFields ?? [], - sizeInBytes: report.sizeInBytes ?? 0, - ilmPhase: result.ilmPhase, - markdownComments: result.markdownComments, - ecsVersion: report.ecsVersion, - indexId: report.indexId ?? '', - error: result.error, - }; -}; - -export const formatResultFromStorage = ({ - storageResult, - pattern, -}: { - storageResult: StorageResult; - pattern: string; -}): DataQualityCheckResult => ({ - docsCount: storageResult.docsCount, - error: storageResult.error, - ilmPhase: storageResult.ilmPhase, - incompatible: storageResult.incompatibleFieldCount, - indexName: storageResult.indexName, - markdownComments: storageResult.markdownComments, - sameFamily: storageResult.sameFamilyFieldCount, - checkedAt: storageResult.checkedAt, - pattern, -}); - -export async function postStorageResult({ - storageResult, - httpFetch, - toasts, - abortController = new AbortController(), -}: { - storageResult: StorageResult; - httpFetch: HttpHandler; - toasts: IToasts; - abortController?: AbortController; -}): Promise { - try { - await httpFetch(POST_INDEX_RESULTS, { - method: 'POST', - signal: abortController.signal, - version: INTERNAL_API_VERSION, - body: JSON.stringify(storageResult), - }); - } catch (err) { - toasts.addError(err, { title: i18n.POST_RESULT_ERROR_TITLE }); - } -} - -export async function getStorageResults({ - pattern, - httpFetch, - toasts, - abortController, -}: { - pattern: string; - httpFetch: HttpHandler; - toasts: IToasts; - abortController: AbortController; -}): Promise { - try { - const route = GET_INDEX_RESULTS_LATEST.replace('{pattern}', pattern); - const results = await httpFetch(route, { - method: 'GET', - signal: abortController.signal, - version: INTERNAL_API_VERSION, - }); - return results; - } catch (err) { - toasts.addError(err, { title: i18n.GET_RESULTS_ERROR_TITLE }); - return []; - } -} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.test.tsx deleted file mode 100644 index 53d576ccf6f70..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.test.tsx +++ /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 { DARK_THEME } from '@elastic/charts'; -import { render, screen } from '@testing-library/react'; -import React from 'react'; - -import { TestExternalProviders } from './mock/test_providers/test_providers'; -import { DataQualityPanel } from '.'; -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; - -const { toasts } = notificationServiceMock.createSetupContract(); - -describe('DataQualityPanel', () => { - beforeEach(() => { - render( - - - - ); - }); - - test('it renders the body', () => { - expect(screen.getByTestId('body')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/index.test.tsx deleted file mode 100644 index 86b3ef1688e6a..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/index.test.tsx +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import React, { FC, PropsWithChildren } from 'react'; - -import { DataQualityProvider } from '../data_quality_panel/data_quality_context'; -import { mockMappingsResponse } from '../mock/mappings_response/mock_mappings_response'; -import { ERROR_LOADING_MAPPINGS } from '../translations'; -import { useMappings, UseMappings } from '.'; -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -import { Theme } from '@elastic/charts'; - -const mockHttpFetch = jest.fn(); -const mockReportDataQualityIndexChecked = jest.fn(); -const mockReportDataQualityCheckAllClicked = jest.fn(); -const mockTelemetryEvents = { - reportDataQualityIndexChecked: mockReportDataQualityIndexChecked, - reportDataQualityCheckAllCompleted: mockReportDataQualityCheckAllClicked, -}; -const { toasts } = notificationServiceMock.createSetupContract(); - -const ContextWrapper: FC> = ({ children }) => ( - true)} - endDate={null} - formatBytes={jest.fn()} - formatNumber={jest.fn()} - isAssistantEnabled={true} - lastChecked={'2023-03-28T22:27:28.159Z'} - openCreateCaseFlyout={jest.fn()} - patterns={['auditbeat-*']} - setLastChecked={jest.fn()} - startDate={null} - theme={{ - background: { - color: '#000', - }, - }} - baseTheme={ - { - background: { - color: '#000', - }, - } as Theme - } - ilmPhases={['hot', 'warm', 'unmanaged']} - selectedIlmPhaseOptions={[ - { - label: 'Hot', - value: 'hot', - }, - { - label: 'Warm', - value: 'warm', - }, - { - label: 'Unmanaged', - value: 'unmanaged', - }, - ]} - setSelectedIlmPhaseOptions={jest.fn()} - > - {children} - -); - -const pattern = 'auditbeat-*'; - -describe('useMappings', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe('successful response from the mappings api', () => { - let mappingsResult: UseMappings | undefined; - - beforeEach(async () => { - mockHttpFetch.mockResolvedValue(mockMappingsResponse); - - const { result, waitForNextUpdate } = renderHook(() => useMappings(pattern), { - wrapper: ContextWrapper, - }); - await waitForNextUpdate(); - mappingsResult = await result.current; - }); - - test('it returns the expected mappings', async () => { - expect(mappingsResult?.indexes).toEqual(mockMappingsResponse); - }); - - test('it returns loading: false, because the data has loaded', async () => { - expect(mappingsResult?.loading).toBe(false); - }); - - test('it returns a null error, because no errors occurred', async () => { - expect(mappingsResult?.error).toBeNull(); - }); - }); - - describe('fetch rejects with an error', () => { - let mappingsResult: UseMappings | undefined; - const errorMessage = 'simulated error'; - - beforeEach(async () => { - mockHttpFetch.mockRejectedValue(new Error(errorMessage)); - - const { result, waitForNextUpdate } = renderHook(() => useMappings(pattern), { - wrapper: ContextWrapper, - }); - await waitForNextUpdate(); - mappingsResult = await result.current; - }); - - test('it returns null mappings, because an error occurred', async () => { - expect(mappingsResult?.indexes).toBeNull(); - }); - - test('it returns loading: false, because data loading reached a terminal state', async () => { - expect(mappingsResult?.loading).toBe(false); - }); - - test('it returns the expected error', async () => { - expect(mappingsResult?.error).toEqual( - ERROR_LOADING_MAPPINGS({ details: errorMessage, patternOrIndexName: pattern }) - ); - }); - }); -}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/index.tsx deleted file mode 100644 index f20809a248086..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/index.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; -import { useEffect, useState } from 'react'; - -import { useDataQualityContext } from '../data_quality_panel/data_quality_context'; -import { fetchMappings } from './helpers'; -import { useIsMounted } from '../use_is_mounted'; - -export interface UseMappings { - indexes: Record | null; - error: string | null; - loading: boolean; -} - -export const useMappings = (patternOrIndexName: string): UseMappings => { - const { isMountedRef } = useIsMounted(); - const [indexes, setIndexes] = useState | null>(null); - const { httpFetch } = useDataQualityContext(); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - const abortController = new AbortController(); - - async function fetchData() { - try { - const response = await fetchMappings({ abortController, httpFetch, patternOrIndexName }); - - if (!abortController.signal.aborted) { - if (isMountedRef.current) { - setIndexes(response); - } - } - } catch (e) { - if (!abortController.signal.aborted) { - if (isMountedRef.current) { - setError(e.message); - } - } - } finally { - if (!abortController.signal.aborted) { - if (isMountedRef.current) { - setLoading(false); - } - } - } - } - - fetchData(); - - return () => { - abortController.abort(); - }; - }, [httpFetch, isMountedRef, patternOrIndexName, setError]); - - return { indexes, error, loading }; -}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/types.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/types.ts deleted file mode 100644 index e8f0124cd4a3f..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/types.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { OnCheckCompleted, PatternRollup } from '../types'; - -export interface UseResultsRollupReturnValue { - onCheckCompleted: OnCheckCompleted; - patternIndexNames: Record; - patternRollups: Record; - totalDocsCount: number | undefined; - totalIncompatible: number | undefined; - totalIndices: number | undefined; - totalIndicesChecked: number | undefined; - totalSameFamily: number | undefined; - totalSizeInBytes: number | undefined; - updatePatternIndexNames: ({ - indexNames, - pattern, - }: { - indexNames: string[]; - pattern: string; - }) => void; - updatePatternRollup: (patternRollup: PatternRollup) => void; -} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/index.test.tsx deleted file mode 100644 index d2d216fd12293..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/index.test.tsx +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import React, { FC, PropsWithChildren } from 'react'; - -import { getUnallowedValueRequestItems } from '../data_quality_panel/allowed_values/helpers'; -import { DataQualityProvider } from '../data_quality_panel/data_quality_context'; -import { mockUnallowedValuesResponse } from '../mock/unallowed_values/mock_unallowed_values'; -import { ERROR_LOADING_UNALLOWED_VALUES } from '../translations'; -import { UnallowedValueRequestItem } from '../types'; -import { useUnallowedValues, UseUnallowedValues } from '.'; -import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; -import { EcsFlatTyped } from '../constants'; -import { Theme } from '@elastic/charts'; - -const mockHttpFetch = jest.fn(); -const mockReportDataQualityIndexChecked = jest.fn(); -const mockReportDataQualityCheckAllClicked = jest.fn(); -const mockTelemetryEvents = { - reportDataQualityIndexChecked: mockReportDataQualityIndexChecked, - reportDataQualityCheckAllCompleted: mockReportDataQualityCheckAllClicked, -}; -const { toasts } = notificationServiceMock.createSetupContract(); - -const ContextWrapper: FC> = ({ children }) => ( - true)} - endDate={null} - formatBytes={jest.fn()} - formatNumber={jest.fn()} - isAssistantEnabled={true} - lastChecked={'2023-03-28T22:27:28.159Z'} - openCreateCaseFlyout={jest.fn()} - patterns={['auditbeat-*']} - setLastChecked={jest.fn()} - startDate={null} - theme={{ - background: { - color: '#000', - }, - }} - baseTheme={ - { - background: { - color: '#000', - }, - } as Theme - } - ilmPhases={['hot', 'warm', 'unmanaged']} - selectedIlmPhaseOptions={[ - { - label: 'Hot', - value: 'hot', - }, - { - label: 'Warm', - value: 'warm', - }, - { - label: 'Unmanaged', - value: 'unmanaged', - }, - ]} - setSelectedIlmPhaseOptions={jest.fn()} - > - {children} - -); - -const indexName = 'auditbeat-custom-index-1'; -const requestItems = getUnallowedValueRequestItems({ - ecsMetadata: EcsFlatTyped, - indexName, -}); - -describe('useUnallowedValues', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe('when requestItems is empty', () => { - const emptyRequestItems: UnallowedValueRequestItem[] = []; - - test('it does NOT make an http request', async () => { - await renderHook( - () => - useUnallowedValues({ - indexName, - requestItems: emptyRequestItems, // <-- empty - }), - { - wrapper: ContextWrapper, - } - ); - - expect(mockHttpFetch).not.toBeCalled(); - }); - }); - - describe('successful response from the unallowed values api', () => { - let unallowedValuesResult: UseUnallowedValues | undefined; - - beforeEach(async () => { - mockHttpFetch.mockResolvedValue(mockUnallowedValuesResponse); - - const { result, waitForNextUpdate } = renderHook( - () => useUnallowedValues({ indexName, requestItems }), - { - wrapper: ContextWrapper, - } - ); - await waitForNextUpdate(); - unallowedValuesResult = await result.current; - }); - - test('it returns the expected unallowed values', async () => { - expect(unallowedValuesResult?.unallowedValues).toEqual({ - 'event.category': [ - { count: 2, fieldName: 'an_invalid_category' }, - { count: 1, fieldName: 'theory' }, - ], - 'event.kind': [], - 'event.outcome': [], - 'event.type': [], - }); - }); - - test('it returns loading: false, because the data has loaded', async () => { - expect(unallowedValuesResult?.loading).toBe(false); - }); - - test('it returns a null error, because no errors occurred', async () => { - expect(unallowedValuesResult?.error).toBeNull(); - }); - }); - - describe('fetch rejects with an error', () => { - let unallowedValuesResult: UseUnallowedValues | undefined; - const errorMessage = 'simulated error'; - - beforeEach(async () => { - mockHttpFetch.mockRejectedValue(new Error(errorMessage)); - - const { result, waitForNextUpdate } = renderHook( - () => useUnallowedValues({ indexName, requestItems }), - { - wrapper: ContextWrapper, - } - ); - await waitForNextUpdate(); - unallowedValuesResult = await result.current; - }); - - test('it returns null unallowed values, because an error occurred', async () => { - expect(unallowedValuesResult?.unallowedValues).toBeNull(); - }); - - test('it returns loading: false, because data loading reached a terminal state', async () => { - expect(unallowedValuesResult?.loading).toBe(false); - }); - - test('it returns the expected error', async () => { - expect(unallowedValuesResult?.error).toEqual( - ERROR_LOADING_UNALLOWED_VALUES({ details: errorMessage, indexName }) - ); - }); - }); -}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/index.tsx deleted file mode 100644 index 7f35da714ecd9..0000000000000 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/index.tsx +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useEffect, useState } from 'react'; - -import { useDataQualityContext } from '../data_quality_panel/data_quality_context'; -import { fetchUnallowedValues, getUnallowedValues } from './helpers'; -import type { UnallowedValueCount, UnallowedValueRequestItem } from '../types'; -import { useIsMounted } from '../use_is_mounted'; - -export interface UseUnallowedValues { - unallowedValues: Record | null; - error: string | null; - loading: boolean; - requestTime: number | undefined; -} - -export const useUnallowedValues = ({ - indexName, - requestItems, -}: { - indexName: string; - requestItems: UnallowedValueRequestItem[]; -}): UseUnallowedValues => { - const { isMountedRef } = useIsMounted(); - const [unallowedValues, setUnallowedValues] = useState | null>(null); - const { httpFetch } = useDataQualityContext(); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - const [requestTime, setRequestTime] = useState(); - useEffect(() => { - if (requestItems.length === 0) { - return; - } - - const abortController = new AbortController(); - - async function fetchData() { - const startTime = Date.now(); - - try { - const searchResults = await fetchUnallowedValues({ - abortController, - httpFetch, - indexName, - requestItems, - }); - - const unallowedValuesMap = getUnallowedValues({ - requestItems, - searchResults, - }); - - if (!abortController.signal.aborted) { - if (isMountedRef.current) { - setUnallowedValues(unallowedValuesMap); - } - } - } catch (e) { - if (!abortController.signal.aborted) { - if (isMountedRef.current) { - setError(e.message); - setRequestTime(Date.now() - startTime); - } - } - } finally { - if (!abortController.signal.aborted) { - if (isMountedRef.current) { - setLoading(false); - setRequestTime(Date.now() - startTime); - } - } - } - } - - fetchData(); - - return () => { - abortController.abort(); - }; - }, [httpFetch, indexName, isMountedRef, requestItems, setError]); - - return { unallowedValues, error, loading, requestTime }; -}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_add_to_new_case/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/hooks/use_add_to_new_case/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_add_to_new_case/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/hooks/use_add_to_new_case/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_add_to_new_case/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/hooks/use_add_to_new_case/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_add_to_new_case/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/hooks/use_add_to_new_case/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/add_to_new_case/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/index.test.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/add_to_new_case/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/index.test.tsx index 1fec0d39fbfd0..ba4aee43c32c7 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/add_to_new_case/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/index.test.tsx @@ -12,7 +12,7 @@ import { AddToNewCaseAction } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; +} from '../../mock/test_providers/test_providers'; import userEvent from '@testing-library/user-event'; describe('AddToNewCaseAction', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/add_to_new_case/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/index.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/add_to_new_case/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/index.tsx index 537f5b13a0f08..93d5b7ba7e20b 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/add_to_new_case/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/add_to_new_case/index.tsx @@ -9,9 +9,9 @@ import React, { useCallback } from 'react'; import { EuiIcon, EuiLink } from '@elastic/eui'; import { useDataQualityContext } from '../../data_quality_context'; -import { useAddToNewCase } from '../../../use_add_to_new_case'; +import { useAddToNewCase } from './hooks/use_add_to_new_case'; import { StyledLinkText } from '../styles'; -import { ADD_TO_NEW_CASE } from '../../../translations'; +import { ADD_TO_NEW_CASE } from '../../translations'; interface Props { markdownComment: string; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.test.tsx similarity index 93% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.test.tsx index 8d706aad92f1f..33e52a398e3c9 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.test.tsx @@ -12,7 +12,7 @@ import { ChatAction } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; +} from '../../mock/test_providers/test_providers'; describe('ChatAction', () => { it('should render new chat link', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx index ca37bcaad97d5..fb990fc295bbf 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/index.tsx @@ -14,7 +14,7 @@ import { DATA_QUALITY_PROMPT_CONTEXT_PILL, DATA_QUALITY_PROMPT_CONTEXT_PILL_TOOLTIP, DATA_QUALITY_SUGGESTED_USER_PROMPT, -} from '../../../translations'; +} from '../../translations'; import { useDataQualityContext } from '../../data_quality_context'; import { ASK_ASSISTANT } from './translations'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/chat/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/chat/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/copy_to_clipboard/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/copy_to_clipboard/index.test.tsx similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/copy_to_clipboard/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/copy_to_clipboard/index.test.tsx index 6e2147293237a..05a44639b08ec 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/copy_to_clipboard/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/copy_to_clipboard/index.test.tsx @@ -14,7 +14,7 @@ import { CopyToClipboardAction } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; +} from '../../mock/test_providers/test_providers'; jest.mock('@elastic/eui', () => { const original = jest.requireActual('@elastic/eui'); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/copy_to_clipboard/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/copy_to_clipboard/index.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/copy_to_clipboard/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/copy_to_clipboard/index.tsx index abf85203a0db1..23df7dd8ad88e 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/copy_to_clipboard/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/copy_to_clipboard/index.tsx @@ -9,7 +9,7 @@ import React, { useCallback } from 'react'; import { EuiIcon, EuiLink, copyToClipboard } from '@elastic/eui'; import { useDataQualityContext } from '../../data_quality_context'; -import { COPIED_RESULTS_TOAST_TITLE, COPY_TO_CLIPBOARD } from '../../../translations'; +import { COPIED_RESULTS_TOAST_TITLE, COPY_TO_CLIPBOARD } from '../../translations'; import { StyledLinkText } from '../styles'; interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/index.test.tsx similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/index.test.tsx index 55f32280ddb9d..8d3d5954c7a9e 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/index.test.tsx @@ -12,7 +12,7 @@ import { Actions } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../mock/test_providers/test_providers'; +} from '../mock/test_providers/test_providers'; describe('Actions', () => { it('renders nothing by default', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/styles.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/styles.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/actions/styles.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/actions/styles.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/constants.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/constants.ts similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/constants.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/constants.ts index c89c4dc5daa15..26fe2698f077c 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/constants.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/constants.ts @@ -38,3 +38,7 @@ export const ilmPhaseOptionsStatic: EuiComboBoxOptionOption[] = [ value: 'unmanaged', }, ]; + +export const EMPTY_STAT = '--'; + +export const INTERNAL_API_VERSION = '1'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/contexts/indices_check_context/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/contexts/indices_check_context/index.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/contexts/indices_check_context/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/contexts/indices_check_context/index.tsx index d6ecacf09ac4e..48863a25e2431 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/contexts/indices_check_context/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/contexts/indices_check_context/index.tsx @@ -7,7 +7,7 @@ import { createContext, useContext } from 'react'; -import { UseIndicesCheckReturnValue } from '../../use_indices_check/types'; +import { UseIndicesCheckReturnValue } from '../../hooks/use_indices_check/types'; export const IndicesCheckContext = createContext(null); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/contexts/results_rollup_context/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/contexts/results_rollup_context/index.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/contexts/results_rollup_context/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/contexts/results_rollup_context/index.tsx index 7771a06fbf7f8..d60c933768153 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/contexts/results_rollup_context/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/contexts/results_rollup_context/index.tsx @@ -7,7 +7,7 @@ import { createContext, useContext } from 'react'; -import { UseResultsRollupReturnValue } from '../../use_results_rollup/types'; +import { UseResultsRollupReturnValue } from '../../hooks/use_results_rollup/types'; export const ResultsRollupContext = createContext(null); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_context/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.test.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_context/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.test.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_context/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_context/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx index 06620ecacd04d..762efef424a10 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_context/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_context/index.tsx @@ -12,7 +12,7 @@ import type { IToasts } from '@kbn/core-notifications-browser'; import { PartialTheme, Theme } from '@elastic/charts'; import { EuiComboBoxOptionOption } from '@elastic/eui'; -import type { TelemetryEvents } from '../../types'; +import type { TelemetryEvents } from '../types'; export interface DataQualityProviderProps { httpFetch: HttpHandler; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/index.test.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/index.test.tsx index 329ff56cd8326..a20e279e6ac19 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/index.test.tsx @@ -8,7 +8,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import { TestExternalProviders } from '../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../mock/test_providers/test_providers'; import { IlmPhasesEmptyPrompt } from '.'; describe('IlmPhasesEmptyPrompt', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/index.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/index.tsx index 1720da6df8be0..c8a6e7385a122 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/index.tsx @@ -15,7 +15,7 @@ import { HOT_DESCRIPTION, UNMANAGED_DESCRIPTION, WARM_DESCRIPTION, -} from '../translations'; +} from '../../translations'; import * as i18n from './translations'; const Ul = styled.ul` diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/ilm_phases_empty_prompt/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/ilm_phases_empty_prompt/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/index.test.tsx similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/index.test.tsx index 399b5705d028d..dfe943215f909 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/index.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; +} from '../mock/test_providers/test_providers'; import { DataQualityDetails } from '.'; const ilmPhases = ['hot', 'warm', 'unmanaged']; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/index.tsx similarity index 86% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/index.tsx index 8f8686f0c03b2..a880d2a7d4f16 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/index.tsx @@ -7,11 +7,11 @@ import React, { useCallback, useState } from 'react'; -import { IlmPhasesEmptyPrompt } from '../../../ilm_phases_empty_prompt'; +import { IlmPhasesEmptyPrompt } from './ilm_phases_empty_prompt'; import { IndicesDetails } from './indices_details'; import { StorageDetails } from './storage_details'; -import { SelectedIndex } from '../../../types'; -import { useDataQualityContext } from '../../data_quality_context'; +import { SelectedIndex } from '../types'; +import { useDataQualityContext } from '../data_quality_context'; const DataQualityDetailsComponent: React.FC = () => { const { isILMAvailable, ilmPhases } = useDataQualityContext(); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/indices_details/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/index.test.tsx similarity index 83% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/indices_details/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/index.test.tsx index ddb17a64d1fc2..d5aaa1eea19ae 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/indices_details/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/index.test.tsx @@ -9,15 +9,15 @@ import numeral from '@elastic/numeral'; import { render, screen, waitFor } from '@testing-library/react'; import React from 'react'; -import { EMPTY_STAT } from '../../../../helpers'; -import { alertIndexWithAllResults } from '../../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { auditbeatWithAllResults } from '../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { packetbeatNoResults } from '../../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { EMPTY_STAT } from '../../constants'; +import { alertIndexWithAllResults } from '../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatNoResults } from '../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../../mock/test_providers/test_providers'; -import { PatternRollup } from '../../../../types'; +} from '../../mock/test_providers/test_providers'; +import { PatternRollup } from '../../types'; import { Props, IndicesDetails } from '.'; const defaultBytesFormat = '0,0.[0]b'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/indices_details/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/index.tsx similarity index 85% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/indices_details/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/index.tsx index 426e61513ee14..fd565d8fc7637 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/indices_details/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/index.tsx @@ -9,10 +9,10 @@ import { EuiFlexItem } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { useResultsRollupContext } from '../../../../contexts/results_rollup_context'; -import { Pattern } from '../../../pattern'; -import { SelectedIndex } from '../../../../types'; -import { useDataQualityContext } from '../../../data_quality_context'; +import { useResultsRollupContext } from '../../contexts/results_rollup_context'; +import { Pattern } from './pattern'; +import { SelectedIndex } from '../../types'; +import { useDataQualityContext } from '../../data_quality_context'; const StyledPatternWrapperFlexItem = styled(EuiFlexItem)` margin-bottom: ${({ theme }) => theme.eui.euiSize}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/error_empty_prompt/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/error_empty_prompt/index.test.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/error_empty_prompt/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/error_empty_prompt/index.test.tsx index ee3241cd74d8b..aad142baff3a4 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/error_empty_prompt/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/error_empty_prompt/index.test.tsx @@ -8,7 +8,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; import { ErrorEmptyPrompt } from '.'; describe('ErrorEmptyPrompt', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/error_empty_prompt/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/error_empty_prompt/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/error_empty_prompt/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/error_empty_prompt/index.tsx index 3214b704dc685..3bac63944838b 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/error_empty_prompt/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/error_empty_prompt/index.tsx @@ -8,7 +8,7 @@ import { EuiCallOut, EuiCode } from '@elastic/eui'; import React from 'react'; -import * as i18n from '../data_quality_summary/errors_popover/translations'; +import * as i18n from '../../../../data_quality_summary/summary_actions/check_status/errors_popover/translations'; interface Props { title: string; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/helpers.test.ts similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/helpers.test.ts index f6a01533bcfbf..56dc6364ba845 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/helpers.test.ts @@ -24,13 +24,13 @@ import { shouldCreateIndexNames, shouldCreatePatternRollup, } from './helpers'; -import { mockIlmExplain } from '../../mock/ilm_explain/mock_ilm_explain'; -import { mockDataQualityCheckResult } from '../../mock/data_quality_check_result/mock_index'; -import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { mockStats } from '../../mock/stats/mock_stats'; -import { DataQualityCheckResult } from '../../types'; -import { getIndexNames, getTotalDocsCount } from '../../helpers'; +import { mockIlmExplain } from '../../../mock/ilm_explain/mock_ilm_explain'; +import { mockDataQualityCheckResult } from '../../../mock/data_quality_check_result/mock_index'; +import { auditbeatWithAllResults } from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { mockStats } from '../../../mock/stats/mock_stats'; +import { DataQualityCheckResult } from '../../../types'; import { IndexSummaryTableItem } from './types'; +import { getIndexNames, getPatternDocsCount } from './utils/stats'; const hot: IlmExplainLifecycleLifecycleExplainManaged = { index: '.ds-packetbeat-8.6.1-2023.02.04-000001', @@ -569,7 +569,7 @@ describe('helpers', () => { ilmPhases: ['hot', 'unmanaged'], isILMAvailable, }); - const newDocsCount = getTotalDocsCount({ indexNames: newIndexNames, stats: mockStats }); + const newDocsCount = getPatternDocsCount({ indexNames: newIndexNames, stats: mockStats }); test('it returns false when the `patternRollup.docsCount` equals newDocsCount', () => { expect( shouldCreatePatternRollup({ diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/helpers.ts similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/helpers.ts index ab3e917246f1d..5470854fd2ff0 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/helpers.ts @@ -15,9 +15,9 @@ import type { PatternRollup, SortConfig, MeteringStatsIndex, -} from '../../types'; -import { getDocsCount, getSizeInBytes } from '../../helpers'; +} from '../../../types'; import { IndexSummaryTableItem } from './types'; +import { getDocsCount, getSizeInBytes } from '../../../utils/stats'; export const isManaged = ( ilmExplainRecord: IlmExplainLifecycleLifecycleExplain | undefined diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_ilm_explain/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_ilm_explain/index.test.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_ilm_explain/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_ilm_explain/index.test.tsx index b8c6092fea0d0..768845f023011 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_ilm_explain/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_ilm_explain/index.test.tsx @@ -8,9 +8,9 @@ import { renderHook } from '@testing-library/react-hooks'; import React from 'react'; -import { DataQualityProvider } from '../data_quality_panel/data_quality_context'; -import { mockIlmExplain } from '../mock/ilm_explain/mock_ilm_explain'; -import { ERROR_LOADING_ILM_EXPLAIN } from '../translations'; +import { DataQualityProvider } from '../../../../../data_quality_context'; +import { mockIlmExplain } from '../../../../../mock/ilm_explain/mock_ilm_explain'; +import { ERROR_LOADING_ILM_EXPLAIN } from '../../../../../translations'; import { useIlmExplain, UseIlmExplain } from '.'; import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; import { Theme } from '@elastic/charts'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_ilm_explain/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_ilm_explain/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_ilm_explain/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_ilm_explain/index.tsx index 8477d710fea76..17d8b8d46dea7 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_ilm_explain/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_ilm_explain/index.tsx @@ -8,10 +8,10 @@ import type { IlmExplainLifecycleLifecycleExplain } from '@elastic/elasticsearch/lib/api/types'; import { useEffect, useState } from 'react'; -import { useDataQualityContext } from '../data_quality_panel/data_quality_context'; -import { INTERNAL_API_VERSION } from '../helpers'; -import * as i18n from '../translations'; -import { useIsMounted } from '../use_is_mounted'; +import { useDataQualityContext } from '../../../../../data_quality_context'; +import { INTERNAL_API_VERSION } from '../../../../../constants'; +import * as i18n from '../../../../../translations'; +import { useIsMounted } from '../../../../../hooks/use_is_mounted'; const ILM_EXPLAIN_ENDPOINT = '/internal/ecs_data_quality_dashboard/ilm_explain'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_stats/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_stats/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx index c07bf9b8afd76..5982fa715adb9 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_stats/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.test.tsx @@ -8,9 +8,9 @@ import { renderHook } from '@testing-library/react-hooks'; import React, { FC, PropsWithChildren } from 'react'; -import { DataQualityProvider } from '../data_quality_panel/data_quality_context'; -import { mockStatsAuditbeatIndex } from '../mock/stats/mock_stats_packetbeat_index'; -import { ERROR_LOADING_STATS } from '../translations'; +import { DataQualityProvider } from '../../../../../data_quality_context'; +import { mockStatsAuditbeatIndex } from '../../../../../mock/stats/mock_stats_packetbeat_index'; +import { ERROR_LOADING_STATS } from '../../../../../translations'; import { useStats, UseStats } from '.'; import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; import { Theme } from '@elastic/charts'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_stats/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_stats/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.tsx index 0de57ccd54568..2f1507ed47007 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_stats/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/hooks/use_stats/index.tsx @@ -8,11 +8,11 @@ import { useEffect, useState } from 'react'; import { HttpFetchQuery } from '@kbn/core/public'; -import { useDataQualityContext } from '../data_quality_panel/data_quality_context'; -import * as i18n from '../translations'; -import { INTERNAL_API_VERSION } from '../helpers'; -import { MeteringStatsIndex } from '../types'; -import { useIsMounted } from '../use_is_mounted'; +import { useDataQualityContext } from '../../../../../data_quality_context'; +import * as i18n from '../../../../../translations'; +import { INTERNAL_API_VERSION } from '../../../../../constants'; +import { MeteringStatsIndex } from '../../../../../types'; +import { useIsMounted } from '../../../../../hooks/use_is_mounted'; const STATS_ENDPOINT = '/internal/ecs_data_quality_dashboard/stats'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index.test.tsx similarity index 91% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index.test.tsx index 9fdd6f3acc606..cbed456f9cdd5 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index.test.tsx @@ -9,13 +9,13 @@ import numeral from '@elastic/numeral'; import { render, screen } from '@testing-library/react'; import React, { ComponentProps } from 'react'; -import { EMPTY_STAT } from '../../helpers'; +import { EMPTY_STAT } from '../../../constants'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../mock/test_providers/test_providers'; +} from '../../../mock/test_providers/test_providers'; import { Pattern } from '.'; -import { getCheckState } from '../../stub/get_check_state'; +import { getCheckState } from '../../../stub/get_check_state'; const indexName = 'auditbeat-custom-index-1'; const defaultBytesFormat = '0,0.[0]b'; @@ -26,7 +26,7 @@ const defaultNumberFormat = '0,0.[000]'; const formatNumber = (value: number | undefined) => value != null ? numeral(value).format(defaultNumberFormat) : EMPTY_STAT; -jest.mock('../../use_stats', () => ({ +jest.mock('./hooks/use_stats', () => ({ useStats: jest.fn(() => ({ stats: {}, error: null, @@ -34,7 +34,7 @@ jest.mock('../../use_stats', () => ({ })), })); -jest.mock('../../use_ilm_explain', () => ({ +jest.mock('./hooks/use_ilm_explain', () => ({ useIlmExplain: jest.fn(() => ({ error: null, ilmExplain: {}, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index.tsx similarity index 90% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index.tsx index 106d9bbe2e433..a59fe7f87d3a5 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index.tsx @@ -8,7 +8,7 @@ import { EuiSpacer, useGeneratedHtmlId } from '@elastic/eui'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { ErrorEmptyPrompt } from '../error_empty_prompt'; +import { ErrorEmptyPrompt } from './error_empty_prompt'; import { defaultSort, getIlmExplainPhaseCounts, @@ -18,27 +18,22 @@ import { shouldCreateIndexNames, shouldCreatePatternRollup, } from './helpers'; -import { - getIndexNames, - getTotalDocsCount, - getTotalPatternIncompatible, - getTotalPatternIndicesChecked, - getTotalSizeInBytes, -} from '../../helpers'; -import { LoadingEmptyPrompt } from '../loading_empty_prompt'; +import { getTotalPatternIncompatible, getTotalPatternIndicesChecked } from '../../../utils/stats'; +import { getIndexNames, getPatternDocsCount, getPatternSizeInBytes } from './utils/stats'; +import { LoadingEmptyPrompt } from './loading_empty_prompt'; import { PatternSummary } from './pattern_summary'; -import { RemoteClustersCallout } from '../remote_clusters_callout'; -import { SummaryTable } from '../summary_table'; -import { getSummaryTableColumns } from '../summary_table/helpers'; +import { RemoteClustersCallout } from './remote_clusters_callout'; +import { SummaryTable } from './summary_table'; +import { getSummaryTableColumns } from './summary_table/helpers'; import * as i18n from './translations'; -import type { PatternRollup, SelectedIndex, SortConfig } from '../../types'; -import { useIlmExplain } from '../../use_ilm_explain'; -import { useStats } from '../../use_stats'; -import { useDataQualityContext } from '../data_quality_context'; +import type { PatternRollup, SelectedIndex, SortConfig } from '../../../types'; +import { useIlmExplain } from './hooks/use_ilm_explain'; +import { useStats } from './hooks/use_stats'; +import { useDataQualityContext } from '../../../data_quality_context'; import { PatternAccordion, PatternAccordionChildren } from './styles'; import { IndexCheckFlyout } from './index_check_flyout'; -import { useResultsRollupContext } from '../../contexts/results_rollup_context'; -import { useIndicesCheckContext } from '../../contexts/indices_check_context'; +import { useResultsRollupContext } from '../../../contexts/results_rollup_context'; +import { useIndicesCheckContext } from '../../../contexts/indices_check_context'; const EMPTY_INDEX_NAMES: string[] = []; @@ -152,7 +147,7 @@ const PatternComponent: React.FC = ({ useEffect(() => { const newIndexNames = getIndexNames({ stats, ilmExplain, ilmPhases, isILMAvailable }); - const newDocsCount = getTotalDocsCount({ indexNames: newIndexNames, stats }); + const newDocsCount = getPatternDocsCount({ indexNames: newIndexNames, stats }); if ( shouldCreateIndexNames({ @@ -188,7 +183,7 @@ const PatternComponent: React.FC = ({ pattern, results: undefined, sizeInBytes: isILMAvailable - ? getTotalSizeInBytes({ + ? getPatternSizeInBytes({ indexNames: getIndexNames({ stats, ilmExplain, ilmPhases, isILMAvailable }), stats, }) ?? 0 diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_current_window_width/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/hooks/use_current_window_width/index.test.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_current_window_width/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/hooks/use_current_window_width/index.test.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_current_window_width/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/hooks/use_current_window_width/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_current_window_width/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/hooks/use_current_window_width/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index.test.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index.test.tsx index b73da31bbcf8c..0b6b1d62ada01 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index.test.tsx @@ -14,10 +14,10 @@ import { IndexCheckFlyout } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; -import { mockIlmExplain } from '../../../mock/ilm_explain/mock_ilm_explain'; -import { auditbeatWithAllResults } from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { mockStats } from '../../../mock/stats/mock_stats'; +} from '../../../../mock/test_providers/test_providers'; +import { mockIlmExplain } from '../../../../mock/ilm_explain/mock_ilm_explain'; +import { auditbeatWithAllResults } from '../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { mockStats } from '../../../../mock/stats/mock_stats'; describe('IndexCheckFlyout', () => { beforeEach(() => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index.tsx index b9d33c51cc495..6748fd0651799 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index.tsx @@ -21,15 +21,16 @@ import { } from '@elastic/eui'; import React, { useCallback, useEffect } from 'react'; import moment from 'moment'; -import { useIndicesCheckContext } from '../../../contexts/indices_check_context'; +import { getDocsCount, getSizeInBytes } from '../../../../utils/stats'; +import { useIndicesCheckContext } from '../../../../contexts/indices_check_context'; -import { EMPTY_STAT, getDocsCount, getSizeInBytes } from '../../../helpers'; -import { MeteringStatsIndex, PatternRollup } from '../../../types'; -import { useDataQualityContext } from '../../data_quality_context'; -import { IndexProperties } from '../../index_properties'; +import { EMPTY_STAT } from '../../../../constants'; +import { MeteringStatsIndex, PatternRollup } from '../../../../types'; +import { useDataQualityContext } from '../../../../data_quality_context'; +import { IndexProperties } from './index_properties'; import { getIlmPhase } from '../helpers'; -import { IndexResultBadge } from '../../index_result_badge'; -import { useCurrentWindowWidth } from '../../../use_current_window_width'; +import { IndexResultBadge } from '../index_result_badge'; +import { useCurrentWindowWidth } from './hooks/use_current_window_width'; import { CHECK_NOW } from './translations'; export interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_body.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_body.test.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_body.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_body.test.tsx index 19e6c47a2c365..cd16e9870906a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_body.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_body.test.tsx @@ -9,7 +9,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { EmptyPromptBody } from './empty_prompt_body'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../../mock/test_providers/test_providers'; describe('EmptyPromptBody', () => { const content = 'foo bar baz @baz'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_body.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_body.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_body.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_body.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_title.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_title.test.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_title.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_title.test.tsx index 760d16f8a87a5..0b146f7b7f123 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_title.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_title.test.tsx @@ -9,7 +9,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { EmptyPromptTitle } from './empty_prompt_title'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../../mock/test_providers/test_providers'; describe('EmptyPromptTitle', () => { const title = 'What is a great title?'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_title.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_title.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/empty_prompt_title.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/empty_prompt_title.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers.test.ts similarity index 82% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers.test.ts index 2ef3eb9c1c190..962fa7a825714 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers.test.ts @@ -5,14 +5,10 @@ * 2.0. */ -import { - getMappingsProperties, - getSortedPartitionedFieldMetadata, - hasAllDataFetchingCompleted, -} from './helpers'; -import { mockIndicesGetMappingIndexMappingRecords } from '../../mock/indices_get_mapping_index_mapping_record/mock_indices_get_mapping_index_mapping_record'; -import { mockMappingsProperties } from '../../mock/mappings_properties/mock_mappings_properties'; -import { EcsFlatTyped } from '../../constants'; +import { getMappingsProperties, getSortedPartitionedFieldMetadata } from './helpers'; +import { mockIndicesGetMappingIndexMappingRecords } from '../../../../../mock/indices_get_mapping_index_mapping_record/mock_indices_get_mapping_index_mapping_record'; +import { mockMappingsProperties } from '../../../../../mock/mappings_properties/mock_mappings_properties'; +import { EcsFlatTyped } from '../../../../../constants'; describe('helpers', () => { describe('getSortedPartitionedFieldMetadata', () => { @@ -250,42 +246,4 @@ describe('helpers', () => { ).toBeNull(); }); }); - - describe('hasAllDataFetchingCompleted', () => { - test('it returns false when both the mappings and unallowed values are loading', () => { - expect( - hasAllDataFetchingCompleted({ - loadingMappings: true, - loadingUnallowedValues: true, - }) - ).toBe(false); - }); - - test('it returns false when mappings are loading, and unallowed values are NOT loading', () => { - expect( - hasAllDataFetchingCompleted({ - loadingMappings: true, - loadingUnallowedValues: false, - }) - ).toBe(false); - }); - - test('it returns false when mappings are NOT loading, and unallowed values are loading', () => { - expect( - hasAllDataFetchingCompleted({ - loadingMappings: false, - loadingUnallowedValues: true, - }) - ).toBe(false); - }); - - test('it returns true when both the mappings and unallowed values have finished loading', () => { - expect( - hasAllDataFetchingCompleted({ - loadingMappings: false, - loadingUnallowedValues: false, - }) - ).toBe(true); - }); - }); }); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers.ts similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers.ts index c0046da0ea814..cf4ae6562b8ed 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers.ts @@ -10,15 +10,15 @@ import type { MappingProperty, } from '@elastic/elasticsearch/lib/api/types'; import { sortBy } from 'lodash/fp'; -import { EcsFlatTyped } from '../../constants'; +import { EcsFlatTyped } from '../../../../../constants'; +import type { PartitionedFieldMetadata, UnallowedValueCount } from '../../../../../types'; import { getEnrichedFieldMetadata, getFieldTypes, getMissingTimestampFieldMetadata, getPartitionedFieldMetadata, -} from '../../helpers'; -import type { PartitionedFieldMetadata, UnallowedValueCount } from '../../types'; +} from './utils/metadata'; export const ALL_TAB_ID = 'allTab'; export const ECS_COMPLIANT_TAB_ID = 'ecsCompliantTab'; @@ -90,11 +90,3 @@ export const getMappingsProperties = ({ return null; }; - -export const hasAllDataFetchingCompleted = ({ - loadingMappings, - loadingUnallowedValues, -}: { - loadingMappings: boolean; - loadingUnallowedValues: boolean; -}): boolean => loadingMappings === false && loadingUnallowedValues === false; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index.test.tsx similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index.test.tsx index 4e991d7878ace..2d361ec0ed34f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index.test.tsx @@ -9,15 +9,15 @@ import numeral from '@elastic/numeral'; import { render, screen, waitFor } from '@testing-library/react'; import React from 'react'; -import { EMPTY_STAT } from '../../helpers'; -import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { EMPTY_STAT } from '../../../../../constants'; +import { auditbeatWithAllResults } from '../../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../mock/test_providers/test_providers'; +} from '../../../../../mock/test_providers/test_providers'; import { LOADING_MAPPINGS, LOADING_UNALLOWED_VALUES } from './translations'; import { IndexProperties, Props } from '.'; -import { getCheckState } from '../../stub/get_check_state'; +import { getCheckState } from '../../../../../stub/get_check_state'; const indexName = 'auditbeat-custom-index-1'; const defaultBytesFormat = '0,0.[0]b'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index.tsx similarity index 86% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index.tsx index f7b1bb37e36f1..f28d506cda0fa 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index.tsx @@ -8,15 +8,15 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; -import { ErrorEmptyPrompt } from '../error_empty_prompt'; -import { LoadingEmptyPrompt } from '../loading_empty_prompt'; -import { getIndexPropertiesContainerId } from '../pattern/helpers'; +import { ErrorEmptyPrompt } from '../../error_empty_prompt'; +import { LoadingEmptyPrompt } from '../../loading_empty_prompt'; +import { getIndexPropertiesContainerId } from '../../helpers'; import * as i18n from './translations'; -import type { IlmPhase, PatternRollup } from '../../types'; -import { useIndicesCheckContext } from '../../contexts/indices_check_context'; +import type { IlmPhase, PatternRollup } from '../../../../../types'; +import { useIndicesCheckContext } from '../../../../../contexts/indices_check_context'; import { IndexCheckFields } from './index_check_fields'; import { IndexStatsPanel } from './index_stats_panel'; -import { useDataQualityContext } from '../data_quality_context'; +import { useDataQualityContext } from '../../../../../data_quality_context'; export interface Props { docsCount: number; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_check_fields/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/index.test.tsx similarity index 90% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_check_fields/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/index.test.tsx index e5ab5247ac41e..024a53087efae 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_check_fields/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/index.test.tsx @@ -12,8 +12,8 @@ import { IndexCheckFields } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; -import { auditbeatWithAllResults } from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +} from '../../../../../../mock/test_providers/test_providers'; +import { auditbeatWithAllResults } from '../../../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; import userEvent from '@testing-library/user-event'; describe('IndexCheckFields', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_check_fields/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/index.tsx similarity index 91% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_check_fields/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/index.tsx index 8fa4a37ea3ead..db6696e36212a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_check_fields/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/index.tsx @@ -9,11 +9,11 @@ import React, { useMemo, useState } from 'react'; import { EuiButtonGroup, EuiFlexGroup, EuiSpacer } from '@elastic/eui'; import styled from 'styled-components'; -import { useDataQualityContext } from '../../data_quality_context'; -import { useIndicesCheckContext } from '../../../contexts/indices_check_context'; +import { useDataQualityContext } from '../../../../../../data_quality_context'; +import { useIndicesCheckContext } from '../../../../../../contexts/indices_check_context'; import { EMPTY_METADATA, INCOMPATIBLE_TAB_ID } from '../helpers'; -import { IlmPhase, PatternRollup } from '../../../types'; -import { getTabs } from '../../tabs/helpers'; +import { IlmPhase, PatternRollup } from '../../../../../../types'; +import { getTabs } from './tabs/helpers'; const StyledTabFlexGroup = styled(EuiFlexGroup)` width: 100%; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/all_tab/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/all_tab/index.tsx similarity index 77% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/all_tab/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/all_tab/index.tsx index c80d1f615f261..085a865917b42 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/all_tab/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/all_tab/index.tsx @@ -9,12 +9,12 @@ import { EcsVersion } from '@elastic/ecs'; import { EuiCallOut, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; -import { CompareFieldsTable } from '../../../compare_fields_table'; -import { getCommonTableColumns } from '../../../compare_fields_table/get_common_table_columns'; -import { EmptyPromptBody } from '../../index_properties/empty_prompt_body'; -import { EmptyPromptTitle } from '../../index_properties/empty_prompt_title'; -import * as i18n from '../../index_properties/translations'; -import type { PartitionedFieldMetadata } from '../../../types'; +import { CompareFieldsTable } from '../compare_fields_table'; +import { getCommonTableColumns } from '../compare_fields_table/get_common_table_columns'; +import { EmptyPromptBody } from '../../../empty_prompt_body'; +import { EmptyPromptTitle } from '../../../empty_prompt_title'; +import * as i18n from '../../../translations'; +import type { PartitionedFieldMetadata } from '../../../../../../../../types'; interface Props { indexName: string; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/custom_callout/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/custom_callout/index.test.tsx similarity index 80% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/custom_callout/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/custom_callout/index.test.tsx index 88bb4ef18ac47..b83f1fdc7ca60 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/custom_callout/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/custom_callout/index.test.tsx @@ -9,12 +9,12 @@ import { EcsVersion } from '@elastic/ecs'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import { ECS_IS_A_PERMISSIVE_SCHEMA } from '../../../index_properties/translations'; +import { ECS_IS_A_PERMISSIVE_SCHEMA } from '../../../../translations'; import { hostNameKeyword, someField, -} from '../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; +} from '../../../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; import { CustomCallout } from '.'; describe('CustomCallout', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/custom_callout/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/custom_callout/index.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/custom_callout/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/custom_callout/index.tsx index f15e2a108a82c..1d631fa15a371 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/custom_callout/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/custom_callout/index.tsx @@ -9,9 +9,9 @@ import { EcsVersion } from '@elastic/ecs'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import React from 'react'; -import type { CustomFieldMetadata } from '../../../../types'; +import type { CustomFieldMetadata } from '../../../../../../../../../types'; -import * as i18n from '../../../index_properties/translations'; +import * as i18n from '../../../../translations'; interface Props { customFieldMetadata: CustomFieldMetadata[]; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/incompatible_callout/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/incompatible_callout/index.test.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/incompatible_callout/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/incompatible_callout/index.test.tsx index 7e1d1f9eb3c02..ffb315c266669 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/incompatible_callout/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/incompatible_callout/index.test.tsx @@ -13,8 +13,8 @@ import { DETECTION_ENGINE_RULES_MAY_NOT_MATCH, MAPPINGS_THAT_CONFLICT_WITH_ECS, PAGES_MAY_NOT_DISPLAY_EVENTS, -} from '../../../index_properties/translations'; -import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; +} from '../../../../translations'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; import { IncompatibleCallout } from '.'; describe('IncompatibleCallout', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/incompatible_callout/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/incompatible_callout/index.tsx similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/incompatible_callout/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/incompatible_callout/index.tsx index 6a692e05f8e54..41a69eb69424a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/incompatible_callout/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/incompatible_callout/index.tsx @@ -10,7 +10,7 @@ import { EcsVersion } from '@elastic/ecs'; import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import React from 'react'; -import * as i18n from '../../../index_properties/translations'; +import * as i18n from '../../../../translations'; import { CalloutItem } from '../../styles'; const IncompatibleCalloutComponent: React.FC = () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/missing_timestamp_callout/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/missing_timestamp_callout/index.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/missing_timestamp_callout/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/missing_timestamp_callout/index.tsx index 1db9e3cb6a494..3e9b1f705d1eb 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/missing_timestamp_callout/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/missing_timestamp_callout/index.tsx @@ -8,7 +8,7 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import React from 'react'; -import * as i18n from '../../../index_properties/translations'; +import * as i18n from '../../../../translations'; import { CalloutItem } from '../../styles'; interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/same_family_callout/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/same_family_callout/index.test.tsx similarity index 82% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/same_family_callout/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/same_family_callout/index.test.tsx index d93b5dab41201..39289f1a9294f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/same_family_callout/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/same_family_callout/index.test.tsx @@ -9,10 +9,10 @@ import { EcsVersion } from '@elastic/ecs'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import { FIELDS_WITH_MAPPINGS_SAME_FAMILY } from '../../../index_properties/translations'; -import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; +import { FIELDS_WITH_MAPPINGS_SAME_FAMILY } from '../../../../translations'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; import { SameFamilyCallout } from '.'; -import { mockPartitionedFieldMetadataWithSameFamily } from '../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family'; +import { mockPartitionedFieldMetadataWithSameFamily } from '../../../../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family'; describe('SameFamilyCallout', () => { beforeEach(() => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/same_family_callout/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/same_family_callout/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/same_family_callout/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/same_family_callout/index.tsx index f89ebdda19889..ba7bab71f228d 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/callouts/same_family_callout/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/callouts/same_family_callout/index.tsx @@ -9,8 +9,8 @@ import { EcsVersion } from '@elastic/ecs'; import { EuiCallOut, EuiSpacer, EuiText } from '@elastic/eui'; import React from 'react'; -import * as i18n from '../../../index_properties/translations'; -import type { EcsBasedFieldMetadata } from '../../../../types'; +import * as i18n from '../../../../translations'; +import type { EcsBasedFieldMetadata } from '../../../../../../../../../types'; interface Props { ecsBasedFieldMetadata: EcsBasedFieldMetadata[]; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/ecs_allowed_values/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/ecs_allowed_values/index.test.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/ecs_allowed_values/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/ecs_allowed_values/index.test.tsx index 97b633eff4a64..da16307b9a23b 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/ecs_allowed_values/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/ecs_allowed_values/index.test.tsx @@ -8,8 +8,8 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import { mockAllowedValues } from '../../mock/allowed_values/mock_allowed_values'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +import { mockAllowedValues } from '../../../../../../../../../mock/allowed_values/mock_allowed_values'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; import { EcsAllowedValues } from '.'; describe('EcsAllowedValues', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/ecs_allowed_values/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/ecs_allowed_values/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/ecs_allowed_values/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/ecs_allowed_values/index.tsx index 8f63047bb91e1..07197641c9788 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/ecs_allowed_values/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/ecs_allowed_values/index.tsx @@ -9,8 +9,8 @@ import { EuiCode, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { EMPTY_PLACEHOLDER } from '../helpers'; -import { CodeSuccess } from '../../styles'; -import type { AllowedValue } from '../../types'; +import { CodeSuccess } from '../../../../../../../../../styles'; +import type { AllowedValue } from '../../../../../../../../../types'; interface Props { allowedValues: AllowedValue[] | undefined; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_common_table_columns/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_common_table_columns/index.test.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_common_table_columns/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_common_table_columns/index.test.tsx index 1695f2587a674..6a7f522aa803f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_common_table_columns/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_common_table_columns/index.test.tsx @@ -9,13 +9,13 @@ import { render, screen } from '@testing-library/react'; import { omit } from 'lodash/fp'; import React from 'react'; -import { SAME_FAMILY } from '../../data_quality_panel/same_family/translations'; +import { SAME_FAMILY } from '../same_family/translations'; import { eventCategory, someField, eventCategoryWithUnallowedValues, -} from '../../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +} from '../../../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; import { DOCUMENT_VALUES_ACTUAL, ECS_DESCRIPTION, @@ -24,7 +24,7 @@ import { FIELD, INDEX_MAPPING_TYPE_ACTUAL, } from '../translations'; -import { EnrichedFieldMetadata } from '../../types'; +import { EnrichedFieldMetadata } from '../../../../../../../../../types'; import { EMPTY_PLACEHOLDER, getCommonTableColumns } from '.'; describe('getCommonTableColumns', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_common_table_columns/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_common_table_columns/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_common_table_columns/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_common_table_columns/index.tsx index 61762d6fc8182..757294cc89c6d 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_common_table_columns/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_common_table_columns/index.tsx @@ -9,13 +9,17 @@ import type { EuiTableFieldDataColumnType } from '@elastic/eui'; import { EuiCode } from '@elastic/eui'; import React from 'react'; -import { SameFamily } from '../../data_quality_panel/same_family'; +import { SameFamily } from '../same_family'; import { EcsAllowedValues } from '../ecs_allowed_values'; -import { getIsInSameFamily } from '../../helpers'; import { IndexInvalidValues } from '../index_invalid_values'; -import { CodeDanger, CodeSuccess } from '../../styles'; +import { CodeDanger, CodeSuccess } from '../../../../../../../../../styles'; import * as i18n from '../translations'; -import type { AllowedValue, EnrichedFieldMetadata, UnallowedValueCount } from '../../types'; +import type { + AllowedValue, + EnrichedFieldMetadata, + UnallowedValueCount, +} from '../../../../../../../../../types'; +import { getIsInSameFamily } from '../../../../utils/get_is_in_same_family'; export const EMPTY_PLACEHOLDER = '--'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_incompatible_mappings_table_columns/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_incompatible_mappings_table_columns/index.test.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_incompatible_mappings_table_columns/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_incompatible_mappings_table_columns/index.test.tsx index 8a9272a717217..588affcfdbf21 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_incompatible_mappings_table_columns/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_incompatible_mappings_table_columns/index.test.tsx @@ -9,10 +9,10 @@ import { render, screen } from '@testing-library/react'; import { omit } from 'lodash/fp'; import React from 'react'; -import { SAME_FAMILY } from '../../data_quality_panel/same_family/translations'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; -import { eventCategory } from '../../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { EcsBasedFieldMetadata } from '../../types'; +import { SAME_FAMILY } from '../same_family/translations'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; +import { eventCategory } from '../../../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { EcsBasedFieldMetadata } from '../../../../../../../../../types'; import { getIncompatibleMappingsTableColumns } from '.'; describe('getIncompatibleMappingsTableColumns', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_incompatible_mappings_table_columns/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_incompatible_mappings_table_columns/index.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_incompatible_mappings_table_columns/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_incompatible_mappings_table_columns/index.tsx index 4592e22565d74..ba2e3e2035f68 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/get_incompatible_mappings_table_columns/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/get_incompatible_mappings_table_columns/index.tsx @@ -8,10 +8,10 @@ import type { EuiTableFieldDataColumnType } from '@elastic/eui'; import React from 'react'; -import { SameFamily } from '../../data_quality_panel/same_family'; -import { CodeDanger, CodeSuccess } from '../../styles'; +import { SameFamily } from '../same_family'; +import { CodeDanger, CodeSuccess } from '../../../../../../../../../styles'; import * as i18n from '../translations'; -import type { EcsBasedFieldMetadata } from '../../types'; +import type { EcsBasedFieldMetadata } from '../../../../../../../../../types'; export const EMPTY_PLACEHOLDER = '--'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/helpers.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/helpers.test.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/helpers.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/helpers.test.tsx index 2bb1e72c8ac6a..8bf2861402c73 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/helpers.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/helpers.test.tsx @@ -18,8 +18,8 @@ import { eventCategory, eventCategoryWithUnallowedValues, someField, -} from '../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { TestExternalProviders } from '../mock/test_providers/test_providers'; +} from '../../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { TestExternalProviders } from '../../../../../../../../mock/test_providers/test_providers'; describe('helpers', () => { describe('getCustomTableColumns', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/helpers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/helpers.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/helpers.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/helpers.tsx index 2563ced06733c..26e3a038b1ffe 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/helpers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/helpers.tsx @@ -11,14 +11,14 @@ import React from 'react'; import { EcsAllowedValues } from './ecs_allowed_values'; import { IndexInvalidValues } from './index_invalid_values'; -import { CodeSuccess } from '../styles'; +import { CodeSuccess } from '../../../../../../../../styles'; import * as i18n from './translations'; import type { AllowedValue, CustomFieldMetadata, EcsBasedFieldMetadata, UnallowedValueCount, -} from '../types'; +} from '../../../../../../../../types'; export const EMPTY_PLACEHOLDER = '--'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index.test.tsx similarity index 79% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index.test.tsx index f1dcced85619f..e7344dad4d55e 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index.test.tsx @@ -8,9 +8,9 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import { INCOMPATIBLE_FIELD_MAPPINGS_TABLE_TITLE } from '../data_quality_panel/tabs/incompatible_tab/translations'; -import { eventCategory } from '../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { TestExternalProviders } from '../mock/test_providers/test_providers'; +import { INCOMPATIBLE_FIELD_MAPPINGS_TABLE_TITLE } from '../incompatible_tab/translations'; +import { eventCategory } from '../../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { TestExternalProviders } from '../../../../../../../../mock/test_providers/test_providers'; import { CompareFieldsTable } from '.'; import { getIncompatibleMappingsTableColumns } from './get_incompatible_mappings_table_columns'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index.tsx similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index.tsx index 460663fb28790..8874bd8594866 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index.tsx @@ -10,7 +10,7 @@ import { EuiInMemoryTable, EuiTitle, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; import * as i18n from './translations'; -import type { EnrichedFieldMetadata } from '../types'; +import type { EnrichedFieldMetadata } from '../../../../../../../../types'; const search: Search = { box: { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index_invalid_values/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index_invalid_values/index.test.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index_invalid_values/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index_invalid_values/index.test.tsx index 719c94bd85d58..8a53f4cdaf546 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index_invalid_values/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index_invalid_values/index.test.tsx @@ -9,8 +9,8 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { EMPTY_PLACEHOLDER } from '../helpers'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; -import { UnallowedValueCount } from '../../types'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; +import { UnallowedValueCount } from '../../../../../../../../../types'; import { IndexInvalidValues } from '.'; describe('IndexInvalidValues', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index_invalid_values/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index_invalid_values/index.tsx similarity index 91% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index_invalid_values/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index_invalid_values/index.tsx index 2b58ea98b8b28..7f83876423ba9 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/index_invalid_values/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/index_invalid_values/index.tsx @@ -10,8 +10,8 @@ import React from 'react'; import styled from 'styled-components'; import { EMPTY_PLACEHOLDER } from '../helpers'; -import { CodeDanger } from '../../styles'; -import type { UnallowedValueCount } from '../../types'; +import { CodeDanger } from '../../../../../../../../../styles'; +import type { UnallowedValueCount } from '../../../../../../../../../types'; const IndexInvalidValueFlexItem = styled(EuiFlexItem)` margin-bottom: ${({ theme }) => theme.eui.euiSizeXS}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/index.test.tsx similarity index 87% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/index.test.tsx index d1bea1a3312b3..58889ad1edb2e 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/index.test.tsx @@ -9,7 +9,7 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; import { SAME_FAMILY } from './translations'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../../../../../../mock/test_providers/test_providers'; import { SameFamily } from '.'; describe('SameFamily', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/same_family/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/same_family/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/compare_fields_table/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/compare_fields_table/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/helpers.test.ts similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/helpers.test.ts index 424664c314832..5061a818e17fd 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/helpers.test.ts @@ -8,7 +8,7 @@ import numeral from '@elastic/numeral'; import { EcsVersion } from '@elastic/ecs'; -import { ECS_IS_A_PERMISSIVE_SCHEMA } from '../../index_properties/translations'; +import { ECS_IS_A_PERMISSIVE_SCHEMA } from '../../../translations'; import { getAllCustomMarkdownComments, getCustomMarkdownComment, @@ -17,9 +17,9 @@ import { import { hostNameKeyword, someField, -} from '../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { mockPartitionedFieldMetadata } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; -import { EMPTY_STAT } from '../../../helpers'; +} from '../../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { mockPartitionedFieldMetadata } from '../../../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; +import { EMPTY_STAT } from '../../../../../../../../constants'; const defaultBytesFormat = '0,0.[0]b'; const formatBytes = (value: number | undefined) => diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/helpers.ts similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/helpers.ts index 55cb4898b7951..4ccebaefaa180 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/helpers.ts @@ -7,7 +7,7 @@ import { EcsVersion } from '@elastic/ecs'; -import { FIELD, INDEX_MAPPING_TYPE } from '../../../compare_fields_table/translations'; +import { FIELD, INDEX_MAPPING_TYPE } from '../compare_fields_table/translations'; import { getSummaryMarkdownComment, getCustomMarkdownTableRows, @@ -15,9 +15,13 @@ import { getMarkdownTable, getTabCountsMarkdownComment, getSummaryTableMarkdownComment, -} from '../../index_properties/markdown/helpers'; -import * as i18n from '../../index_properties/translations'; -import type { CustomFieldMetadata, IlmPhase, PartitionedFieldMetadata } from '../../../types'; +} from '../../../markdown/helpers'; +import * as i18n from '../../../translations'; +import type { + CustomFieldMetadata, + IlmPhase, + PartitionedFieldMetadata, +} from '../../../../../../../../types'; export const getCustomMarkdownComment = ({ customFieldMetadata, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/index.tsx similarity index 85% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/index.tsx index 8c786216bc55a..2d7437e8f0638 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/custom_tab/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/custom_tab/index.tsx @@ -9,14 +9,14 @@ import { EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; import { CustomCallout } from '../callouts/custom_callout'; -import { CompareFieldsTable } from '../../../compare_fields_table'; -import { getCustomTableColumns } from '../../../compare_fields_table/helpers'; -import { EmptyPromptBody } from '../../index_properties/empty_prompt_body'; -import { EmptyPromptTitle } from '../../index_properties/empty_prompt_title'; +import { CompareFieldsTable } from '../compare_fields_table'; +import { getCustomTableColumns } from '../compare_fields_table/helpers'; +import { EmptyPromptBody } from '../../../empty_prompt_body'; +import { EmptyPromptTitle } from '../../../empty_prompt_title'; import { getAllCustomMarkdownComments, showCustomCallout } from './helpers'; -import * as i18n from '../../index_properties/translations'; -import type { IlmPhase, PartitionedFieldMetadata } from '../../../types'; -import { useDataQualityContext } from '../../data_quality_context'; +import * as i18n from '../../../translations'; +import type { IlmPhase, PartitionedFieldMetadata } from '../../../../../../../../types'; +import { useDataQualityContext } from '../../../../../../../../data_quality_context'; import { StickyActions } from '../sticky_actions'; interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/ecs_compliant_tab/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/ecs_compliant_tab/index.tsx similarity index 85% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/ecs_compliant_tab/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/ecs_compliant_tab/index.tsx index 39b932cd88e40..7455ae3f482b9 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/ecs_compliant_tab/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/ecs_compliant_tab/index.tsx @@ -11,14 +11,14 @@ import { EuiCallOut, EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; import styled from 'styled-components'; -import { CompareFieldsTable } from '../../../compare_fields_table'; -import { getEcsCompliantTableColumns } from '../../../compare_fields_table/helpers'; -import { EmptyPromptBody } from '../../index_properties/empty_prompt_body'; -import { EmptyPromptTitle } from '../../index_properties/empty_prompt_title'; +import { CompareFieldsTable } from '../compare_fields_table'; +import { getEcsCompliantTableColumns } from '../compare_fields_table/helpers'; +import { EmptyPromptBody } from '../../../empty_prompt_body'; +import { EmptyPromptTitle } from '../../../empty_prompt_title'; import { showMissingTimestampCallout } from '../helpers'; import { CalloutItem } from '../styles'; -import * as i18n from '../../index_properties/translations'; -import type { PartitionedFieldMetadata } from '../../../types'; +import * as i18n from '../../../translations'; +import type { PartitionedFieldMetadata } from '../../../../../../../../types'; const EmptyPromptContainer = styled.div` width: 100%; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/helpers.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/helpers.test.tsx similarity index 90% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/helpers.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/helpers.test.tsx index 3891a3d661561..4c30702fcef36 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/helpers.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/helpers.test.tsx @@ -10,9 +10,9 @@ import { omit } from 'lodash/fp'; import { eventCategory, timestamp, -} from '../../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { mockPartitionedFieldMetadata } from '../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; -import { mockStatsAuditbeatIndex } from '../../mock/stats/mock_stats_packetbeat_index'; +} from '../../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { mockPartitionedFieldMetadata } from '../../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; +import { mockStatsAuditbeatIndex } from '../../../../../../../mock/stats/mock_stats_packetbeat_index'; import { getEcsCompliantBadgeColor, getMissingTimestampComment, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/helpers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/helpers.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/helpers.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/helpers.tsx index 5220522350b07..fa4e63afc6f3b 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/helpers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/helpers.tsx @@ -9,10 +9,11 @@ import { EuiBadge } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; +import { getSizeInBytes } from '../../../../../../../utils/stats'; +import { getIncompatibleStatBadgeColor } from '../../../../../../../utils/get_incompatible_stat_badge_color'; import { AllTab } from './all_tab'; import { CustomTab } from './custom_tab'; import { EcsCompliantTab } from './ecs_compliant_tab'; -import { getIncompatibleStatBadgeColor, getSizeInBytes } from '../../helpers'; import { IncompatibleTab } from './incompatible_tab'; import { ALL_TAB_ID, @@ -20,16 +21,16 @@ import { ECS_COMPLIANT_TAB_ID, INCOMPATIBLE_TAB_ID, SAME_FAMILY_TAB_ID, -} from '../index_properties/helpers'; -import { getMarkdownComment } from '../index_properties/markdown/helpers'; -import * as i18n from '../index_properties/translations'; +} from '../../helpers'; +import { getMarkdownComment } from '../../markdown/helpers'; +import * as i18n from '../../translations'; import { SameFamilyTab } from './same_family_tab'; import type { EcsBasedFieldMetadata, IlmPhase, MeteringStatsIndex, PartitionedFieldMetadata, -} from '../../types'; +} from '../../../../../../../types'; export const getMissingTimestampComment = (): string => getMarkdownComment({ diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers.test.ts similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers.test.ts index 9851da18072a7..5d0e66daff88a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers.test.ts @@ -18,14 +18,14 @@ import { getIncompatibleValuesFields, showInvalidCallout, } from './helpers'; -import { EMPTY_STAT } from '../../../helpers'; +import { EMPTY_STAT } from '../../../../../../../../constants'; import { DETECTION_ENGINE_RULES_MAY_NOT_MATCH, MAPPINGS_THAT_CONFLICT_WITH_ECS, PAGES_MAY_NOT_DISPLAY_EVENTS, -} from '../../index_properties/translations'; -import { mockPartitionedFieldMetadata } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; -import { PartitionedFieldMetadata } from '../../../types'; +} from '../../../translations'; +import { mockPartitionedFieldMetadata } from '../../../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; +import { PartitionedFieldMetadata } from '../../../../../../../../types'; describe('helpers', () => { describe('getIncompatibleFieldsMarkdownComment', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers.ts similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers.ts index c4c6dfd4a2a82..edd7152c6d492 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers.ts @@ -16,9 +16,13 @@ import { getSummaryTableMarkdownComment, getTabCountsMarkdownComment, escape, -} from '../../index_properties/markdown/helpers'; -import * as i18n from '../../index_properties/translations'; -import type { EcsBasedFieldMetadata, IlmPhase, PartitionedFieldMetadata } from '../../../types'; +} from '../../../markdown/helpers'; +import * as i18n from '../../../translations'; +import type { + EcsBasedFieldMetadata, + IlmPhase, + PartitionedFieldMetadata, +} from '../../../../../../../../types'; import { INCOMPATIBLE_FIELD_MAPPINGS_TABLE_TITLE, INCOMPATIBLE_FIELD_VALUES_TABLE_TITLE, @@ -29,8 +33,8 @@ import { INDEX_MAPPING_TYPE_ACTUAL, DOCUMENT_VALUES_ACTUAL, ECS_VALUES_EXPECTED, -} from '../../../compare_fields_table/translations'; -import { getIsInSameFamily } from '../../../helpers'; +} from '../compare_fields_table/translations'; +import { getIsInSameFamily } from '../../../utils/get_is_in_same_family'; export const getIncompatibleFieldsMarkdownComment = (incompatible: number): string => getMarkdownComment({ diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/index.tsx similarity index 87% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/index.tsx index 52559b3d5116c..d24e82192291f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/index.tsx @@ -9,24 +9,24 @@ import { EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; import { IncompatibleCallout } from '../callouts/incompatible_callout'; -import { CompareFieldsTable } from '../../../compare_fields_table'; -import { getIncompatibleMappingsTableColumns } from '../../../compare_fields_table/get_incompatible_mappings_table_columns'; -import { getIncompatibleValuesTableColumns } from '../../../compare_fields_table/helpers'; -import { EmptyPromptBody } from '../../index_properties/empty_prompt_body'; -import { EmptyPromptTitle } from '../../index_properties/empty_prompt_title'; +import { CompareFieldsTable } from '../compare_fields_table'; +import { getIncompatibleMappingsTableColumns } from '../compare_fields_table/get_incompatible_mappings_table_columns'; +import { getIncompatibleValuesTableColumns } from '../compare_fields_table/helpers'; +import { EmptyPromptBody } from '../../../empty_prompt_body'; +import { EmptyPromptTitle } from '../../../empty_prompt_title'; import { getAllIncompatibleMarkdownComments, getIncompatibleMappings, getIncompatibleValues, showInvalidCallout, } from './helpers'; -import * as i18n from '../../index_properties/translations'; +import * as i18n from '../../../translations'; import { INCOMPATIBLE_FIELD_MAPPINGS_TABLE_TITLE, INCOMPATIBLE_FIELD_VALUES_TABLE_TITLE, } from './translations'; -import type { IlmPhase, PartitionedFieldMetadata } from '../../../types'; -import { useDataQualityContext } from '../../data_quality_context'; +import type { IlmPhase, PartitionedFieldMetadata } from '../../../../../../../../types'; +import { useDataQualityContext } from '../../../../../../../../data_quality_context'; import { StickyActions } from '../sticky_actions'; interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/incompatible_tab/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/helpers.test.ts similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/helpers.test.ts index 0af79eda5e312..6eedd81fae4a5 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/helpers.test.ts @@ -13,9 +13,9 @@ import { getSameFamilyMarkdownComment, getSameFamilyMarkdownTablesComment, } from './helpers'; -import { EMPTY_STAT } from '../../../helpers'; -import { mockPartitionedFieldMetadata } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; -import { mockPartitionedFieldMetadataWithSameFamily } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family'; +import { EMPTY_STAT } from '../../../../../../../../constants'; +import { mockPartitionedFieldMetadata } from '../../../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; +import { mockPartitionedFieldMetadataWithSameFamily } from '../../../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family'; describe('helpers', () => { describe('getSameFamilyMarkdownComment', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/helpers.ts similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/helpers.ts index d6c8852bb33bb..3c90cb81a5906 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/helpers.ts @@ -11,7 +11,7 @@ import { FIELD, ECS_MAPPING_TYPE_EXPECTED, INDEX_MAPPING_TYPE_ACTUAL, -} from '../../../compare_fields_table/translations'; +} from '../compare_fields_table/translations'; import { getSummaryMarkdownComment, getIncompatibleMappingsMarkdownTableRows, @@ -19,10 +19,14 @@ import { getMarkdownTable, getSummaryTableMarkdownComment, getTabCountsMarkdownComment, -} from '../../index_properties/markdown/helpers'; -import * as i18n from '../../index_properties/translations'; +} from '../../../markdown/helpers'; +import * as i18n from '../../../translations'; import { SAME_FAMILY_FIELD_MAPPINGS_TABLE_TITLE } from './translations'; -import type { EcsBasedFieldMetadata, IlmPhase, PartitionedFieldMetadata } from '../../../types'; +import type { + EcsBasedFieldMetadata, + IlmPhase, + PartitionedFieldMetadata, +} from '../../../../../../../../types'; export const getSameFamilyMarkdownComment = (fieldsInSameFamily: number): string => getMarkdownComment({ diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/index.tsx similarity index 90% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/index.tsx index 37891a4257a5c..8d91e26a0da09 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/index.tsx @@ -9,12 +9,12 @@ import { EuiSpacer } from '@elastic/eui'; import React, { useMemo } from 'react'; import { SameFamilyCallout } from '../callouts/same_family_callout'; -import { CompareFieldsTable } from '../../../compare_fields_table'; -import { getIncompatibleMappingsTableColumns } from '../../../compare_fields_table/get_incompatible_mappings_table_columns'; -import { useDataQualityContext } from '../../data_quality_context'; +import { CompareFieldsTable } from '../compare_fields_table'; +import { getIncompatibleMappingsTableColumns } from '../compare_fields_table/get_incompatible_mappings_table_columns'; +import { useDataQualityContext } from '../../../../../../../../data_quality_context'; import { getAllSameFamilyMarkdownComments, getSameFamilyMappings } from './helpers'; import { SAME_FAMILY_FIELD_MAPPINGS_TABLE_TITLE } from './translations'; -import type { IlmPhase, PartitionedFieldMetadata } from '../../../types'; +import type { IlmPhase, PartitionedFieldMetadata } from '../../../../../../../../types'; import { StickyActions } from '../sticky_actions'; interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/same_family_tab/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/same_family_tab/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/sticky_actions/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/sticky_actions/index.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/sticky_actions/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/sticky_actions/index.tsx index 57b17a7453dd0..1cd2630e720d1 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/sticky_actions/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/sticky_actions/index.tsx @@ -9,7 +9,7 @@ import React, { FC } from 'react'; import { EuiButtonEmpty } from '@elastic/eui'; import styled from 'styled-components'; -import { Actions } from '../../actions'; +import { Actions } from '../../../../../../../../actions'; export const CopyToClipboardButton = styled(EuiButtonEmpty)` margin-left: ${({ theme }) => theme.eui.euiSizeXS}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/styles.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/styles.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/tabs/styles.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/styles.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_stats_panel/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_stats_panel/index.test.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_stats_panel/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_stats_panel/index.test.tsx index f878cd9de4f13..b589eb09e8d12 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_stats_panel/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_stats_panel/index.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { screen, render } from '@testing-library/react'; import { IndexStatsPanel } from '.'; -import { TestExternalProviders } from '../../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../../../mock/test_providers/test_providers'; describe('IndexStatsPanel', () => { it('renders stats panel', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_stats_panel/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_stats_panel/index.tsx similarity index 87% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_stats_panel/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_stats_panel/index.tsx index 03b20e8a4ce45..da5ff8efc4242 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/index_stats_panel/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_stats_panel/index.tsx @@ -8,11 +8,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; + import { DOCS } from '../translations'; -import { ILM_PHASE } from '../../../translations'; -import { SIZE } from '../../summary_table/translations'; -import { Stat } from '../../pattern/pattern_summary/stats_rollup/stat'; -import { getIlmPhaseDescription } from '../../../helpers'; +import { ILM_PHASE } from '../../../../../../translations'; +import { SIZE } from '../../../summary_table/translations'; +import { Stat } from '../../../../../../stat'; +import { getIlmPhaseDescription } from '../../../../../../utils/get_ilm_phase_description'; const StyledFlexItem = styled(EuiFlexItem)` border-right: 1px solid ${({ theme }) => theme.eui.euiBorderColor}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.test.ts similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.test.ts index 8c14a214cabf3..5fe3dbed0bd25 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.test.ts @@ -11,9 +11,13 @@ import { ECS_MAPPING_TYPE_EXPECTED, FIELD, INDEX_MAPPING_TYPE_ACTUAL, -} from '../../../compare_fields_table/translations'; -import { ERRORS } from '../../data_quality_summary/errors_popover/translations'; -import { ERROR, INDEX, PATTERN } from '../../data_quality_summary/errors_viewer/translations'; +} from '../index_check_fields/tabs/compare_fields_table/translations'; +import { ERRORS } from '../../../../../../data_quality_summary/summary_actions/check_status/errors_popover/translations'; +import { + ERROR, + INDEX, + PATTERN, +} from '../../../../../../data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/translations'; import { escape, escapePreserveNewlines, @@ -41,27 +45,27 @@ import { getSummaryTableMarkdownRow, getTabCountsMarkdownComment, } from './helpers'; -import { EMPTY_STAT } from '../../../helpers'; -import { mockAllowedValues } from '../../../mock/allowed_values/mock_allowed_values'; +import { EMPTY_STAT } from '../../../../../../constants'; +import { mockAllowedValues } from '../../../../../../mock/allowed_values/mock_allowed_values'; import { eventCategory, mockCustomFields, mockIncompatibleMappings, sourceIpWithTextMapping, -} from '../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; -import { mockPartitionedFieldMetadata } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; +} from '../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; +import { mockPartitionedFieldMetadata } from '../../../../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; import { auditbeatNoResults, auditbeatWithAllResults, -} from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { SAME_FAMILY } from '../../same_family/translations'; -import { INCOMPATIBLE_FIELD_MAPPINGS_TABLE_TITLE } from '../../tabs/incompatible_tab/translations'; +} from '../../../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { SAME_FAMILY } from '../index_check_fields/tabs/compare_fields_table/same_family/translations'; +import { INCOMPATIBLE_FIELD_MAPPINGS_TABLE_TITLE } from '../index_check_fields/tabs/incompatible_tab/translations'; import { EcsBasedFieldMetadata, ErrorSummary, PatternRollup, UnallowedValueCount, -} from '../../../types'; +} from '../../../../../../types'; const errorSummary: ErrorSummary[] = [ { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.ts similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.ts index bdbfdba4ddb35..cc32fab713881 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/markdown/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers.ts @@ -5,6 +5,10 @@ * 2.0. */ +import { + getTotalPatternIncompatible, + getTotalPatternIndicesChecked, +} from '../../../../../../utils/stats'; import { ERRORS_MAY_OCCUR, ERRORS_CALLOUT_SUMMARY, @@ -14,14 +18,16 @@ import { READ, THE_FOLLOWING_PRIVILEGES_ARE_REQUIRED, VIEW_INDEX_METADATA, -} from '../../data_quality_summary/errors_popover/translations'; +} from '../../../../../../data_quality_summary/summary_actions/check_status/errors_popover/translations'; +import { EMPTY_STAT } from '../../../../../../constants'; +import { SAME_FAMILY } from '../index_check_fields/tabs/compare_fields_table/same_family/translations'; import { - EMPTY_STAT, - getTotalPatternIncompatible, - getTotalPatternIndicesChecked, -} from '../../../helpers'; -import { SAME_FAMILY } from '../../same_family/translations'; -import { HOT, WARM, COLD, FROZEN, UNMANAGED } from '../../../ilm_phases_empty_prompt/translations'; + HOT, + WARM, + COLD, + FROZEN, + UNMANAGED, +} from '../../../../../ilm_phases_empty_prompt/translations'; import * as i18n from '../translations'; import type { AllowedValue, @@ -34,8 +40,8 @@ import type { PartitionedFieldMetadata, PatternRollup, UnallowedValueCount, -} from '../../../types'; -import { getDocsCountPercent } from '../../summary_table/helpers'; +} from '../../../../../../types'; +import { getDocsCountPercent } from '../../../summary_table/helpers'; import { DOCS, ILM_PHASE, @@ -45,8 +51,8 @@ import { INDICES_CHECKED, RESULT, SIZE, -} from '../../summary_table/translations'; -import { DATA_QUALITY_TITLE } from '../../../translations'; +} from '../../../summary_table/translations'; +import { DATA_QUALITY_TITLE } from '../../../../../../translations'; export const EMPTY_PLACEHOLDER = '--'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_properties/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/get_is_in_same_family.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/get_is_in_same_family.test.ts new file mode 100644 index 0000000000000..63388b15c9495 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/get_is_in_same_family.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getIsInSameFamily } from './get_is_in_same_family'; + +describe('getIsInSameFamily', () => { + test('it returns false when ecsExpectedType is undefined', () => { + expect(getIsInSameFamily({ ecsExpectedType: undefined, type: 'keyword' })).toBe(false); + }); + + const expectedFamilyMembers: { + [key: string]: string[]; + } = { + constant_keyword: ['keyword', 'wildcard'], // `keyword` and `wildcard` in the same family as `constant_keyword` + keyword: ['constant_keyword', 'wildcard'], + match_only_text: ['text'], + text: ['match_only_text'], + wildcard: ['keyword', 'constant_keyword'], + }; + + const ecsExpectedTypes = Object.keys(expectedFamilyMembers); + + ecsExpectedTypes.forEach((ecsExpectedType) => { + const otherMembersOfSameFamily = expectedFamilyMembers[ecsExpectedType]; + + otherMembersOfSameFamily.forEach((type) => + test(`it returns true for ecsExpectedType '${ecsExpectedType}' when given '${type}', a type in the same family`, () => { + expect(getIsInSameFamily({ ecsExpectedType, type })).toBe(true); + }) + ); + + test(`it returns false for ecsExpectedType '${ecsExpectedType}' when given 'date', a type NOT in the same family`, () => { + expect(getIsInSameFamily({ ecsExpectedType, type: 'date' })).toBe(false); + }); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/get_is_in_same_family.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/get_is_in_same_family.ts new file mode 100644 index 0000000000000..aa56bc472cbd0 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/get_is_in_same_family.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Per https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html#_core_datatypes + * + * ``` + * Field types are grouped by _family_. Types in the same family have exactly + * the same search behavior but may have different space usage or + * performance characteristics. + * + * Currently, there are two type families, `keyword` and `text`. Other type + * families have only a single field type. For example, the `boolean` type + * family consists of one field type: `boolean`. + * ``` + */ +export const fieldTypeFamilies: Record> = { + keyword: new Set(['keyword', 'constant_keyword', 'wildcard']), + text: new Set(['text', 'match_only_text']), +}; + +export const getIsInSameFamily = ({ + ecsExpectedType, + type, +}: { + ecsExpectedType: string | undefined; + type: string; +}): boolean => { + if (ecsExpectedType != null) { + const allFamilies = Object.values(fieldTypeFamilies); + + return allFamilies.reduce( + (acc, family) => (acc !== true ? family.has(ecsExpectedType) && family.has(type) : acc), + false + ); + } else { + return false; + } +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/metadata.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/metadata.test.ts new file mode 100644 index 0000000000000..d59e4821ed1c8 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/metadata.test.ts @@ -0,0 +1,402 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { omit } from 'lodash/fp'; + +import { + EnrichedFieldMetadata, + PartitionedFieldMetadata, + UnallowedValueCount, +} from '../../../../../../types'; +import { mockMappingsProperties } from '../../../../../../mock/mappings_properties/mock_mappings_properties'; +import { + FieldType, + getEnrichedFieldMetadata, + getFieldTypes, + getMissingTimestampFieldMetadata, + getPartitionedFieldMetadata, + isMappingCompatible, +} from './metadata'; +import { EcsFlatTyped } from '../../../../../../constants'; +import { + hostNameWithTextMapping, + hostNameKeyword, + someField, + someFieldKeyword, + sourceIpWithTextMapping, + sourceIpKeyword, + sourcePort, + timestamp, + eventCategoryWithUnallowedValues, +} from '../../../../../../mock/enriched_field_metadata/mock_enriched_field_metadata'; + +describe('getFieldTypes', () => { + const expected = [ + { + field: '@timestamp', + type: 'date', + }, + { + field: 'event.category', + type: 'keyword', + }, + { + field: 'host.name', + type: 'text', + }, + { + field: 'host.name.keyword', + type: 'keyword', + }, + { + field: 'some.field', + type: 'text', + }, + { + field: 'some.field.keyword', + type: 'keyword', + }, + { + field: 'source.ip', + type: 'text', + }, + { + field: 'source.ip.keyword', + type: 'keyword', + }, + { + field: 'source.port', + type: 'long', + }, + ]; + + test('it flattens the field names and types in the mapping properties', () => { + expect(getFieldTypes(mockMappingsProperties)).toEqual(expected); + }); + + test('it throws a type error when mappingsProperties is not flatten-able', () => { + // @ts-expect-error + const invalidType: Record = []; // <-- this is an array, NOT a valid Record + + expect(() => getFieldTypes(invalidType)).toThrowError('Root value is not flatten-able'); + }); +}); + +describe('isMappingCompatible', () => { + test('it returns true for an exact match', () => { + expect(isMappingCompatible({ ecsExpectedType: 'keyword', type: 'keyword' })).toBe(true); + }); + + test("it returns false when both types don't exactly match", () => { + expect(isMappingCompatible({ ecsExpectedType: 'wildcard', type: 'keyword' })).toBe(false); + }); +}); + +describe('getEnrichedFieldMetadata', () => { + /** + * The ECS schema + * https://raw.githubusercontent.com/elastic/ecs/main/generated/ecs/ecs_flat.yml + * defines a handful of fields that have `allowed_values`. For these + * fields, the documents in an index should only have specific values. + * + * This instance of the type `Record` + * represents an index that doesn't have any unallowed values, for the + * specified keys in the map, i.e. `event.category`, `event.kind`, etc. + * + * This will be used to test the happy path. Variants of this + * value will be used to test unhappy paths. + */ + const noUnallowedValues: Record = { + 'event.category': [], + 'event.kind': [], + 'event.outcome': [], + 'event.type': [], + }; + + /** + * Represents an index that has unallowed values, for the + * `event.category` field. The other fields in the collection, + * i.e. `event.kind`, don't have any unallowed values. + * + * This instance will be used to test paths where a field is + * NOT ECS complaint, because the index has unallowed values. + */ + const unallowedValues: Record = { + 'event.category': [ + { + count: 2, + fieldName: 'an_invalid_category', + }, + { + count: 1, + fieldName: 'theory', + }, + ], + 'event.kind': [], + 'event.outcome': [], + 'event.type': [], + }; + + /** + * This instance of a `FieldType` has the correct mapping for the + * `event.category` field. + * + * This instance will be used to test paths where the index has + * a valid mapping for the `event.category` field. + */ + const fieldMetadataCorrectMappingType: FieldType = { + field: 'event.category', + type: 'keyword', // <-- this index has the correct mapping type + }; + + /** + * This `EnrichedFieldMetadata` for the `event.category` field, + * represents a happy path result, where the index being checked: + * + * 1) The `type` of the field in the index, `keyword`, matches the expected + * `type` of the `event.category` field, as defined by the `EcsMetadata` + * 2) The index doesn't have any unallowed values for the `event.category` field + * + * Since this is a happy path result, it has the following values: + * `indexInvalidValues` is an empty array, because the index does not contain any invalid values + * `isEcsCompliant` is true, because the index has the expected mapping type, and no unallowed values + */ + const happyPathResultSample: EnrichedFieldMetadata = { + dashed_name: 'event-category', + description: + 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy.\n`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory.\nThis field is an array. This will allow proper categorization of some events that fall in multiple categories.', + example: 'authentication', + flat_name: 'event.category', + ignore_above: 1024, + level: 'core', + name: 'category', + normalize: ['array'], + short: 'Event category. The second categorization field in the hierarchy.', + type: 'keyword', + indexFieldName: 'event.category', + indexFieldType: 'keyword', // a valid mapping, because the `type` property from the `ecsMetadata` is also `keyword` + indexInvalidValues: [], // empty array, because the index does not contain any invalid values + hasEcsMetadata: true, + isEcsCompliant: true, // because the index has the expected mapping type, and no unallowed values + isInSameFamily: false, + }; + + /** + * Creates expected result matcher based on the happy path result sample. Please, add similar `expect` based assertions to it if anything breaks + * with an ECS upgrade, instead of hardcoding the values. + */ + const expectedResult = (extraFields: Record = {}) => + expect.objectContaining({ + ...happyPathResultSample, + ...extraFields, + allowed_values: expect.arrayContaining([ + expect.objectContaining({ + description: expect.any(String), + name: expect.any(String), + expected_event_types: expect.any(Array), + }), + ]), + }); + + test('it returns the happy path result when the index has no mapping conflicts, and no unallowed values', () => { + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: fieldMetadataCorrectMappingType, // no mapping conflicts for `event.category` in this index + unallowedValues: noUnallowedValues, // no unallowed values for `event.category` in this index + }) + ).toEqual(expectedResult()); + }); + + test('it returns the happy path result when the index has no mapping conflicts, and the unallowedValues map does not contain an entry for the field', () => { + // create an `unallowedValues` that doesn't have an entry for `event.category`: + const noEntryForEventCategory: Record = omit( + 'event.category', + unallowedValues + ); + + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: fieldMetadataCorrectMappingType, // no mapping conflicts for `event.category` in this index + unallowedValues: noEntryForEventCategory, // a lookup in this map for the `event.category` field will return undefined + }) + ).toEqual(expectedResult()); + }); + + test('it returns a result with the expected `indexInvalidValues` and `isEcsCompliant` when the index has no mapping conflict, but it has unallowed values', () => { + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: fieldMetadataCorrectMappingType, // no mapping conflicts for `event.category` in this index + unallowedValues, // this index has unallowed values for the event.category field + }) + ).toEqual( + expectedResult({ + indexInvalidValues: [ + { + count: 2, + fieldName: 'an_invalid_category', + }, + { + count: 1, + fieldName: 'theory', + }, + ], + isEcsCompliant: false, // because there are unallowed values + }) + ); + }); + + test('it returns a result with the expected `isEcsCompliant` and `isInSameFamily` when the index type does not match ECS, but NO unallowed values', () => { + const indexFieldType = 'text'; + + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: { + field: 'event.category', // `event.category` is a `keyword`, per the ECS spec + type: indexFieldType, // this index has a mapping of `text` instead + }, + unallowedValues: noUnallowedValues, // no unallowed values for `event.category` in this index + }) + ).toEqual( + expectedResult({ + indexFieldType, + isEcsCompliant: false, // `keyword` !== `text` + isInSameFamily: false, // `keyword` and `text` are not in the same family + }) + ); + }); + + test('it returns a result with the expected `isEcsCompliant` and `isInSameFamily` when the mapping is is in the same family', () => { + const indexFieldType = 'wildcard'; + + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: { + field: 'event.category', // `event.category` is a `keyword` per the ECS spec + type: indexFieldType, // this index has a mapping of `wildcard` instead + }, + unallowedValues: noUnallowedValues, // no unallowed values for `event.category` in this index + }) + ).toEqual( + expectedResult({ + indexFieldType, + isEcsCompliant: false, // `wildcard` !== `keyword` + isInSameFamily: true, // `wildcard` and `keyword` are in the same family + }) + ); + }); + + test('it returns a result with the expected `indexInvalidValues`,`isEcsCompliant`, and `isInSameFamily` when the index has BOTH mapping conflicts, and unallowed values', () => { + const indexFieldType = 'text'; + + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: { + field: 'event.category', // `event.category` is a `keyword` per the ECS spec + type: indexFieldType, // this index has a mapping of `text` instead + }, + unallowedValues, // this index also has unallowed values for the event.category field + }) + ).toEqual( + expectedResult({ + indexFieldType, + indexInvalidValues: [ + { + count: 2, + fieldName: 'an_invalid_category', + }, + { + count: 1, + fieldName: 'theory', + }, + ], + isEcsCompliant: false, // because there are BOTH mapping conflicts and unallowed values + isInSameFamily: false, // `text` and `keyword` are not in the same family + }) + ); + }); + + test('it returns the expected result for a custom field, i.e. a field that does NOT have an entry in `ecsMetadata`', () => { + const field = 'a_custom_field'; // not defined by ECS + const indexFieldType = 'keyword'; + + expect( + getEnrichedFieldMetadata({ + ecsMetadata: EcsFlatTyped, + fieldMetadata: { + field, + type: indexFieldType, // no mapping conflict, because ECS doesn't define this field + }, + unallowedValues: noUnallowedValues, // no unallowed values for `a_custom_field` in this index + }) + ).toEqual({ + indexFieldName: field, + indexFieldType, + indexInvalidValues: [], + hasEcsMetadata: false, + isEcsCompliant: false, + isInSameFamily: false, // custom fields are never in the same family + }); + }); +}); + +describe('getMissingTimestampFieldMetadata', () => { + test('it returns the expected `EnrichedFieldMetadata`', () => { + expect(getMissingTimestampFieldMetadata()).toEqual({ + ...EcsFlatTyped['@timestamp'], + hasEcsMetadata: true, + indexFieldName: '@timestamp', + indexFieldType: '-', // the index did NOT define a mapping for @timestamp + indexInvalidValues: [], + isEcsCompliant: false, // an index must define the @timestamp mapping + isInSameFamily: false, // `date` is not a member of any families + }); + }); +}); + +describe('getPartitionedFieldMetadata', () => { + test('it places all the `EnrichedFieldMetadata` in the expected categories', () => { + const enrichedFieldMetadata: EnrichedFieldMetadata[] = [ + timestamp, + eventCategoryWithUnallowedValues, + hostNameWithTextMapping, + hostNameKeyword, + someField, + someFieldKeyword, + sourceIpWithTextMapping, + sourceIpKeyword, + sourcePort, + ]; + const expected: PartitionedFieldMetadata = { + all: [ + timestamp, + eventCategoryWithUnallowedValues, + hostNameWithTextMapping, + hostNameKeyword, + someField, + someFieldKeyword, + sourceIpWithTextMapping, + sourceIpKeyword, + sourcePort, + ], + ecsCompliant: [timestamp, sourcePort], + custom: [hostNameKeyword, someField, someFieldKeyword, sourceIpKeyword], + incompatible: [ + eventCategoryWithUnallowedValues, + hostNameWithTextMapping, + sourceIpWithTextMapping, + ], + sameFamily: [], + }; + + expect(getPartitionedFieldMetadata(enrichedFieldMetadata)).toEqual(expected); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/metadata.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/metadata.ts new file mode 100644 index 0000000000000..87adf1e2314e1 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/utils/metadata.ts @@ -0,0 +1,167 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { has } from 'lodash/fp'; + +import { EcsFlatTyped } from '../../../../../../constants'; +import { + EcsBasedFieldMetadata, + EnrichedFieldMetadata, + PartitionedFieldMetadata, + UnallowedValueCount, +} from '../../../../../../types'; +import { getIsInSameFamily } from './get_is_in_same_family'; + +export const getPartitionedFieldMetadata = ( + enrichedFieldMetadata: EnrichedFieldMetadata[] +): PartitionedFieldMetadata => + enrichedFieldMetadata.reduce( + (acc, x) => ({ + all: [...acc.all, x], + ecsCompliant: x.isEcsCompliant ? [...acc.ecsCompliant, x] : acc.ecsCompliant, + custom: !x.hasEcsMetadata ? [...acc.custom, x] : acc.custom, + incompatible: + x.hasEcsMetadata && !x.isEcsCompliant && !x.isInSameFamily + ? [...acc.incompatible, x] + : acc.incompatible, + sameFamily: x.isInSameFamily ? [...acc.sameFamily, x] : acc.sameFamily, + }), + { + all: [], + ecsCompliant: [], + custom: [], + incompatible: [], + sameFamily: [], + } + ); + +export interface FieldType { + field: string; + type: string; +} + +function shouldReadKeys(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +const getNextPathWithoutProperties = ({ + key, + pathWithoutProperties, + value, +}: { + key: string; + pathWithoutProperties: string; + value: unknown; +}): string => { + if (!pathWithoutProperties) { + return key; + } + + if (shouldReadKeys(value) && (key === 'properties' || key === 'fields')) { + return `${pathWithoutProperties}`; + } else { + return `${pathWithoutProperties}.${key}`; + } +}; + +export function getFieldTypes(mappingsProperties: Record): FieldType[] { + if (!shouldReadKeys(mappingsProperties)) { + throw new TypeError(`Root value is not flatten-able, received ${mappingsProperties}`); + } + + const result: FieldType[] = []; + (function flatten(prefix, object, pathWithoutProperties) { + for (const [key, value] of Object.entries(object)) { + const path = prefix ? `${prefix}.${key}` : key; + + const nextPathWithoutProperties = getNextPathWithoutProperties({ + key, + pathWithoutProperties, + value, + }); + + if (shouldReadKeys(value)) { + flatten(path, value, nextPathWithoutProperties); + } else { + if (nextPathWithoutProperties.endsWith('.type')) { + const pathWithoutType = nextPathWithoutProperties.slice( + 0, + nextPathWithoutProperties.lastIndexOf('.type') + ); + + result.push({ + field: pathWithoutType, + type: `${value}`, + }); + } + } + } + })('', mappingsProperties, ''); + + return result; +} + +export const isMappingCompatible = ({ + ecsExpectedType, + type, +}: { + ecsExpectedType: string | undefined; + type: string; +}): boolean => type === ecsExpectedType; + +export const getEnrichedFieldMetadata = ({ + ecsMetadata, + fieldMetadata, + unallowedValues, +}: { + ecsMetadata: EcsFlatTyped; + fieldMetadata: FieldType; + unallowedValues: Record; +}): EnrichedFieldMetadata => { + const { field, type } = fieldMetadata; + const indexInvalidValues = unallowedValues[field] ?? []; + + if (has(fieldMetadata.field, ecsMetadata)) { + const ecsExpectedType = ecsMetadata[field].type; + const isEcsCompliant = + isMappingCompatible({ ecsExpectedType, type }) && indexInvalidValues.length === 0; + + const isInSameFamily = + !isMappingCompatible({ ecsExpectedType, type }) && + indexInvalidValues.length === 0 && + getIsInSameFamily({ ecsExpectedType, type }); + + return { + ...ecsMetadata[field], + indexFieldName: field, + indexFieldType: type, + indexInvalidValues, + hasEcsMetadata: true, + isEcsCompliant, + isInSameFamily, + }; + } else { + return { + indexFieldName: field, + indexFieldType: type, + indexInvalidValues: [], + hasEcsMetadata: false, + isEcsCompliant: false, + isInSameFamily: false, // custom fields are never in the same family + }; + } +}; + +export const getMissingTimestampFieldMetadata = (): EcsBasedFieldMetadata => ({ + ...EcsFlatTyped['@timestamp'], + hasEcsMetadata: true, + indexFieldName: '@timestamp', + indexFieldType: '-', + indexInvalidValues: [], + isEcsCompliant: false, + isInSameFamily: false, // `date` is not a member of any families +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/index_check_flyout/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/helpers.test.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/helpers.test.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/helpers.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/helpers.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/index.test.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/index.test.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/index_result_badge/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/index_result_badge/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/loading_empty_prompt/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/loading_empty_prompt/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/loading_empty_prompt/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/loading_empty_prompt/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/index.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/index.tsx index c30fd3e7dc4ce..db4d95ba48b4f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/index.tsx @@ -8,9 +8,9 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; -import type { IlmExplainPhaseCounts } from '../../../types'; +import type { IlmExplainPhaseCounts } from '../../../../types'; import { PatternLabel } from './pattern_label'; -import { StatsRollup } from './stats_rollup'; +import { StatsRollup } from '../../../../stats_rollup'; interface Props { ilmExplainPhaseCounts: IlmExplainPhaseCounts | undefined; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/helpers.test.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/helpers.test.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/helpers.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/helpers.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/ilm_phase_counts/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/index.test.tsx similarity index 93% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/ilm_phase_counts/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/index.test.tsx index 23031b9210df1..f9e04fc707b01 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/ilm_phase_counts/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/index.test.tsx @@ -13,9 +13,9 @@ import { import { render, screen } from '@testing-library/react'; import React from 'react'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../../../mock/test_providers/test_providers'; import { IlmPhaseCounts } from '.'; -import { getIlmExplainPhaseCounts } from '../pattern/helpers'; +import { getIlmExplainPhaseCounts } from '../../../helpers'; const hot: IlmExplainLifecycleLifecycleExplainManaged = { index: '.ds-packetbeat-8.6.1-2023.02.04-000001', diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/ilm_phase_counts/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/ilm_phase_counts/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/index.tsx index b24014bb400e6..c1d1ead5e7891 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/ilm_phase_counts/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/index.tsx @@ -9,8 +9,8 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { getPatternIlmPhaseDescription } from '../../helpers'; -import type { IlmExplainPhaseCounts, IlmPhase } from '../../types'; +import type { IlmExplainPhaseCounts, IlmPhase } from '../../../../../../types'; +import { getPatternIlmPhaseDescription } from './utils/get_pattern_ilm_phase_description'; const PhaseCountsFlexGroup = styled(EuiFlexGroup)` display: inline-flex; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/translations.ts new file mode 100644 index 0000000000000..d6a87384c9ae4 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/translations.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const UNMANAGED_PATTERN_TOOLTIP = ({ + indices, + pattern, +}: { + indices: number; + pattern: string; +}) => + i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.unmanagedPatternTooltip', { + values: { indices, pattern }, + defaultMessage: `{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} unmanaged by Index Lifecycle Management (ILM)`, + }); + +export const WARM_PATTERN_TOOLTIP = ({ indices, pattern }: { indices: number; pattern: string }) => + i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.warmPatternTooltip', { + values: { indices, pattern }, + defaultMessage: + '{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} warm. Warm indices are no longer being updated but are still being queried.', + }); + +export const HOT_PATTERN_TOOLTIP = ({ indices, pattern }: { indices: number; pattern: string }) => + i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.hotPatternTooltip', { + values: { indices, pattern }, + defaultMessage: + '{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} hot. Hot indices are actively being updated and queried.', + }); + +export const FROZEN_PATTERN_TOOLTIP = ({ + indices, + pattern, +}: { + indices: number; + pattern: string; +}) => + i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.frozenPatternTooltip', { + values: { indices, pattern }, + defaultMessage: `{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} frozen. Frozen indices are no longer being updated and are queried rarely. The information still needs to be searchable, but it's okay if those queries are extremely slow.`, + }); + +export const COLD_PATTERN_TOOLTIP = ({ indices, pattern }: { indices: number; pattern: string }) => + i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.coldPatternTooltip', { + values: { indices, pattern }, + defaultMessage: + '{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} cold. Cold indices are no longer being updated and are queried infrequently. The information still needs to be searchable, but it’s okay if those queries are slower.', + }); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/utils/get_pattern_ilm_phase_description.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/utils/get_pattern_ilm_phase_description.test.ts new file mode 100644 index 0000000000000..3faff162dbffa --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/utils/get_pattern_ilm_phase_description.test.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getPatternIlmPhaseDescription } from './get_pattern_ilm_phase_description'; + +describe('getPatternIlmPhaseDescription', () => { + const phases: Array<{ + expected: string; + indices: number; + pattern: string; + phase: string; + }> = [ + { + expected: + '1 index matching the .alerts-security.alerts-default pattern is hot. Hot indices are actively being updated and queried.', + indices: 1, + pattern: '.alerts-security.alerts-default', + phase: 'hot', + }, + { + expected: + '2 indices matching the .alerts-security.alerts-default pattern are hot. Hot indices are actively being updated and queried.', + indices: 2, + pattern: '.alerts-security.alerts-default', + phase: 'hot', + }, + { + expected: + '1 index matching the .alerts-security.alerts-default pattern is warm. Warm indices are no longer being updated but are still being queried.', + indices: 1, + pattern: '.alerts-security.alerts-default', + phase: 'warm', + }, + { + expected: + '2 indices matching the .alerts-security.alerts-default pattern are warm. Warm indices are no longer being updated but are still being queried.', + indices: 2, + pattern: '.alerts-security.alerts-default', + phase: 'warm', + }, + { + expected: + '1 index matching the .alerts-security.alerts-default pattern is cold. Cold indices are no longer being updated and are queried infrequently. The information still needs to be searchable, but it’s okay if those queries are slower.', + indices: 1, + pattern: '.alerts-security.alerts-default', + phase: 'cold', + }, + { + expected: + '2 indices matching the .alerts-security.alerts-default pattern are cold. Cold indices are no longer being updated and are queried infrequently. The information still needs to be searchable, but it’s okay if those queries are slower.', + indices: 2, + pattern: '.alerts-security.alerts-default', + phase: 'cold', + }, + { + expected: + "1 index matching the .alerts-security.alerts-default pattern is frozen. Frozen indices are no longer being updated and are queried rarely. The information still needs to be searchable, but it's okay if those queries are extremely slow.", + indices: 1, + pattern: '.alerts-security.alerts-default', + phase: 'frozen', + }, + { + expected: + "2 indices matching the .alerts-security.alerts-default pattern are frozen. Frozen indices are no longer being updated and are queried rarely. The information still needs to be searchable, but it's okay if those queries are extremely slow.", + indices: 2, + pattern: '.alerts-security.alerts-default', + phase: 'frozen', + }, + { + expected: + '1 index matching the .alerts-security.alerts-default pattern is unmanaged by Index Lifecycle Management (ILM)', + indices: 1, + pattern: '.alerts-security.alerts-default', + phase: 'unmanaged', + }, + { + expected: + '2 indices matching the .alerts-security.alerts-default pattern are unmanaged by Index Lifecycle Management (ILM)', + indices: 2, + pattern: '.alerts-security.alerts-default', + phase: 'unmanaged', + }, + { + expected: '', + indices: 1, + pattern: '.alerts-security.alerts-default', + phase: 'some-other-phase', + }, + { + expected: '', + indices: 2, + pattern: '.alerts-security.alerts-default', + phase: 'some-other-phase', + }, + ]; + + phases.forEach(({ expected, indices, pattern, phase }) => { + test(`it returns the expected description when indices is ${indices}, pattern is ${pattern}, and phase is ${phase}`, () => { + expect(getPatternIlmPhaseDescription({ indices, pattern, phase })).toBe(expected); + }); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/utils/get_pattern_ilm_phase_description.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/utils/get_pattern_ilm_phase_description.ts new file mode 100644 index 0000000000000..20adb0c0c5bf9 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/ilm_phase_counts/utils/get_pattern_ilm_phase_description.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 * as i18n from '../translations'; + +export const getPatternIlmPhaseDescription = ({ + indices, + pattern, + phase, +}: { + indices: number; + pattern: string; + phase: string; +}): string => { + switch (phase) { + case 'hot': + return i18n.HOT_PATTERN_TOOLTIP({ indices, pattern }); + case 'warm': + return i18n.WARM_PATTERN_TOOLTIP({ indices, pattern }); + case 'cold': + return i18n.COLD_PATTERN_TOOLTIP({ indices, pattern }); + case 'frozen': + return i18n.FROZEN_PATTERN_TOOLTIP({ indices, pattern }); + case 'unmanaged': + return i18n.UNMANAGED_PATTERN_TOOLTIP({ indices, pattern }); + default: + return ''; + } +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/index.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/index.tsx index 62ff66a873124..03fede1fb7675 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/index.tsx @@ -9,10 +9,10 @@ import { EuiTitle, EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { getPatternResultTooltip, showResult } from './helpers'; -import { IlmPhaseCounts } from '../../../ilm_phase_counts'; +import { IlmPhaseCounts } from './ilm_phase_counts'; import * as i18n from '../translations'; -import type { IlmExplainPhaseCounts } from '../../../../types'; -import { IndexResultBadge } from '../../../index_result_badge'; +import type { IlmExplainPhaseCounts } from '../../../../../types'; +import { IndexResultBadge } from '../../index_result_badge'; interface Props { incompatible: number | undefined; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/pattern_label/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/pattern_label/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/pattern_summary/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/remote_clusters_callout/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/remote_clusters_callout/index.test.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/remote_clusters_callout/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/remote_clusters_callout/index.test.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/remote_clusters_callout/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/remote_clusters_callout/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/remote_clusters_callout/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/remote_clusters_callout/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/remote_clusters_callout/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/remote_clusters_callout/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/remote_clusters_callout/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/remote_clusters_callout/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/styles.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/styles.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/styles.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/styles.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/helpers.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/helpers.test.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/helpers.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/helpers.test.tsx index a4227f0631819..1efaa01d36f9e 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/helpers.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/helpers.test.tsx @@ -16,8 +16,8 @@ import userEvent from '@testing-library/user-event'; import { omit } from 'lodash/fp'; import React from 'react'; -import { TestExternalProviders } from '../../mock/test_providers/test_providers'; -import { EMPTY_STAT } from '../../helpers'; +import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; +import { EMPTY_STAT } from '../../../../constants'; import { getDocsCountPercent, getIncompatibleStatColor, @@ -28,8 +28,8 @@ import { getToggleButtonId, } from './helpers'; import { CHECK_INDEX, VIEW_CHECK_DETAILS } from './translations'; -import { IndexSummaryTableItem } from '../pattern/types'; -import { getCheckState } from '../../stub/get_check_state'; +import { IndexSummaryTableItem } from '../types'; +import { getCheckState } from '../../../../stub/get_check_state'; const defaultBytesFormat = '0,0.[0]b'; const formatBytes = (value: number | undefined) => diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/helpers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/helpers.tsx similarity index 93% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/helpers.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/helpers.tsx index f8e5b8d1b271e..327c5b5e46667 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/helpers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/helpers.tsx @@ -18,15 +18,16 @@ import moment from 'moment'; import styled from 'styled-components'; import { euiThemeVars } from '@kbn/ui-theme'; -import { EMPTY_STAT, getIlmPhaseDescription } from '../../helpers'; -import { INCOMPATIBLE_INDEX_TOOL_TIP } from '../stat_label/translations'; -import { INDEX_SIZE_TOOLTIP } from '../../translations'; +import { EMPTY_STAT } from '../../../../constants'; +import { getIlmPhaseDescription } from '../../../../utils/get_ilm_phase_description'; +import { INCOMPATIBLE_INDEX_TOOL_TIP } from '../../../../stat_label/translations'; +import { INDEX_SIZE_TOOLTIP } from '../../../../translations'; import * as i18n from './translations'; -import { IndexSummaryTableItem } from '../pattern/types'; -import { UseIndicesCheckCheckState } from '../../use_indices_check/types'; +import { IndexSummaryTableItem } from '../types'; +import { UseIndicesCheckCheckState } from '../../../../hooks/use_indices_check/types'; import { IndexResultBadge } from '../index_result_badge'; import { getIndexResultToolTip } from '../index_result_badge/helpers'; -import { Stat } from '../pattern/pattern_summary/stats_rollup/stat'; +import { Stat } from '../../../../stat'; const ProgressContainer = styled.div` width: 150px; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/index.test.tsx similarity index 86% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/index.test.tsx index 24d57f927e6ea..01d45a3784a5f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/index.test.tsx @@ -9,17 +9,17 @@ import numeral from '@elastic/numeral'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import { EMPTY_STAT } from '../../helpers'; +import { EMPTY_STAT } from '../../../../constants'; import { getSummaryTableColumns } from './helpers'; -import { mockIlmExplain } from '../../mock/ilm_explain/mock_ilm_explain'; -import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { mockStats } from '../../mock/stats/mock_stats'; +import { mockIlmExplain } from '../../../../mock/ilm_explain/mock_ilm_explain'; +import { auditbeatWithAllResults } from '../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { mockStats } from '../../../../mock/stats/mock_stats'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../mock/test_providers/test_providers'; -import { getSummaryTableItems } from '../pattern/helpers'; -import { SortConfig } from '../../types'; +} from '../../../../mock/test_providers/test_providers'; +import { getSummaryTableItems } from '../helpers'; +import { SortConfig } from '../../../../types'; import { Props, SummaryTable } from '.'; const defaultBytesFormat = '0,0.[0]b'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/index.tsx similarity index 91% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/index.tsx index cc09109ea16f9..fad209fb29e54 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/index.tsx @@ -10,11 +10,11 @@ import { EuiInMemoryTable } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; import { getShowPagination } from './helpers'; -import { defaultSort, MIN_PAGE_SIZE } from '../pattern/helpers'; -import { SortConfig } from '../../types'; -import { useDataQualityContext } from '../data_quality_context'; -import { IndexSummaryTableItem } from '../pattern/types'; -import { UseIndicesCheckCheckState } from '../../use_indices_check/types'; +import { defaultSort, MIN_PAGE_SIZE } from '../helpers'; +import { SortConfig } from '../../../../types'; +import { useDataQualityContext } from '../../../../data_quality_context'; +import { IndexSummaryTableItem } from '../types'; +import { UseIndicesCheckCheckState } from '../../../../hooks/use_indices_check/types'; export interface Props { getTableColumns: ({ diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/summary_table/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/summary_table/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/types.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/types.ts similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/types.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/types.ts index b079976950f1b..e44300859bffd 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/types.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IlmPhase } from '../../types'; +import { IlmPhase } from '../../../types'; export interface IndexSummaryTableItem { docsCount: number; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/utils/stats.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/utils/stats.test.ts new file mode 100644 index 0000000000000..306c9f93d83b6 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/utils/stats.test.ts @@ -0,0 +1,234 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { omit } from 'lodash/fp'; + +import { mockStatsAuditbeatIndex } from '../../../../mock/stats/mock_stats_packetbeat_index'; +import { mockStatsPacketbeatIndex } from '../../../../mock/stats/mock_stats_auditbeat_index'; +import { mockIlmExplain } from '../../../../mock/ilm_explain/mock_ilm_explain'; +import { mockStats } from '../../../../mock/stats/mock_stats'; +import { getIndexNames, getPatternDocsCount, getPatternSizeInBytes } from './stats'; +import { IlmExplainLifecycleLifecycleExplain } from '@elastic/elasticsearch/lib/api/types'; + +describe('getIndexNames', () => { + const isILMAvailable = true; + const ilmPhases = ['hot', 'warm', 'unmanaged']; + + test('returns the expected index names when they have an ILM phase included in the ilmPhases list', () => { + expect( + getIndexNames({ + ilmExplain: mockIlmExplain, // <-- the mock indexes have 'hot' ILM phases + ilmPhases, + isILMAvailable, + stats: mockStats, + }) + ).toEqual([ + '.ds-packetbeat-8.6.1-2023.02.04-000001', + '.ds-packetbeat-8.5.3-2023.02.04-000001', + 'auditbeat-custom-index-1', + ]); + }); + + test('returns the expected filtered index names when they do NOT have an ILM phase included in the ilmPhases list', () => { + expect( + getIndexNames({ + ilmExplain: mockIlmExplain, // <-- the mock indexes have 'hot' and 'unmanaged' ILM phases... + ilmPhases: ['warm', 'unmanaged'], // <-- ...but we don't ask for 'hot' + isILMAvailable, + stats: mockStats, + }) + ).toEqual(['auditbeat-custom-index-1']); // <-- the 'unmanaged' index + }); + + test('returns the expected index names when the `ilmExplain` is missing a record for an index', () => { + // the following `ilmExplain` is missing a record for one of the two packetbeat indexes: + const ilmExplainWithMissingIndex: Record = omit( + '.ds-packetbeat-8.6.1-2023.02.04-000001', + mockIlmExplain + ); + + expect( + getIndexNames({ + ilmExplain: ilmExplainWithMissingIndex, // <-- the mock indexes have 'hot' ILM phases... + ilmPhases: ['hot', 'warm', 'unmanaged'], + isILMAvailable, + stats: mockStats, + }) + ).toEqual(['.ds-packetbeat-8.5.3-2023.02.04-000001', 'auditbeat-custom-index-1']); // <-- only includes two of the three indices, because the other one is missing an ILM explain record + }); + + test('returns empty index names when `ilmPhases` is empty', () => { + expect( + getIndexNames({ + ilmExplain: mockIlmExplain, + ilmPhases: [], + isILMAvailable, + stats: mockStats, + }) + ).toEqual([]); + }); + + test('returns empty index names when they have an ILM phase that matches', () => { + expect( + getIndexNames({ + ilmExplain: null, + ilmPhases, + isILMAvailable, + stats: mockStats, + }) + ).toEqual([]); + }); + + test('returns empty index names when just `stats` is null', () => { + expect( + getIndexNames({ + ilmExplain: mockIlmExplain, + ilmPhases, + isILMAvailable, + stats: null, + }) + ).toEqual([]); + }); + + test('returns empty index names when both `ilmExplain` and `stats` are null', () => { + expect( + getIndexNames({ + ilmExplain: null, + ilmPhases, + isILMAvailable, + stats: null, + }) + ).toEqual([]); + }); +}); + +describe('getPatternDocsCount', () => { + test('it returns the expected total given a subset of index names in the stats', () => { + const indexName = '.ds-packetbeat-8.5.3-2023.02.04-000001'; + const expectedCount = mockStatsPacketbeatIndex[indexName].num_docs; + + expect( + getPatternDocsCount({ + indexNames: [indexName], + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(expectedCount); + }); + + test('it returns the expected total given all index names in the stats', () => { + const allIndexNamesInStats = [ + '.ds-packetbeat-8.6.1-2023.02.04-000001', + '.ds-packetbeat-8.5.3-2023.02.04-000001', + ]; + + expect( + getPatternDocsCount({ + indexNames: allIndexNamesInStats, + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(3258632); + }); + + test('it returns zero given an empty collection of index names', () => { + expect( + getPatternDocsCount({ + indexNames: [], // <-- empty + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(0); + }); + + test('it returns the expected total for a green index', () => { + const indexName = 'auditbeat-custom-index-1'; + const expectedCount = mockStatsAuditbeatIndex[indexName].num_docs; + + expect( + getPatternDocsCount({ + indexNames: [indexName], + stats: mockStatsAuditbeatIndex, + }) + ).toEqual(expectedCount); + }); +}); + +describe('getPatternSizeInBytes', () => { + test('it returns the expected total given a subset of index names in the stats', () => { + const indexName = '.ds-packetbeat-8.5.3-2023.02.04-000001'; + const expectedCount = mockStatsPacketbeatIndex[indexName].size_in_bytes; + + expect( + getPatternSizeInBytes({ + indexNames: [indexName], + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(expectedCount); + }); + + test('it returns the expected total given all index names in the stats', () => { + const allIndexNamesInStats = [ + '.ds-packetbeat-8.6.1-2023.02.04-000001', + '.ds-packetbeat-8.5.3-2023.02.04-000001', + ]; + + expect( + getPatternSizeInBytes({ + indexNames: allIndexNamesInStats, + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(1464758182); + }); + + test('it returns undefined given an empty collection of index names', () => { + expect( + getPatternSizeInBytes({ + indexNames: [], // <-- empty + stats: mockStatsPacketbeatIndex, + }) + ).toBeUndefined(); + }); + + test('it returns undefined if sizeInByte in not an integer', () => { + const indexName = 'auditbeat-custom-index-1'; + + expect( + getPatternSizeInBytes({ + indexNames: [indexName], + stats: { [indexName]: { ...mockStatsAuditbeatIndex[indexName], size_in_bytes: null } }, + }) + ).toBeUndefined(); + }); + + test('it returns the expected total for an index', () => { + const indexName = 'auditbeat-custom-index-1'; + const expectedCount = mockStatsAuditbeatIndex[indexName].size_in_bytes; + + expect( + getPatternSizeInBytes({ + indexNames: [indexName], + stats: mockStatsAuditbeatIndex, + }) + ).toEqual(expectedCount); + }); + + test('it returns the expected total for indices', () => { + const expectedCount = Object.values(mockStatsPacketbeatIndex).reduce( + (acc, { size_in_bytes: sizeInBytes }) => { + return acc + (sizeInBytes ?? 0); + }, + 0 + ); + + expect( + getPatternSizeInBytes({ + indexNames: [ + '.ds-packetbeat-8.6.1-2023.02.04-000001', + '.ds-packetbeat-8.5.3-2023.02.04-000001', + ], + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(expectedCount); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/utils/stats.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/utils/stats.ts new file mode 100644 index 0000000000000..83e2b592dc079 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/indices_details/pattern/utils/stats.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IlmExplainLifecycleLifecycleExplain } from '@elastic/elasticsearch/lib/api/types'; + +import { getDocsCount, getSizeInBytes } from '../../../../utils/stats'; +import { MeteringStatsIndex } from '../../../../types'; +import { getIlmPhase } from '../helpers'; + +export const getPatternDocsCount = ({ + indexNames, + stats, +}: { + indexNames: string[]; + stats: Record | null; +}): number => + indexNames.reduce( + (acc: number, indexName: string) => acc + getDocsCount({ stats, indexName }), + 0 + ); + +export const getPatternSizeInBytes = ({ + indexNames, + stats, +}: { + indexNames: string[]; + stats: Record | null; +}): number | undefined => { + let sum; + for (let i = 0; i < indexNames.length; i++) { + const currentSizeInBytes = getSizeInBytes({ stats, indexName: indexNames[i] }); + if (currentSizeInBytes != null) { + if (sum == null) { + sum = 0; + } + sum += currentSizeInBytes; + } else { + return undefined; + } + } + return sum; +}; + +const EMPTY_INDEX_NAMES: string[] = []; +export const getIndexNames = ({ + ilmExplain, + ilmPhases, + isILMAvailable, + stats, +}: { + ilmExplain: Record | null; + ilmPhases: string[]; + isILMAvailable: boolean; + stats: Record | null; +}): string[] => { + if (((isILMAvailable && ilmExplain != null) || !isILMAvailable) && stats != null) { + const allIndexNames = Object.keys(stats); + const filteredByIlmPhase = isILMAvailable + ? allIndexNames.filter((indexName) => + ilmPhases.includes(getIlmPhase(ilmExplain?.[indexName], isILMAvailable) ?? '') + ) + : allIndexNames; + + return filteredByIlmPhase; + } else { + return EMPTY_INDEX_NAMES; + } +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/helpers.test.ts similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/helpers.test.ts index 650b70586d19f..da46cd2b40f33 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/helpers.test.ts @@ -8,7 +8,7 @@ import numeral from '@elastic/numeral'; import { euiThemeVars } from '@kbn/ui-theme'; -import { EMPTY_STAT } from '../../../../helpers'; +import { EMPTY_STAT } from '../../constants'; import { DEFAULT_INDEX_COLOR, getFillColor, @@ -21,10 +21,10 @@ import { getPatternLegendItem, getPatternSizeInBytes, } from './helpers'; -import { alertIndexWithAllResults } from '../../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { auditbeatWithAllResults } from '../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { packetbeatNoResults } from '../../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; -import { PatternRollup } from '../../../../types'; +import { alertIndexWithAllResults } from '../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatNoResults } from '../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { PatternRollup } from '../../types'; const defaultBytesFormat = '0,0.[0]b'; const formatBytes = (value: number | undefined) => diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/helpers.ts similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/helpers.ts index 3eaf493222cb0..283854a62acf2 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/helpers.ts @@ -9,9 +9,9 @@ import type { Datum, Key, ArrayNode } from '@elastic/charts'; import { euiThemeVars } from '@kbn/ui-theme'; import { orderBy } from 'lodash/fp'; -import { getDocsCount, getSizeInBytes } from '../../../../helpers'; -import { getIlmPhase } from '../../../pattern/helpers'; -import { PatternRollup } from '../../../../types'; +import { getIlmPhase } from '../indices_details/pattern/helpers'; +import { PatternRollup } from '../../types'; +import { getDocsCount, getSizeInBytes } from '../../utils/stats'; export interface LegendItem { color: string | null; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/index.test.tsx similarity index 79% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/index.test.tsx index 5dd06ad340474..3ebb44a8306ef 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/index.test.tsx @@ -9,15 +9,15 @@ import numeral from '@elastic/numeral'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import { EMPTY_STAT } from '../../../../helpers'; -import { alertIndexWithAllResults } from '../../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { auditbeatWithAllResults } from '../../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { packetbeatNoResults } from '../../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { EMPTY_STAT } from '../../constants'; +import { alertIndexWithAllResults } from '../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatNoResults } from '../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../../mock/test_providers/test_providers'; -import { PatternRollup } from '../../../../types'; +} from '../../mock/test_providers/test_providers'; +import { PatternRollup } from '../../types'; import { Props, StorageDetails } from '.'; const defaultBytesFormat = '0,0.[0]b'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/index.tsx similarity index 81% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/index.tsx index ff43116c02878..cfde7c0342585 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/index.tsx @@ -7,12 +7,12 @@ import React, { useCallback, useMemo } from 'react'; -import { useResultsRollupContext } from '../../../../contexts/results_rollup_context'; +import { useResultsRollupContext } from '../../contexts/results_rollup_context'; import { getFlattenedBuckets } from './helpers'; -import { StorageTreemap } from '../../../storage_treemap'; -import { DEFAULT_MAX_CHART_HEIGHT } from '../../../tabs/styles'; -import { SelectedIndex } from '../../../../types'; -import { useDataQualityContext } from '../../../data_quality_context'; +import { StorageTreemap } from './storage_treemap'; +import { DEFAULT_MAX_CHART_HEIGHT } from '../indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/styles'; +import { SelectedIndex } from '../../types'; +import { useDataQualityContext } from '../../data_quality_context'; import { DOCS_UNIT } from './translations'; export interface Props { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/chart_legend_item/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/chart_legend_item/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/chart_legend_item/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/chart_legend_item/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/index.test.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/index.test.tsx index 5e22bc185b1c1..a8998a134416f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/index.test.tsx @@ -11,24 +11,20 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { - FlattenedBucket, - getFlattenedBuckets, - getLegendItems, -} from '../body/data_quality_details/storage_details/helpers'; -import { EMPTY_STAT } from '../../helpers'; -import { alertIndexWithAllResults } from '../../mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { packetbeatNoResults } from '../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { FlattenedBucket, getFlattenedBuckets, getLegendItems } from '../helpers'; +import { EMPTY_STAT } from '../../../constants'; +import { alertIndexWithAllResults } from '../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatNoResults } from '../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../mock/test_providers/test_providers'; +} from '../../../mock/test_providers/test_providers'; import type { Props } from '.'; import { StorageTreemap } from '.'; -import { DEFAULT_MAX_CHART_HEIGHT } from '../tabs/styles'; +import { DEFAULT_MAX_CHART_HEIGHT } from '../../indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/styles'; import { NO_DATA_LABEL } from './translations'; -import { PatternRollup } from '../../types'; +import { PatternRollup } from '../../../types'; const defaultBytesFormat = '0,0.[0]b'; const formatBytes = (value: number | undefined) => diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/index.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/index.tsx index e56cbadc66009..fbabe4412e493 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/index.tsx @@ -27,12 +27,15 @@ import { getLayersMultiDimensional, getLegendItems, getPathToFlattenedBucketMap, -} from '../body/data_quality_details/storage_details/helpers'; +} from '../helpers'; import { ChartLegendItem } from './chart_legend_item'; import { NoData } from './no_data'; -import { ChartFlexItem, LegendContainer } from '../tabs/styles'; -import { PatternRollup, SelectedIndex } from '../../types'; -import { useDataQualityContext } from '../data_quality_context'; +import { + ChartFlexItem, + LegendContainer, +} from '../../indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/styles'; +import { PatternRollup, SelectedIndex } from '../../../types'; +import { useDataQualityContext } from '../../../data_quality_context'; export const DEFAULT_MIN_CHART_HEIGHT = 240; // px export const LEGEND_WIDTH = 220; // px diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/no_data/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/no_data/index.test.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/no_data/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/no_data/index.test.tsx index 95503d7f156bd..dbb6dd955c9ea 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/no_data/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/no_data/index.test.tsx @@ -11,7 +11,7 @@ import React from 'react'; import * as i18n from '../translations'; import { NoData } from '.'; -import { TestExternalProviders } from '../../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; describe('NoData', () => { test('renders the expected "no data" message', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/no_data/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/no_data/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/no_data/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/no_data/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/storage_treemap/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/storage_treemap/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/body/data_quality_details/storage_details/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_details/storage_details/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/index.test.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/index.test.tsx index d2d0a388c465d..4a821d1251ddc 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/index.test.tsx @@ -13,7 +13,7 @@ import { IlmPhaseFilter } from '.'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; +} from '../../mock/test_providers/test_providers'; import { COLD_DESCRIPTION, FROZEN_DESCRIPTION, @@ -21,7 +21,7 @@ import { INDEX_LIFECYCLE_MANAGEMENT_PHASES, UNMANAGED_DESCRIPTION, WARM_DESCRIPTION, -} from '../../../translations'; +} from '../../translations'; describe('IlmPhaseFilter', () => { it('renders combobox with ilmPhase label and preselected hot, warm, unmanaged options', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/index.tsx similarity index 93% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/index.tsx index d0411349662fd..cd7148d38b3aa 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/index.tsx @@ -14,13 +14,13 @@ import { } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; -import { ilmPhaseOptionsStatic } from '../../../constants'; -import { getIlmPhaseDescription } from '../../../helpers'; +import { ilmPhaseOptionsStatic } from '../../constants'; +import { getIlmPhaseDescription } from '../../utils/get_ilm_phase_description'; import { ILM_PHASE, INDEX_LIFECYCLE_MANAGEMENT_PHASES, SELECT_ONE_OR_MORE_ILM_PHASES, -} from '../../../translations'; +} from '../../translations'; import { useDataQualityContext } from '../../data_quality_context'; import { StyledFormControlLayout, StyledOption, StyledOptionLabel } from './styles'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/styles.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/styles.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/ilm_phase_filter/styles.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/ilm_phase_filter/styles.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/index.test.tsx similarity index 86% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/index.test.tsx index 6b8994e0d7919..322d30be6dd81 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/index.test.tsx @@ -9,15 +9,15 @@ import numeral from '@elastic/numeral'; import { render, screen } from '@testing-library/react'; import React from 'react'; -import { EMPTY_STAT } from '../../helpers'; -import { alertIndexWithAllResults } from '../../mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { packetbeatNoResults } from '../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { EMPTY_STAT } from '../constants'; +import { alertIndexWithAllResults } from '../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatNoResults } from '../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../mock/test_providers/test_providers'; -import { PatternRollup } from '../../types'; +} from '../mock/test_providers/test_providers'; +import { PatternRollup } from '../types'; import { DataQualitySummary } from '.'; import { getTotalDocsCount, @@ -25,7 +25,7 @@ import { getTotalIndices, getTotalIndicesChecked, getTotalSizeInBytes, -} from '../../use_results_rollup/helpers'; +} from '../hooks/use_results_rollup/utils/stats'; const defaultBytesFormat = '0,0.[0]b'; const formatBytes = (value: number | undefined) => diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/index.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/index.tsx index eca684ce5c218..09c98c1a84197 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/index.tsx @@ -9,11 +9,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { StatsRollup } from '../pattern/pattern_summary/stats_rollup'; +import { StatsRollup } from '../stats_rollup'; import { SummaryActions } from './summary_actions'; import { IlmPhaseFilter } from './ilm_phase_filter'; import { useDataQualityContext } from '../data_quality_context'; -import { useResultsRollupContext } from '../../contexts/results_rollup_context'; +import { useResultsRollupContext } from '../contexts/results_rollup_context'; const MAX_SUMMARY_ACTIONS_CONTAINER_WIDTH = 400; const MIN_SUMMARY_ACTIONS_CONTAINER_WIDTH = 235; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.test.ts similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.test.ts index 5f96cfa9953a6..2b37622baa655 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.test.ts @@ -6,7 +6,7 @@ */ import { getAllIndicesToCheck, getIndexDocsCountFromRollup, getIndexToCheck } from './helpers'; -import { mockPacketbeatPatternRollup } from '../../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { mockPacketbeatPatternRollup } from '../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; const patternIndexNames: Record = { 'packetbeat-*': [ diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.ts similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.ts index ede3184350e58..dfbc0f69f82aa 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/helpers.ts @@ -7,8 +7,8 @@ import { orderBy } from 'lodash/fp'; -import { getDocsCount } from '../../../../helpers'; -import type { IndexToCheck, MeteringStatsIndex, PatternRollup } from '../../../../types'; +import type { IndexToCheck, MeteringStatsIndex, PatternRollup } from '../../../types'; +import { getDocsCount } from '../../../utils/stats'; export const getIndexToCheck = ({ indexName, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx index 97e93124b84cf..14368907362fb 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.test.tsx @@ -10,16 +10,16 @@ import userEvent from '@testing-library/user-event'; import { act, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; -import { mockMappingsResponse } from '../../../../mock/mappings_response/mock_mappings_response'; +import { mockMappingsResponse } from '../../../mock/mappings_response/mock_mappings_response'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../../mock/test_providers/test_providers'; -import { mockUnallowedValuesResponse } from '../../../../mock/unallowed_values/mock_unallowed_values'; -import { CANCEL, CHECK_ALL } from '../../../../translations'; -import { OnCheckCompleted, UnallowedValueRequestItem } from '../../../../types'; +} from '../../../mock/test_providers/test_providers'; +import { mockUnallowedValuesResponse } from '../../../mock/unallowed_values/mock_unallowed_values'; +import { CANCEL, CHECK_ALL } from '../../../translations'; +import { OnCheckCompleted, UnallowedValueRequestItem } from '../../../types'; import { CheckAll } from '.'; -import { EMPTY_STAT } from '../../../../helpers'; +import { EMPTY_STAT } from '../../../constants'; const defaultBytesFormat = '0,0.[0]b'; const mockFormatBytes = (value: number | undefined) => @@ -35,16 +35,19 @@ const mockFetchMappings = jest.fn(() => ) ); -jest.mock('../../../../use_mappings/helpers', () => ({ - fetchMappings: (_: { abortController: AbortController; patternOrIndexName: string }) => - mockFetchMappings(), -})); +jest.mock('../../../utils/fetch_mappings', () => { + const original = jest.requireActual('../../../utils/fetch_mappings'); + return { + ...original, + fetchMappings: (_: { abortController: AbortController; patternOrIndexName: string }) => + mockFetchMappings(), + }; +}); const mockFetchUnallowedValues = jest.fn(() => Promise.resolve(mockUnallowedValuesResponse)); -jest.mock('../../../../use_unallowed_values/helpers', () => { - const original = jest.requireActual('../../../../use_unallowed_values/helpers'); - +jest.mock('../../../utils/fetch_unallowed_values', () => { + const original = jest.requireActual('../../../utils/fetch_unallowed_values'); return { ...original, fetchUnallowedValues: (_: { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.tsx index c8bb58de2ef44..e2851ee4b3761 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/index.tsx @@ -10,12 +10,12 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import { v4 as uuidv4 } from 'uuid'; -import { useResultsRollupContext } from '../../../../contexts/results_rollup_context'; -import { checkIndex } from '../../../../utils/check_index'; -import { useDataQualityContext } from '../../../data_quality_context'; import { getAllIndicesToCheck } from './helpers'; -import * as i18n from '../../../../translations'; -import type { IndexToCheck } from '../../../../types'; +import { useResultsRollupContext } from '../../../contexts/results_rollup_context'; +import { checkIndex } from '../../../utils/check_index'; +import { useDataQualityContext } from '../../../data_quality_context'; +import * as i18n from '../../../translations'; +import type { IndexToCheck } from '../../../types'; const CheckAllButton = styled(EuiButton)` width: 112px; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/check_all/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_all/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/helpers.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/helpers.test.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/helpers.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/helpers.test.tsx index 4ef8e57bf74b9..13b2e5e88605a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/helpers.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/helpers.test.tsx @@ -10,8 +10,8 @@ import { omit } from 'lodash/fp'; import React from 'react'; import { getErrorsViewerTableColumns } from './helpers'; -import { TestExternalProviders } from '../../../mock/test_providers/test_providers'; -import { ErrorSummary } from '../../../types'; +import { TestExternalProviders } from '../../../../../mock/test_providers/test_providers'; +import { ErrorSummary } from '../../../../../types'; const errorSummary: ErrorSummary[] = [ { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/helpers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/helpers.tsx similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/helpers.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/helpers.tsx index 35a4a74cca875..a72580e464ad4 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/helpers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/helpers.tsx @@ -10,7 +10,7 @@ import { EuiCode } from '@elastic/eui'; import React from 'react'; import * as i18n from './translations'; -import type { ErrorSummary } from '../../../types'; +import type { ErrorSummary } from '../../../../../types'; export const EMPTY_PLACEHOLDER = '--'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/index.test.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/index.test.tsx index 0354f687cda24..1c605a64d8ab2 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/index.test.tsx @@ -8,9 +8,9 @@ import { render, screen } from '@testing-library/react'; import React from 'react'; -import { TestExternalProviders } from '../../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../../mock/test_providers/test_providers'; import { ERROR, INDEX, PATTERN } from './translations'; -import { ErrorSummary } from '../../../types'; +import { ErrorSummary } from '../../../../../types'; import { ErrorsViewer } from '.'; interface ExpectedColumns { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/index.tsx similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/index.tsx index 2336abe79c651..363127e4f919c 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/index.tsx @@ -14,7 +14,7 @@ import { ERRORS_CONTAINER_MIN_WIDTH, getErrorsViewerTableColumns, } from './helpers'; -import type { ErrorSummary } from '../../../types'; +import type { ErrorSummary } from '../../../../../types'; const ErrorsViewerContainer = styled.div` max-width: ${ERRORS_CONTAINER_MAX_WIDTH}px; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_viewer/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/errors_viewer/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/index.test.tsx similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/index.test.tsx index ecedacc646043..43cd0b7d215c6 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/index.test.tsx @@ -9,7 +9,7 @@ import userEvent from '@testing-library/user-event'; import { act, render, screen } from '@testing-library/react'; import React from 'react'; -import { TestExternalProviders } from '../../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../../../../mock/test_providers/test_providers'; import { ErrorsPopover } from '.'; const mockCopyToClipboard = jest.fn((value) => true); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/index.tsx similarity index 89% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/index.tsx index 8f80e3fa3cab5..a4bb73147e97b 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/index.tsx @@ -16,15 +16,15 @@ import { import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { ErrorsViewer } from '../errors_viewer'; -import { ERRORS_CONTAINER_MAX_WIDTH } from '../errors_viewer/helpers'; +import { ErrorsViewer } from './errors_viewer'; +import { ERRORS_CONTAINER_MAX_WIDTH } from './errors_viewer/helpers'; import { getErrorsMarkdownTable, getErrorsMarkdownTableRows, -} from '../../index_properties/markdown/helpers'; +} from '../../../../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers'; import * as i18n from './translations'; -import type { ErrorSummary } from '../../../types'; -import { ERROR, INDEX, PATTERN } from '../errors_viewer/translations'; +import type { ErrorSummary } from '../../../../types'; +import { ERROR, INDEX, PATTERN } from './errors_viewer/translations'; const CallOut = styled(EuiCallOut)` max-width: ${ERRORS_CONTAINER_MAX_WIDTH}px; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/errors_popover/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/errors_popover/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/check_status/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/index.test.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/check_status/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/index.test.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/check_status/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/index.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/check_status/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/index.tsx index a39c7bbf7cc7d..694bab1b97efe 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/check_status/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/check_status/index.tsx @@ -9,10 +9,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiProgress, EuiSpacer, EuiText } from '@ela import React, { useEffect, useState } from 'react'; import moment from 'moment'; -import { ErrorsPopover } from '../errors_popover'; +import { ErrorsPopover } from './errors_popover'; import * as i18n from '../../../translations'; import type { ErrorSummary, IndexToCheck } from '../../../types'; -import { useDataQualityContext } from '../../data_quality_context'; +import { useDataQualityContext } from '../../../data_quality_context'; export const EMPTY_LAST_CHECKED_DATE = '--'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/index.test.tsx similarity index 88% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/index.test.tsx index d202bdf9b342d..1bcfc9ec12aa3 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/index.test.tsx @@ -10,15 +10,15 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { EMPTY_STAT } from '../../../helpers'; -import { alertIndexWithAllResults } from '../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; -import { auditbeatWithAllResults } from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { packetbeatNoResults } from '../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { EMPTY_STAT } from '../../constants'; +import { alertIndexWithAllResults } from '../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatNoResults } from '../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../mock/test_providers/test_providers'; -import { PatternRollup } from '../../../types'; +} from '../../mock/test_providers/test_providers'; +import { PatternRollup } from '../../types'; import { SummaryActions } from '.'; import { getTotalDocsCount, @@ -26,7 +26,7 @@ import { getTotalIndices, getTotalIndicesChecked, getTotalSizeInBytes, -} from '../../../use_results_rollup/helpers'; +} from '../../hooks/use_results_rollup/utils/stats'; const mockCopyToClipboard = jest.fn((value) => true); jest.mock('@elastic/eui', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/index.tsx similarity index 91% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/index.tsx index e0d7233f538d2..d0037032172c3 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/data_quality_summary/summary_actions/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/index.tsx @@ -11,9 +11,9 @@ import React, { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import { CheckAll } from './check_all'; -import { CheckStatus } from '../check_status'; -import { ERROR, INDEX, PATTERN } from '../errors_viewer/translations'; -import { ERRORS } from '../errors_popover/translations'; +import { CheckStatus } from './check_status'; +import { ERROR, INDEX, PATTERN } from './check_status/errors_popover/errors_viewer/translations'; +import { ERRORS } from './check_status/errors_popover/translations'; import { getDataQualitySummaryMarkdownComment, getErrorsMarkdownTable, @@ -21,13 +21,17 @@ import { getPatternSummaryMarkdownComment, getSummaryTableMarkdownHeader, getSummaryTableMarkdownRow, -} from '../../index_properties/markdown/helpers'; -import { defaultSort, getSummaryTableItems } from '../../pattern/helpers'; -import type { DataQualityCheckResult, IndexToCheck, PatternRollup } from '../../../types'; -import { getErrorSummaries, getSizeInBytes } from '../../../helpers'; +} from '../../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers'; +import { + defaultSort, + getSummaryTableItems, +} from '../../data_quality_details/indices_details/pattern/helpers'; +import type { DataQualityCheckResult, IndexToCheck, PatternRollup } from '../../types'; import { useDataQualityContext } from '../../data_quality_context'; -import { useResultsRollupContext } from '../../../contexts/results_rollup_context'; +import { useResultsRollupContext } from '../../contexts/results_rollup_context'; import { Actions } from '../../actions'; +import { getErrorSummaries } from './utils/get_error_summaries'; +import { getSizeInBytes } from '../../utils/stats'; const StyledActionsContainerFlexItem = styled(EuiFlexItem)` margin-top: auto; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/utils/get_error_summaries.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/utils/get_error_summaries.test.ts new file mode 100644 index 0000000000000..c1e78b92c0fd8 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/utils/get_error_summaries.test.ts @@ -0,0 +1,188 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { alertIndexNoResults } from '../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { + auditbeatNoResults, + auditbeatWithAllResults, +} from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { + packetbeatNoResults, + packetbeatWithSomeErrors, +} from '../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { DataQualityCheckResult, PatternRollup } from '../../../types'; +import { + getErrorSummaries, + getErrorSummariesForRollup, + getErrorSummary, +} from './get_error_summaries'; + +describe('getErrorSummary', () => { + test('it returns the expected error summary', () => { + const resultWithError: DataQualityCheckResult = { + docsCount: 1630289, + error: + 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', + ilmPhase: 'hot', + incompatible: undefined, + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'packetbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }; + + expect(getErrorSummary(resultWithError)).toEqual({ + error: + 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + pattern: 'packetbeat-*', + }); + }); +}); + +describe('getErrorSummariesForRollup', () => { + test('it returns the expected array of `ErrorSummary` when the `PatternRollup` contains errors', () => { + expect(getErrorSummariesForRollup(packetbeatWithSomeErrors)).toEqual([ + { + error: + 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + pattern: 'packetbeat-*', + }, + ]); + }); + + test('it returns the an empty array of `ErrorSummary` when the `PatternRollup` contains all results, with NO errors', () => { + expect(getErrorSummariesForRollup(auditbeatWithAllResults)).toEqual([]); + }); + + test('it returns the an empty array of `ErrorSummary` when the `PatternRollup` has NO results', () => { + expect(getErrorSummariesForRollup(auditbeatNoResults)).toEqual([]); + }); + + test('it returns the an empty array of `ErrorSummary` when the `PatternRollup` is undefined', () => { + expect(getErrorSummariesForRollup(undefined)).toEqual([]); + }); + + test('it returns BOTH the expected (root) pattern-level error, and an index-level error when `PatternRollup` has both', () => { + const withPatternLevelError: PatternRollup = { + ...packetbeatWithSomeErrors, + error: 'This is a pattern-level error', + }; + + expect(getErrorSummariesForRollup(withPatternLevelError)).toEqual([ + { + error: 'This is a pattern-level error', + indexName: null, + pattern: 'packetbeat-*', + }, + { + error: + 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + pattern: 'packetbeat-*', + }, + ]); + }); + + test('it returns the expected (root) pattern-level error when there are no index-level results', () => { + const withPatternLevelError: PatternRollup = { + ...auditbeatNoResults, + error: 'This is a pattern-level error', + }; + + expect(getErrorSummariesForRollup(withPatternLevelError)).toEqual([ + { + error: 'This is a pattern-level error', + indexName: null, + pattern: 'auditbeat-*', + }, + ]); + }); +}); + +describe('getErrorSummaries', () => { + test('it returns an empty array when patternRollups is empty', () => { + expect(getErrorSummaries({})).toEqual([]); + }); + + test('it returns an empty array when none of the patternRollups have errors', () => { + expect( + getErrorSummaries({ + '.alerts-security.alerts-default': alertIndexNoResults, + 'auditbeat-*': auditbeatWithAllResults, + 'packetbeat-*': packetbeatNoResults, + }) + ).toEqual([]); + }); + + test('it returns the expected array of `ErrorSummary` when some of the `PatternRollup` contain errors', () => { + expect( + getErrorSummaries({ + '.alerts-security.alerts-default': alertIndexNoResults, + 'auditbeat-*': auditbeatWithAllResults, + 'packetbeat-*': packetbeatWithSomeErrors, // <-- has errors + }) + ).toEqual([ + { + error: + 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + pattern: 'packetbeat-*', + }, + ]); + }); + + test('it returns the expected array of `ErrorSummary` when there are both pattern-level and index-level errors', () => { + const withPatternLevelError: PatternRollup = { + ...auditbeatNoResults, + error: 'This is a pattern-level error', + }; + + expect( + getErrorSummaries({ + '.alerts-security.alerts-default': alertIndexNoResults, + 'auditbeat-*': withPatternLevelError, // <-- has pattern-level errors + 'packetbeat-*': packetbeatWithSomeErrors, // <-- has index-level errors + }) + ).toEqual([ + { + error: 'This is a pattern-level error', + indexName: null, + pattern: 'auditbeat-*', + }, + { + error: + 'Error loading mappings for .ds-packetbeat-8.5.3-2023.02.04-000001: Error: simulated error fetching index .ds-packetbeat-8.5.3-2023.02.04-000001', + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + pattern: 'packetbeat-*', + }, + ]); + }); + + test('it returns the expected array of `ErrorSummary` when there are just pattern-level errors', () => { + const withPatternLevelError: PatternRollup = { + ...auditbeatNoResults, + error: 'This is a pattern-level error', + }; + + expect( + getErrorSummaries({ + '.alerts-security.alerts-default': alertIndexNoResults, + 'auditbeat-*': withPatternLevelError, // <-- has pattern-level errors + 'packetbeat-*': packetbeatNoResults, + }) + ).toEqual([ + { + error: 'This is a pattern-level error', + indexName: null, + pattern: 'auditbeat-*', + }, + ]); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/utils/get_error_summaries.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/utils/get_error_summaries.ts new file mode 100644 index 0000000000000..a3b6b8ac7d1d8 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/data_quality_summary/summary_actions/utils/get_error_summaries.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import sortBy from 'lodash/fp/sortBy'; +import { DataQualityCheckResult, ErrorSummary, PatternRollup } from '../../../types'; + +export const getErrorSummary = ({ + error, + indexName, + pattern, +}: DataQualityCheckResult): ErrorSummary => ({ + error: String(error), + indexName, + pattern, +}); + +export const getErrorSummariesForRollup = ( + patternRollup: PatternRollup | undefined +): ErrorSummary[] => { + const maybePatternErrorSummary: ErrorSummary[] = + patternRollup != null && patternRollup.error != null + ? [{ pattern: patternRollup.pattern, indexName: null, error: patternRollup.error }] + : []; + + if (patternRollup != null && patternRollup.results != null) { + const unsortedResults: DataQualityCheckResult[] = Object.values(patternRollup.results); + const sortedResults = sortBy('indexName', unsortedResults); + + return sortedResults.reduce( + (acc, result) => [...acc, ...(result.error != null ? [getErrorSummary(result)] : [])], + maybePatternErrorSummary + ); + } else { + return maybePatternErrorSummary; + } +}; + +export const getErrorSummaries = ( + patternRollups: Record +): ErrorSummary[] => { + const allPatterns: string[] = Object.keys(patternRollups); + + // sort the patterns A-Z: + const sortedPatterns = [...allPatterns].sort((a, b) => { + return a.localeCompare(b); + }); + + return sortedPatterns.reduce( + (acc, pattern) => [...acc, ...getErrorSummariesForRollup(patternRollups[pattern])], + [] + ); +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/index.test.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/index.test.tsx index b129102e5516e..f16803936794d 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/index.test.tsx @@ -9,14 +9,14 @@ import { act, renderHook } from '@testing-library/react-hooks'; import { useIndicesCheck } from '.'; -import * as utilsCheckIndex from '../utils/check_index'; -import { mockUnallowedValuesResponse } from '../mock/unallowed_values/mock_unallowed_values'; -import { mockMappingsResponse } from '../mock/mappings_response/mock_mappings_response'; +import * as utilsCheckIndex from '../../utils/check_index'; +import { mockUnallowedValuesResponse } from '../../mock/unallowed_values/mock_unallowed_values'; +import { mockMappingsResponse } from '../../mock/mappings_response/mock_mappings_response'; import { HttpHandler } from '@kbn/core-http-browser'; -import { MappingsError } from '../use_mappings/helpers'; -import { UnallowedValuesError } from '../use_unallowed_values/helpers'; +import { MappingsError } from '../../utils/fetch_mappings'; +import { UnallowedValuesError } from '../../utils/fetch_unallowed_values'; import { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; -import { UnallowedValueSearchResult } from '../types'; +import { UnallowedValueSearchResult } from '../../types'; import { getInitialCheckStateValue } from './reducer'; const getSpies = () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/index.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/index.tsx index acbad56a613c5..6ad00aacb338d 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/index.tsx @@ -6,10 +6,10 @@ */ import { useReducer, useCallback } from 'react'; -import { OnCheckCompleted } from '../types'; -import { MappingsError } from '../use_mappings/helpers'; -import { UnallowedValuesError } from '../use_unallowed_values/helpers'; -import { checkIndex as _checkIndex, CheckIndexProps } from '../utils/check_index'; +import { OnCheckCompleted } from '../../types'; +import { MappingsError } from '../../utils/fetch_mappings'; +import { UnallowedValuesError } from '../../utils/fetch_unallowed_values'; +import { checkIndex as _checkIndex, CheckIndexProps } from '../../utils/check_index'; import { initialState, reducer } from './reducer'; import { UseIndicesCheckReturnValue } from './types'; import { useIsMounted } from '../use_is_mounted'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/reducer.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/reducer.ts similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/reducer.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/reducer.ts index ca596643605ce..73bb4c1a98df1 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/reducer.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/reducer.ts @@ -14,9 +14,9 @@ import { PartitionedFieldMetadata, UnallowedValueCount, UnallowedValueSearchResult, -} from '../types'; -import { MappingsError } from '../use_mappings/helpers'; -import { UnallowedValuesError } from '../use_unallowed_values/helpers'; +} from '../../types'; +import { MappingsError } from '../../utils/fetch_mappings'; +import { UnallowedValuesError } from '../../utils/fetch_unallowed_values'; import { UseIndicesCheckState } from './types'; type Action = { data: { indexName: string } } & ( diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/types.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/types.ts similarity index 86% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/types.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/types.ts index c7f0145f68f15..2b9ecf147e0a3 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_indices_check/types.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_indices_check/types.ts @@ -13,10 +13,10 @@ import { PartitionedFieldMetadata, UnallowedValueCount, UnallowedValueSearchResult, -} from '../types'; -import { MappingsError } from '../use_mappings/helpers'; -import { UnallowedValuesError } from '../use_unallowed_values/helpers'; -import { CheckIndexProps } from '../utils/check_index'; +} from '../../types'; +import { MappingsError } from '../../utils/fetch_mappings'; +import { UnallowedValuesError } from '../../utils/fetch_unallowed_values'; +import { CheckIndexProps } from '../../utils/check_index'; export interface UseIndicesCheckCheckState { [indexName: string]: { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_is_mounted/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_is_mounted/index.test.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_is_mounted/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_is_mounted/index.test.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_is_mounted/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_is_mounted/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_is_mounted/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_is_mounted/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/constants.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/constants.ts new file mode 100644 index 0000000000000..e2251d526136f --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/constants.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const POST_INDEX_RESULTS = '/internal/ecs_data_quality_dashboard/results'; +export const GET_INDEX_RESULTS_LATEST = + '/internal/ecs_data_quality_dashboard/results_latest/{pattern}'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx similarity index 93% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx index f0c6f9d28e501..eb8cd670d70c5 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/index.tsx @@ -7,10 +7,10 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { EcsVersion } from '@elastic/ecs'; - import { isEmpty } from 'lodash/fp'; import { IToasts } from '@kbn/core-notifications-browser'; import { HttpHandler } from '@kbn/core-http-browser'; + import { getTotalDocsCount, getTotalIncompatible, @@ -18,33 +18,34 @@ import { getTotalIndicesChecked, getTotalSameFamily, getTotalSizeInBytes, - updateResultOnCheckCompleted, -} from './helpers'; - + getTotalPatternSameFamily, + getIndexId, +} from './utils/stats'; +import { + getStorageResults, + postStorageResult, + formatStorageResult, + formatResultFromStorage, +} from './utils/storage'; +import { getPatternRollupsWithLatestCheckResult } from './utils/get_pattern_rollups_with_latest_check_result'; import type { DataQualityCheckResult, OnCheckCompleted, PatternRollup, TelemetryEvents, -} from '../types'; +} from '../../types'; import { - getDocsCount, - getIndexId, - getStorageResults, - getSizeInBytes, - getTotalPatternSameFamily, - postStorageResult, - formatStorageResult, - formatResultFromStorage, -} from '../helpers'; -import { getIlmPhase, getIndexIncompatible } from '../data_quality_panel/pattern/helpers'; + getIlmPhase, + getIndexIncompatible, +} from '../../data_quality_details/indices_details/pattern/helpers'; import { getIncompatibleMappingsFields, getIncompatibleValuesFields, getSameFamilyFields, -} from '../data_quality_panel/tabs/incompatible_tab/helpers'; +} from '../../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers'; import { UseResultsRollupReturnValue } from './types'; import { useIsMounted } from '../use_is_mounted'; +import { getDocsCount, getSizeInBytes } from '../../utils/stats'; interface Props { ilmPhases: string[]; @@ -169,7 +170,7 @@ export const useResultsRollup = ({ isCheckAll, }) => { setPatternRollups((currentPatternRollups) => { - const updatedRollups = updateResultOnCheckCompleted({ + const updatedRollups = getPatternRollupsWithLatestCheckResult({ error, formatBytes, formatNumber, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/types.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/types.ts new file mode 100644 index 0000000000000..093ee8fdd645c --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/types.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + IlmPhase, + IncompatibleFieldMappingItem, + IncompatibleFieldValueItem, + OnCheckCompleted, + PatternRollup, + SameFamilyFieldItem, +} from '../../types'; + +export interface UseResultsRollupReturnValue { + onCheckCompleted: OnCheckCompleted; + patternIndexNames: Record; + patternRollups: Record; + totalDocsCount: number | undefined; + totalIncompatible: number | undefined; + totalIndices: number | undefined; + totalIndicesChecked: number | undefined; + totalSameFamily: number | undefined; + totalSizeInBytes: number | undefined; + updatePatternIndexNames: ({ + indexNames, + pattern, + }: { + indexNames: string[]; + pattern: string; + }) => void; + updatePatternRollup: (patternRollup: PatternRollup) => void; +} + +export interface StorageResult { + batchId: string; + indexName: string; + indexPattern: string; + isCheckAll: boolean; + checkedAt: number; + docsCount: number; + totalFieldCount: number; + ecsFieldCount: number; + customFieldCount: number; + incompatibleFieldCount: number; + incompatibleFieldMappingItems: IncompatibleFieldMappingItem[]; + incompatibleFieldValueItems: IncompatibleFieldValueItem[]; + sameFamilyFieldCount: number; + sameFamilyFields: string[]; + sameFamilyFieldItems: SameFamilyFieldItem[]; + unallowedMappingFields: string[]; + unallowedValueFields: string[]; + sizeInBytes: number; + ilmPhase?: IlmPhase; + markdownComments: string[]; + ecsVersion: string; + indexId: string; + error: string | null; +} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/get_pattern_rollups_with_latest_check_result.test.ts similarity index 77% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/get_pattern_rollups_with_latest_check_result.test.ts index c724ee1ae38de..f6cd702ef139f 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/get_pattern_rollups_with_latest_check_result.test.ts @@ -7,24 +7,11 @@ import numeral from '@elastic/numeral'; -import { - getTotalDocsCount, - getTotalIncompatible, - getTotalIndices, - getTotalIndicesChecked, - getTotalSameFamily, - updateResultOnCheckCompleted, -} from './helpers'; -import { auditbeatWithAllResults } from '../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; -import { - mockPacketbeatPatternRollup, - packetbeatNoResults, - packetbeatWithSomeErrors, -} from '../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; -import { DataQualityCheckResult, MeteringStatsIndex, PatternRollup } from '../types'; -import { EMPTY_STAT } from '../helpers'; -import { mockPartitionedFieldMetadata } from '../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; -import { alertIndexWithAllResults } from '../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { getPatternRollupsWithLatestCheckResult } from './get_pattern_rollups_with_latest_check_result'; +import { mockPacketbeatPatternRollup } from '../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { MeteringStatsIndex, PatternRollup } from '../../../types'; +import { EMPTY_STAT } from '../../../constants'; +import { mockPartitionedFieldMetadata } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata'; import { EcsVersion } from '@elastic/ecs'; const defaultBytesFormat = '0,0.[0]b'; @@ -35,11 +22,6 @@ const defaultNumberFormat = '0,0.[000]'; const formatNumber = (value: number | undefined) => value != null ? numeral(value).format(defaultNumberFormat) : EMPTY_STAT; -const patternRollups: Record = { - 'auditbeat-*': auditbeatWithAllResults, // indices: 3 - 'packetbeat-*': mockPacketbeatPatternRollup, // indices: 2 -}; - describe('helpers', () => { let originalFetch: (typeof global)['fetch']; @@ -51,121 +33,6 @@ describe('helpers', () => { global.fetch = originalFetch; }); - describe('getTotalSameFamily', () => { - const defaultDataQualityCheckResult: DataQualityCheckResult = { - docsCount: 26093, - error: null, - ilmPhase: 'hot', - incompatible: 0, - indexName: '.internal.alerts-security.alerts-default-000001', - markdownComments: ['foo', 'bar', 'baz'], - pattern: '.alerts-security.alerts-default', - sameFamily: 7, - checkedAt: 1706526408000, - }; - - const alertIndexWithSameFamily: PatternRollup = { - ...alertIndexWithAllResults, - results: { - '.internal.alerts-security.alerts-default-000001': { - ...defaultDataQualityCheckResult, - }, - }, - }; - - const withSameFamily: Record = { - '.internal.alerts-security.alerts-default-000001': alertIndexWithSameFamily, - }; - - test('it returns the expected count when patternRollups has sameFamily', () => { - expect(getTotalSameFamily(withSameFamily)).toEqual(7); - }); - - test('it returns undefined when patternRollups is empty', () => { - expect(getTotalSameFamily({})).toBeUndefined(); - }); - - test('it returns zero when none of the rollups have same family', () => { - expect(getTotalSameFamily(patternRollups)).toEqual(0); - }); - }); - - describe('getTotalIndices', () => { - test('it returns the expected total when ALL `PatternRollup`s have an `indices`', () => { - expect(getTotalIndices(patternRollups)).toEqual(5); - }); - - test('it returns undefined when only SOME of the `PatternRollup`s have an `indices`', () => { - const someIndicesAreUndefined: Record = { - 'auditbeat-*': { - ...auditbeatWithAllResults, - indices: undefined, // <-- - }, - 'packetbeat-*': mockPacketbeatPatternRollup, // indices: 2 - }; - - expect(getTotalIndices(someIndicesAreUndefined)).toBeUndefined(); - }); - }); - - describe('getTotalDocsCount', () => { - test('it returns the expected total when ALL `PatternRollup`s have a `docsCount`', () => { - expect(getTotalDocsCount(patternRollups)).toEqual( - Number(auditbeatWithAllResults.docsCount) + Number(mockPacketbeatPatternRollup.docsCount) - ); - }); - - test('it returns undefined when only SOME of the `PatternRollup`s have a `docsCount`', () => { - const someIndicesAreUndefined: Record = { - 'auditbeat-*': { - ...auditbeatWithAllResults, - docsCount: undefined, // <-- - }, - 'packetbeat-*': mockPacketbeatPatternRollup, - }; - - expect(getTotalDocsCount(someIndicesAreUndefined)).toBeUndefined(); - }); - }); - - describe('getTotalIncompatible', () => { - test('it returns the expected total when ALL `PatternRollup`s have `results`', () => { - expect(getTotalIncompatible(patternRollups)).toEqual(4); - }); - - test('it returns the expected total when only SOME of the `PatternRollup`s have `results`', () => { - const someResultsAreUndefined: Record = { - 'auditbeat-*': auditbeatWithAllResults, - 'packetbeat-*': packetbeatNoResults, // <-- results is undefined - }; - - expect(getTotalIncompatible(someResultsAreUndefined)).toEqual(4); - }); - - test('it returns undefined when NONE of the `PatternRollup`s have `results`', () => { - const someResultsAreUndefined: Record = { - 'packetbeat-*': packetbeatNoResults, // <-- results is undefined - }; - - expect(getTotalIncompatible(someResultsAreUndefined)).toBeUndefined(); - }); - }); - - describe('getTotalIndicesChecked', () => { - test('it returns the expected total', () => { - expect(getTotalIndicesChecked(patternRollups)).toEqual(3); - }); - - test('it returns the expected total when errors have occurred', () => { - const someErrors: Record = { - 'auditbeat-*': auditbeatWithAllResults, // indices: 3 - 'packetbeat-*': packetbeatWithSomeErrors, // <-- indices: 2, but one has errors - }; - - expect(getTotalIndicesChecked(someErrors)).toEqual(4); - }); - }); - describe('updateResultOnCheckCompleted', () => { const packetbeatStats861: MeteringStatsIndex = mockPacketbeatPatternRollup.stats != null @@ -178,7 +45,7 @@ describe('helpers', () => { test('it returns the updated rollups', () => { expect( - updateResultOnCheckCompleted({ + getPatternRollupsWithLatestCheckResult({ error: null, formatBytes, formatNumber, @@ -280,7 +147,7 @@ describe('helpers', () => { }; expect( - updateResultOnCheckCompleted({ + getPatternRollupsWithLatestCheckResult({ error: null, formatBytes, formatNumber, @@ -377,7 +244,7 @@ describe('helpers', () => { test('it returns the expected results when `partitionedFieldMetadata` is null', () => { expect( - updateResultOnCheckCompleted({ + getPatternRollupsWithLatestCheckResult({ error: null, formatBytes, formatNumber, @@ -472,7 +339,7 @@ describe('helpers', () => { }; expect( - updateResultOnCheckCompleted({ + getPatternRollupsWithLatestCheckResult({ error: null, formatBytes, formatNumber, @@ -532,7 +399,7 @@ describe('helpers', () => { }; expect( - updateResultOnCheckCompleted({ + getPatternRollupsWithLatestCheckResult({ error: null, formatBytes, formatNumber, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/get_pattern_rollups_with_latest_check_result.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/get_pattern_rollups_with_latest_check_result.ts new file mode 100644 index 0000000000000..22b7eb6db4d8d --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/get_pattern_rollups_with_latest_check_result.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getIndexDocsCountFromRollup } from '../../../data_quality_summary/summary_actions/check_all/helpers'; +import { getIlmPhase } from '../../../data_quality_details/indices_details/pattern/helpers'; +import { getAllIncompatibleMarkdownComments } from '../../../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/index_check_fields/tabs/incompatible_tab/helpers'; +import { getSizeInBytes } from '../../../utils/stats'; +import type { IlmPhase, PartitionedFieldMetadata, PatternRollup } from '../../../types'; + +export const getPatternRollupsWithLatestCheckResult = ({ + error, + formatBytes, + formatNumber, + indexName, + isILMAvailable, + partitionedFieldMetadata, + pattern, + patternRollups, +}: { + error: string | null; + formatBytes: (value: number | undefined) => string; + formatNumber: (value: number | undefined) => string; + indexName: string; + isILMAvailable: boolean; + partitionedFieldMetadata: PartitionedFieldMetadata | null; + pattern: string; + patternRollups: Record; +}): Record => { + const patternRollup: PatternRollup | undefined = patternRollups[pattern]; + + if (patternRollup != null) { + const ilmExplain = patternRollup.ilmExplain; + + const ilmPhase: IlmPhase | undefined = + ilmExplain != null ? getIlmPhase(ilmExplain[indexName], isILMAvailable) : undefined; + + const docsCount = getIndexDocsCountFromRollup({ + indexName, + patternRollup, + }); + + const patternDocsCount = patternRollup.docsCount ?? 0; + + const sizeInBytes = getSizeInBytes({ indexName, stats: patternRollup.stats }); + + const markdownComments = + partitionedFieldMetadata != null + ? getAllIncompatibleMarkdownComments({ + docsCount, + formatBytes, + formatNumber, + ilmPhase, + indexName, + isILMAvailable, + partitionedFieldMetadata, + patternDocsCount, + sizeInBytes, + }) + : []; + + const incompatible = partitionedFieldMetadata?.incompatible.length; + const sameFamily = partitionedFieldMetadata?.sameFamily.length; + const checkedAt = partitionedFieldMetadata ? Date.now() : undefined; + + return { + ...patternRollups, + [pattern]: { + ...patternRollup, + results: { + ...(patternRollup.results ?? {}), + [indexName]: { + docsCount, + error, + ilmPhase, + incompatible, + indexName, + markdownComments, + pattern, + sameFamily, + checkedAt, + }, + }, + }, + }; + } else { + return patternRollups; + } +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/stats.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/stats.test.ts new file mode 100644 index 0000000000000..7f28c6bcd1727 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/stats.test.ts @@ -0,0 +1,231 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { alertIndexWithAllResults } from '../../../mock/pattern_rollup/mock_alerts_pattern_rollup'; +import { auditbeatWithAllResults } from '../../../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { + mockPacketbeatPatternRollup, + packetbeatNoResults, + packetbeatWithSomeErrors, +} from '../../../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { mockStats } from '../../../mock/stats/mock_stats'; +import { DataQualityCheckResult, PatternRollup } from '../../../types'; +import { + getIndexId, + getTotalDocsCount, + getTotalIncompatible, + getTotalIndices, + getTotalIndicesChecked, + getTotalPatternSameFamily, + getTotalSameFamily, +} from './stats'; + +const patternRollups: Record = { + 'auditbeat-*': auditbeatWithAllResults, // indices: 3 + 'packetbeat-*': mockPacketbeatPatternRollup, // indices: 2 +}; + +describe('getTotalPatternSameFamily', () => { + const baseResult: DataQualityCheckResult = { + docsCount: 4, + error: null, + ilmPhase: 'unmanaged', + incompatible: 3, + indexName: 'auditbeat-custom-index-1', + markdownComments: [ + '### auditbeat-custom-index-1\n', + '| Result | Index | Docs | Incompatible fields | ILM Phase |\n|--------|-------|------|---------------------|-----------|\n| ❌ | auditbeat-custom-index-1 | 4 (0.0%) | 3 | `unmanaged` |\n\n', + '### **Incompatible fields** `3` **Custom fields** `4` **ECS compliant fields** `2` **All fields** `9`\n', + "#### 3 incompatible fields, 0 fields with mappings in the same family\n\nFields are incompatible with ECS when index mappings, or the values of the fields in the index, don't conform to the Elastic Common Schema (ECS), version 8.6.1.\n\nIncompatible fields with mappings in the same family have exactly the same search behavior but may have different space usage or performance characteristics.\n\nWhen an incompatible field is not in the same family:\n❌ Detection engine rules referencing these fields may not match them correctly\n❌ Pages may not display some events or fields due to unexpected field mappings or values\n❌ Mappings or field values that don't comply with ECS are not supported\n", + '\n#### Incompatible field mappings - auditbeat-custom-index-1\n\n\n| Field | ECS mapping type (expected) | Index mapping type (actual) | \n|-------|-----------------------------|-----------------------------|\n| host.name | `keyword` | `text` |\n| source.ip | `ip` | `text` |\n\n#### Incompatible field values - auditbeat-custom-index-1\n\n\n| Field | ECS values (expected) | Document values (actual) | \n|-------|-----------------------|--------------------------|\n| event.category | `authentication`, `configuration`, `database`, `driver`, `email`, `file`, `host`, `iam`, `intrusion_detection`, `malware`, `network`, `package`, `process`, `registry`, `session`, `threat`, `vulnerability`, `web` | `an_invalid_category` (2),\n`theory` (1) |\n\n', + ], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }; + + it('returns undefined when results is undefined', () => { + expect(getTotalPatternSameFamily(undefined)).toBeUndefined(); + }); + + it('returns 0 when results is an empty object', () => { + expect(getTotalPatternSameFamily({})).toBe(0); + }); + + it('should sum sameFamily values and return the total', () => { + const results: Record = { + a: { + ...baseResult, + indexName: 'a', + markdownComments: [], + pattern: 'pattern', + sameFamily: 2, + }, + b: { + ...baseResult, + indexName: 'b', + markdownComments: [], + pattern: 'pattern', + sameFamily: 3, + }, + c: { ...baseResult, indexName: 'c', markdownComments: [], pattern: 'pattern' }, + }; + + expect(getTotalPatternSameFamily(results)).toBe(5); + }); + + it('handles a mix of defined and undefined sameFamily values', () => { + const results: Record = { + a: { + ...baseResult, + indexName: 'a', + markdownComments: [], + pattern: 'pattern', + sameFamily: 1, + }, + b: { + ...baseResult, + indexName: 'b', + markdownComments: [], + pattern: 'pattern', + sameFamily: undefined, + }, + c: { + ...baseResult, + indexName: 'c', + markdownComments: [], + pattern: 'pattern', + sameFamily: 2, + }, + }; + + expect(getTotalPatternSameFamily(results)).toBe(3); + }); +}); + +describe('getTotalSameFamily', () => { + const defaultDataQualityCheckResult: DataQualityCheckResult = { + docsCount: 26093, + error: null, + ilmPhase: 'hot', + incompatible: 0, + indexName: '.internal.alerts-security.alerts-default-000001', + markdownComments: ['foo', 'bar', 'baz'], + pattern: '.alerts-security.alerts-default', + sameFamily: 7, + checkedAt: 1706526408000, + }; + + const alertIndexWithSameFamily: PatternRollup = { + ...alertIndexWithAllResults, + results: { + '.internal.alerts-security.alerts-default-000001': { + ...defaultDataQualityCheckResult, + }, + }, + }; + + const withSameFamily: Record = { + '.internal.alerts-security.alerts-default-000001': alertIndexWithSameFamily, + }; + + test('it returns the expected count when patternRollups has sameFamily', () => { + expect(getTotalSameFamily(withSameFamily)).toEqual(7); + }); + + test('it returns undefined when patternRollups is empty', () => { + expect(getTotalSameFamily({})).toBeUndefined(); + }); + + test('it returns zero when none of the rollups have same family', () => { + expect(getTotalSameFamily(patternRollups)).toEqual(0); + }); +}); + +describe('getTotalIndices', () => { + test('it returns the expected total when ALL `PatternRollup`s have an `indices`', () => { + expect(getTotalIndices(patternRollups)).toEqual(5); + }); + + test('it returns undefined when only SOME of the `PatternRollup`s have an `indices`', () => { + const someIndicesAreUndefined: Record = { + 'auditbeat-*': { + ...auditbeatWithAllResults, + indices: undefined, // <-- + }, + 'packetbeat-*': mockPacketbeatPatternRollup, // indices: 2 + }; + + expect(getTotalIndices(someIndicesAreUndefined)).toBeUndefined(); + }); +}); + +describe('getTotalDocsCount', () => { + test('it returns the expected total when ALL `PatternRollup`s have a `docsCount`', () => { + expect(getTotalDocsCount(patternRollups)).toEqual( + Number(auditbeatWithAllResults.docsCount) + Number(mockPacketbeatPatternRollup.docsCount) + ); + }); + + test('it returns undefined when only SOME of the `PatternRollup`s have a `docsCount`', () => { + const someIndicesAreUndefined: Record = { + 'auditbeat-*': { + ...auditbeatWithAllResults, + docsCount: undefined, // <-- + }, + 'packetbeat-*': mockPacketbeatPatternRollup, + }; + + expect(getTotalDocsCount(someIndicesAreUndefined)).toBeUndefined(); + }); +}); + +describe('getTotalIncompatible', () => { + test('it returns the expected total when ALL `PatternRollup`s have `results`', () => { + expect(getTotalIncompatible(patternRollups)).toEqual(4); + }); + + test('it returns the expected total when only SOME of the `PatternRollup`s have `results`', () => { + const someResultsAreUndefined: Record = { + 'auditbeat-*': auditbeatWithAllResults, + 'packetbeat-*': packetbeatNoResults, // <-- results is undefined + }; + + expect(getTotalIncompatible(someResultsAreUndefined)).toEqual(4); + }); + + test('it returns undefined when NONE of the `PatternRollup`s have `results`', () => { + const someResultsAreUndefined: Record = { + 'packetbeat-*': packetbeatNoResults, // <-- results is undefined + }; + + expect(getTotalIncompatible(someResultsAreUndefined)).toBeUndefined(); + }); +}); + +describe('getTotalIndicesChecked', () => { + test('it returns the expected total', () => { + expect(getTotalIndicesChecked(patternRollups)).toEqual(3); + }); + + test('it returns the expected total when errors have occurred', () => { + const someErrors: Record = { + 'auditbeat-*': auditbeatWithAllResults, // indices: 3 + 'packetbeat-*': packetbeatWithSomeErrors, // <-- indices: 2, but one has errors + }; + + expect(getTotalIndicesChecked(someErrors)).toEqual(4); + }); +}); + +describe('getIndexId', () => { + it('returns the expected index ID', () => { + expect(getIndexId({ indexName: 'auditbeat-custom-index-1', stats: mockStats })).toEqual( + 'uyJDDqGrRQqdBTN0mCF-iw' + ); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/stats.ts similarity index 52% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/stats.ts index 07f51572b6ba2..c3a44f04471ea 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_results_rollup/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/stats.ts @@ -5,16 +5,20 @@ * 2.0. */ -import { getIndexDocsCountFromRollup } from '../data_quality_panel/data_quality_summary/summary_actions/check_all/helpers'; -import { getIlmPhase } from '../data_quality_panel/pattern/helpers'; -import { getAllIncompatibleMarkdownComments } from '../data_quality_panel/tabs/incompatible_tab/helpers'; -import { - getSizeInBytes, - getTotalPatternIncompatible, - getTotalPatternIndicesChecked, - getTotalPatternSameFamily, -} from '../helpers'; -import type { IlmPhase, PartitionedFieldMetadata, PatternRollup } from '../types'; +import { DataQualityCheckResult, MeteringStatsIndex, PatternRollup } from '../../../types'; +import { getTotalPatternIncompatible, getTotalPatternIndicesChecked } from '../../../utils/stats'; + +export const getTotalPatternSameFamily = ( + results: Record | undefined +): number | undefined => { + if (results == null) { + return undefined; + } + + const allResults = Object.values(results); + + return allResults.reduce((acc, { sameFamily }) => acc + (sameFamily ?? 0), 0); +}; export const getTotalIndices = ( patternRollups: Record @@ -87,82 +91,10 @@ export const getTotalIndicesChecked = (patternRollups: Record string; - formatNumber: (value: number | undefined) => string; indexName: string; - isILMAvailable: boolean; - partitionedFieldMetadata: PartitionedFieldMetadata | null; - pattern: string; - patternRollups: Record; -}): Record => { - const patternRollup: PatternRollup | undefined = patternRollups[pattern]; - - if (patternRollup != null) { - const ilmExplain = patternRollup.ilmExplain; - - const ilmPhase: IlmPhase | undefined = - ilmExplain != null ? getIlmPhase(ilmExplain[indexName], isILMAvailable) : undefined; - - const docsCount = getIndexDocsCountFromRollup({ - indexName, - patternRollup, - }); - - const patternDocsCount = patternRollup.docsCount ?? 0; - - const sizeInBytes = getSizeInBytes({ indexName, stats: patternRollup.stats }); - - const markdownComments = - partitionedFieldMetadata != null - ? getAllIncompatibleMarkdownComments({ - docsCount, - formatBytes, - formatNumber, - ilmPhase, - indexName, - isILMAvailable, - partitionedFieldMetadata, - patternDocsCount, - sizeInBytes, - }) - : []; - - const incompatible = partitionedFieldMetadata?.incompatible.length; - const sameFamily = partitionedFieldMetadata?.sameFamily.length; - const checkedAt = partitionedFieldMetadata ? Date.now() : undefined; - - return { - ...patternRollups, - [pattern]: { - ...patternRollup, - results: { - ...(patternRollup.results ?? {}), - [indexName]: { - docsCount, - error, - ilmPhase, - incompatible, - indexName, - markdownComments, - pattern, - sameFamily, - checkedAt, - }, - }, - }, - }; - } else { - return patternRollups; - } -}; + stats: Record | null; +}): string | null | undefined => stats && stats[indexName]?.uuid; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts new file mode 100644 index 0000000000000..0e894694ed1e9 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.test.ts @@ -0,0 +1,202 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { httpServiceMock } from '@kbn/core-http-browser-mocks'; +import { mockPartitionedFieldMetadataWithSameFamily } from '../../../mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family'; +import { StorageResult } from '../types'; +import { formatStorageResult, getStorageResults, postStorageResult } from './storage'; +import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; + +describe('formatStorageResult', () => { + it('should correctly format the input data into a StorageResult object', () => { + const inputData: Parameters[number] = { + result: { + indexName: 'testIndex', + pattern: 'testPattern', + checkedAt: 1627545600000, + docsCount: 100, + incompatible: 3, + sameFamily: 1, + ilmPhase: 'hot', + markdownComments: ['test comments'], + error: null, + }, + report: { + batchId: 'testBatch', + isCheckAll: true, + sameFamilyFields: ['agent.type'], + unallowedMappingFields: ['event.category', 'host.name', 'source.ip'], + unallowedValueFields: ['event.category'], + sizeInBytes: 5000, + ecsVersion: '1.0.0', + indexName: 'testIndex', + indexId: 'testIndexId', + }, + partitionedFieldMetadata: mockPartitionedFieldMetadataWithSameFamily, + }; + + const expectedResult: StorageResult = { + batchId: 'testBatch', + indexName: 'testIndex', + indexPattern: 'testPattern', + isCheckAll: true, + checkedAt: 1627545600000, + docsCount: 100, + totalFieldCount: 10, + ecsFieldCount: 2, + customFieldCount: 4, + incompatibleFieldCount: 3, + incompatibleFieldMappingItems: [ + { + fieldName: 'event.category', + expectedValue: 'keyword', + actualValue: 'constant_keyword', + description: + 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy.\n`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory.\nThis field is an array. This will allow proper categorization of some events that fall in multiple categories.', + }, + { + fieldName: 'host.name', + expectedValue: 'keyword', + actualValue: 'text', + description: + 'Name of the host.\nIt can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.', + }, + { + fieldName: 'source.ip', + expectedValue: 'ip', + actualValue: 'text', + description: 'IP address of the source (IPv4 or IPv6).', + }, + ], + incompatibleFieldValueItems: [ + { + fieldName: 'event.category', + expectedValues: [ + 'authentication', + 'configuration', + 'database', + 'driver', + 'email', + 'file', + 'host', + 'iam', + 'intrusion_detection', + 'malware', + 'network', + 'package', + 'process', + 'registry', + 'session', + 'threat', + 'vulnerability', + 'web', + ], + actualValues: [{ name: 'an_invalid_category', count: 2 }], + description: + 'This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy.\n`event.category` represents the "big buckets" of ECS categories. For example, filtering on `event.category:process` yields all events relating to process activity. This field is closely related to `event.type`, which is used as a subcategory.\nThis field is an array. This will allow proper categorization of some events that fall in multiple categories.', + }, + ], + sameFamilyFieldCount: 1, + sameFamilyFields: ['agent.type'], + sameFamilyFieldItems: [ + { + fieldName: 'agent.type', + expectedValue: 'keyword', + actualValue: 'constant_keyword', + description: + 'Type of the agent.\nThe agent type always stays the same and should be given by the agent used. In case of Filebeat the agent would always be Filebeat also if two Filebeat instances are run on the same machine.', + }, + ], + unallowedMappingFields: ['event.category', 'host.name', 'source.ip'], + unallowedValueFields: ['event.category'], + sizeInBytes: 5000, + ilmPhase: 'hot', + markdownComments: ['test comments'], + ecsVersion: '1.0.0', + indexId: 'testIndexId', + error: null, + }; + + expect(formatStorageResult(inputData)).toEqual(expectedResult); + }); +}); + +describe('postStorageResult', () => { + const { fetch } = httpServiceMock.createStartContract(); + const { toasts } = notificationServiceMock.createStartContract(); + beforeEach(() => { + fetch.mockClear(); + }); + + test('it posts the result', async () => { + const storageResult = { indexName: 'test' } as unknown as StorageResult; + await postStorageResult({ + storageResult, + httpFetch: fetch, + abortController: new AbortController(), + toasts, + }); + + expect(fetch).toHaveBeenCalledWith( + '/internal/ecs_data_quality_dashboard/results', + expect.objectContaining({ + method: 'POST', + body: JSON.stringify(storageResult), + }) + ); + }); + + test('it throws error', async () => { + const storageResult = { indexName: 'test' } as unknown as StorageResult; + fetch.mockRejectedValueOnce('test-error'); + await postStorageResult({ + httpFetch: fetch, + storageResult, + abortController: new AbortController(), + toasts, + }); + expect(toasts.addError).toHaveBeenCalledWith('test-error', { title: expect.any(String) }); + }); +}); + +describe('getStorageResults', () => { + const { fetch } = httpServiceMock.createStartContract(); + const { toasts } = notificationServiceMock.createStartContract(); + beforeEach(() => { + fetch.mockClear(); + }); + + test('it gets the results', async () => { + await getStorageResults({ + httpFetch: fetch, + abortController: new AbortController(), + pattern: 'auditbeat-*', + toasts, + }); + + expect(fetch).toHaveBeenCalledWith( + '/internal/ecs_data_quality_dashboard/results_latest/auditbeat-*', + expect.objectContaining({ + method: 'GET', + }) + ); + }); + + it('should catch error', async () => { + fetch.mockRejectedValueOnce('test-error'); + + const results = await getStorageResults({ + httpFetch: fetch, + abortController: new AbortController(), + pattern: 'auditbeat-*', + toasts, + }); + + expect(toasts.addError).toHaveBeenCalledWith('test-error', { title: expect.any(String) }); + expect(results).toEqual([]); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts new file mode 100644 index 0000000000000..b7b3b120441d3 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/hooks/use_results_rollup/utils/storage.ts @@ -0,0 +1,157 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { HttpHandler } from '@kbn/core-http-browser'; +import { IToasts } from '@kbn/core-notifications-browser'; + +import { + DataQualityCheckResult, + DataQualityIndexCheckedParams, + IncompatibleFieldMappingItem, + IncompatibleFieldValueItem, + PartitionedFieldMetadata, + SameFamilyFieldItem, +} from '../../../types'; +import { StorageResult } from '../types'; +import { GET_INDEX_RESULTS_LATEST, POST_INDEX_RESULTS } from '../constants'; +import { INTERNAL_API_VERSION } from '../../../constants'; +import { GET_RESULTS_ERROR_TITLE, POST_RESULT_ERROR_TITLE } from '../../../translations'; + +export const formatStorageResult = ({ + result, + report, + partitionedFieldMetadata, +}: { + result: DataQualityCheckResult; + report: DataQualityIndexCheckedParams; + partitionedFieldMetadata: PartitionedFieldMetadata; +}): StorageResult => { + const incompatibleFieldMappingItems: IncompatibleFieldMappingItem[] = []; + const incompatibleFieldValueItems: IncompatibleFieldValueItem[] = []; + const sameFamilyFieldItems: SameFamilyFieldItem[] = []; + + partitionedFieldMetadata.incompatible.forEach((field) => { + if (field.type !== field.indexFieldType) { + incompatibleFieldMappingItems.push({ + fieldName: field.indexFieldName, + expectedValue: field.type, + actualValue: field.indexFieldType, + description: field.description, + }); + } + + if (field.indexInvalidValues.length > 0) { + incompatibleFieldValueItems.push({ + fieldName: field.indexFieldName, + expectedValues: field.allowed_values?.map((x) => x.name) ?? [], + actualValues: field.indexInvalidValues.map((v) => ({ name: v.fieldName, count: v.count })), + description: field.description, + }); + } + }); + + partitionedFieldMetadata.sameFamily.forEach((field) => { + sameFamilyFieldItems.push({ + fieldName: field.indexFieldName, + expectedValue: field.type, + actualValue: field.indexFieldType, + description: field.description, + }); + }); + + return { + batchId: report.batchId, + indexName: result.indexName, + indexPattern: result.pattern, + isCheckAll: report.isCheckAll, + checkedAt: result.checkedAt ?? Date.now(), + docsCount: result.docsCount ?? 0, + totalFieldCount: partitionedFieldMetadata.all.length, + ecsFieldCount: partitionedFieldMetadata.ecsCompliant.length, + customFieldCount: partitionedFieldMetadata.custom.length, + incompatibleFieldCount: partitionedFieldMetadata.incompatible.length, + incompatibleFieldMappingItems, + incompatibleFieldValueItems, + sameFamilyFieldCount: partitionedFieldMetadata.sameFamily.length, + sameFamilyFields: report.sameFamilyFields ?? [], + sameFamilyFieldItems, + unallowedMappingFields: report.unallowedMappingFields ?? [], + unallowedValueFields: report.unallowedValueFields ?? [], + sizeInBytes: report.sizeInBytes ?? 0, + ilmPhase: result.ilmPhase, + markdownComments: result.markdownComments, + ecsVersion: report.ecsVersion, + indexId: report.indexId ?? '', + error: result.error, + }; +}; + +export const formatResultFromStorage = ({ + storageResult, + pattern, +}: { + storageResult: StorageResult; + pattern: string; +}): DataQualityCheckResult => ({ + docsCount: storageResult.docsCount, + error: storageResult.error, + ilmPhase: storageResult.ilmPhase, + incompatible: storageResult.incompatibleFieldCount, + indexName: storageResult.indexName, + markdownComments: storageResult.markdownComments, + sameFamily: storageResult.sameFamilyFieldCount, + checkedAt: storageResult.checkedAt, + pattern, +}); + +export async function postStorageResult({ + storageResult, + httpFetch, + toasts, + abortController = new AbortController(), +}: { + storageResult: StorageResult; + httpFetch: HttpHandler; + toasts: IToasts; + abortController?: AbortController; +}): Promise { + try { + await httpFetch(POST_INDEX_RESULTS, { + method: 'POST', + signal: abortController.signal, + version: INTERNAL_API_VERSION, + body: JSON.stringify(storageResult), + }); + } catch (err) { + toasts.addError(err, { title: POST_RESULT_ERROR_TITLE }); + } +} + +export async function getStorageResults({ + pattern, + httpFetch, + toasts, + abortController, +}: { + pattern: string; + httpFetch: HttpHandler; + toasts: IToasts; + abortController: AbortController; +}): Promise { + try { + const route = GET_INDEX_RESULTS_LATEST.replace('{pattern}', pattern); + const results = await httpFetch(route, { + method: 'GET', + signal: abortController.signal, + version: INTERNAL_API_VERSION, + }); + return results; + } catch (err) { + toasts.addError(err, { title: GET_RESULTS_ERROR_TITLE }); + return []; + } +} diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx new file mode 100644 index 0000000000000..b7ea6613dac62 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.test.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DARK_THEME } from '@elastic/charts'; +import { render, screen } from '@testing-library/react'; +import { notificationServiceMock } from '@kbn/core-notifications-browser-mocks'; +import React from 'react'; + +import { TestExternalProviders } from './mock/test_providers/test_providers'; +import { mockUseResultsRollup } from './mock/use_results_rollup/mock_use_results_rollup'; +import { getCheckState } from './stub/get_check_state'; +import * as useResultsRollup from './hooks/use_results_rollup'; +import * as useIndicesCheck from './hooks/use_indices_check'; +import { DataQualityPanel } from '.'; + +jest.mock('./data_quality_details/indices_details/pattern/hooks/use_stats', () => ({ + useStats: jest.fn(() => ({ + stats: {}, + error: null, + loading: false, + })), +})); + +jest.mock('./data_quality_details/indices_details/pattern/hooks/use_ilm_explain', () => ({ + useIlmExplain: jest.fn(() => ({ + error: null, + ilmExplain: {}, + loading: false, + })), +})); + +jest.spyOn(useResultsRollup, 'useResultsRollup').mockImplementation(() => mockUseResultsRollup); + +jest.spyOn(useIndicesCheck, 'useIndicesCheck').mockImplementation(() => ({ + checkIndex: jest.fn(), + checkState: { + ...getCheckState('auditbeat-*'), + }, +})); + +const { toasts } = notificationServiceMock.createSetupContract(); + +const patterns = ['auditbeat-*']; + +describe('DataQualityPanel', () => { + beforeEach(() => { + jest.clearAllMocks(); + + render( + + + + ); + }); + + it('renders the data quality summary', () => { + expect(screen.getByTestId('dataQualitySummary')).toBeInTheDocument(); + }); + + it(`renders the '${patterns.join(', ')}' patterns`, () => { + for (const pattern of patterns) { + expect(screen.getByTestId(`${pattern}PatternPanel`)).toBeInTheDocument(); + } + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx similarity index 84% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx index 1fcedc7f76a82..7d1a106d83570 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/index.tsx @@ -11,16 +11,16 @@ import type { PartialTheme, Theme } from '@elastic/charts'; import React, { useCallback, useMemo, useState } from 'react'; import type { IToasts } from '@kbn/core-notifications-browser'; -import { EuiComboBoxOptionOption } from '@elastic/eui'; -import { Body } from './data_quality_panel/body'; -import { DataQualityProvider } from './data_quality_panel/data_quality_context'; -import { EMPTY_STAT } from './helpers'; +import { EuiComboBoxOptionOption, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { DataQualityProvider } from './data_quality_context'; import { ReportDataQualityCheckAllCompleted, ReportDataQualityIndexChecked } from './types'; import { ResultsRollupContext } from './contexts/results_rollup_context'; import { IndicesCheckContext } from './contexts/indices_check_context'; -import { useIndicesCheck } from './use_indices_check'; -import { useResultsRollup } from './use_results_rollup'; -import { ilmPhaseOptionsStatic } from './constants'; +import { useIndicesCheck } from './hooks/use_indices_check'; +import { useResultsRollup } from './hooks/use_results_rollup'; +import { ilmPhaseOptionsStatic, EMPTY_STAT } from './constants'; +import { DataQualitySummary } from './data_quality_summary'; +import { DataQualityDetails } from './data_quality_details'; interface Props { toasts: IToasts; @@ -141,7 +141,16 @@ const DataQualityPanelComponent: React.FC = ({ > - + + + + + + + + + + diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/allowed_values/mock_allowed_values.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/allowed_values/mock_allowed_values.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/allowed_values/mock_allowed_values.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/allowed_values/mock_allowed_values.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/data_quality_check_result/mock_index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/data_quality_check_result/mock_index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/data_quality_check_result/mock_index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/data_quality_check_result/mock_index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/enriched_field_metadata/mock_enriched_field_metadata.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/enriched_field_metadata/mock_enriched_field_metadata.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/enriched_field_metadata/mock_enriched_field_metadata.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/enriched_field_metadata/mock_enriched_field_metadata.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/ilm_explain/mock_ilm_explain.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/ilm_explain/mock_ilm_explain.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/ilm_explain/mock_ilm_explain.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/ilm_explain/mock_ilm_explain.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/indices_get_mapping_index_mapping_record/mock_indices_get_mapping_index_mapping_record.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/indices_get_mapping_index_mapping_record/mock_indices_get_mapping_index_mapping_record.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/indices_get_mapping_index_mapping_record/mock_indices_get_mapping_index_mapping_record.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/indices_get_mapping_index_mapping_record/mock_indices_get_mapping_index_mapping_record.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/mappings_properties/mock_mappings_properties.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/mappings_properties/mock_mappings_properties.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/mappings_properties/mock_mappings_properties.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/mappings_properties/mock_mappings_properties.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/mappings_response/mock_mappings_response.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/mappings_response/mock_mappings_response.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/mappings_response/mock_mappings_response.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/mappings_response/mock_mappings_response.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/partitioned_field_metadata/mock_partitioned_field_metadata.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/partitioned_field_metadata/mock_partitioned_field_metadata.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/partitioned_field_metadata/mock_partitioned_field_metadata.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/partitioned_field_metadata/mock_partitioned_field_metadata.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/partitioned_field_metadata/mock_partitioned_field_metadata_with_same_family.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/pattern_rollup/mock_alerts_pattern_rollup.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/pattern_rollup/mock_alerts_pattern_rollup.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/pattern_rollup/mock_alerts_pattern_rollup.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/pattern_rollup/mock_alerts_pattern_rollup.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/pattern_rollup/mock_auditbeat_pattern_rollup.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/pattern_rollup/mock_auditbeat_pattern_rollup.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/pattern_rollup/mock_auditbeat_pattern_rollup.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/pattern_rollup/mock_auditbeat_pattern_rollup.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/pattern_rollup/mock_packetbeat_pattern_rollup.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/pattern_rollup/mock_packetbeat_pattern_rollup.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/pattern_rollup/mock_packetbeat_pattern_rollup.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/pattern_rollup/mock_packetbeat_pattern_rollup.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/stats/mock_stats.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/stats/mock_stats.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/stats/mock_stats.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/stats/mock_stats.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/stats/mock_stats_auditbeat_index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/stats/mock_stats_auditbeat_index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/stats/mock_stats_auditbeat_index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/stats/mock_stats_auditbeat_index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/stats/mock_stats_packetbeat_index.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/stats/mock_stats_packetbeat_index.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/stats/mock_stats_packetbeat_index.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/stats/mock_stats_packetbeat_index.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx index 713b01e8ef71e..922d9b54612a6 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/test_providers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/test_providers.tsx @@ -16,14 +16,11 @@ import { ThemeProvider } from 'styled-components'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Theme } from '@elastic/charts'; -import { - DataQualityProvider, - DataQualityProviderProps, -} from '../../data_quality_panel/data_quality_context'; +import { DataQualityProvider, DataQualityProviderProps } from '../../data_quality_context'; import { ResultsRollupContext } from '../../contexts/results_rollup_context'; import { IndicesCheckContext } from '../../contexts/indices_check_context'; -import { UseIndicesCheckReturnValue } from '../../use_indices_check/types'; -import { UseResultsRollupReturnValue } from '../../use_results_rollup/types'; +import { UseIndicesCheckReturnValue } from '../../hooks/use_indices_check/types'; +import { UseResultsRollupReturnValue } from '../../hooks/use_results_rollup/types'; import { getMergeResultsRollupContextProps } from './utils/get_merged_results_rollup_context_props'; import { getMergedDataQualityContextProps } from './utils/get_merged_data_quality_context_props'; import { getMergedIndicesCheckContextProps } from './utils/get_merged_indices_check_context_props'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_data_quality_context_props.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_data_quality_context_props.ts similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_data_quality_context_props.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_data_quality_context_props.ts index d4cac9198e9c8..264198e510b5e 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_data_quality_context_props.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_data_quality_context_props.ts @@ -7,8 +7,8 @@ import numeral from '@elastic/numeral'; -import { DataQualityProviderProps } from '../../../data_quality_panel/data_quality_context'; -import { EMPTY_STAT } from '../../../helpers'; +import { DataQualityProviderProps } from '../../../data_quality_context'; +import { EMPTY_STAT } from '../../../constants'; export const getMergedDataQualityContextProps = ( dataQualityContextProps?: Partial diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_indices_check_context_props.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_indices_check_context_props.ts similarity index 95% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_indices_check_context_props.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_indices_check_context_props.ts index 28129d7e8155f..74817057ee377 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_indices_check_context_props.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_indices_check_context_props.ts @@ -9,7 +9,7 @@ import { getCheckState } from '../../../stub/get_check_state'; import { UseIndicesCheckCheckState, UseIndicesCheckReturnValue, -} from '../../../use_indices_check/types'; +} from '../../../hooks/use_indices_check/types'; export const getMergedIndicesCheckContextProps = ( patternIndexNames: Record, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_results_rollup_context_props.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_results_rollup_context_props.ts similarity index 57% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_results_rollup_context_props.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_results_rollup_context_props.ts index bb8e3e6967b4d..352b50ec1ef2a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/test_providers/utils/get_merged_results_rollup_context_props.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/test_providers/utils/get_merged_results_rollup_context_props.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { UseResultsRollupReturnValue } from '../../../use_results_rollup/types'; -import { auditbeatWithAllResults } from '../../pattern_rollup/mock_auditbeat_pattern_rollup'; +import { UseResultsRollupReturnValue } from '../../../hooks/use_results_rollup/types'; +import { mockUseResultsRollup } from '../../use_results_rollup/mock_use_results_rollup'; export const getMergeResultsRollupContextProps = ( resultsRollupContextProps?: Partial @@ -24,25 +24,7 @@ export const getMergeResultsRollupContextProps = ( updatePatternIndexNames, updatePatternRollup, } = { - onCheckCompleted: jest.fn(), - patternIndexNames: { - 'auditbeat-*': [ - '.ds-auditbeat-8.6.1-2023.02.07-000001', - 'auditbeat-custom-index-1', - 'auditbeat-custom-empty-index-1', - ], - }, - patternRollups: { - 'auditbeat-*': auditbeatWithAllResults, - }, - totalDocsCount: 19127, - totalIncompatible: 4, - totalIndices: 3, - totalIndicesChecked: 3, - totalSameFamily: 0, - totalSizeInBytes: 18820446, - updatePatternIndexNames: jest.fn(), - updatePatternRollup: jest.fn(), + ...mockUseResultsRollup, ...resultsRollupContextProps, }; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/unallowed_values/mock_unallowed_values.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/unallowed_values/mock_unallowed_values.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/mock/unallowed_values/mock_unallowed_values.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/unallowed_values/mock_unallowed_values.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/use_results_rollup/mock_use_results_rollup.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/use_results_rollup/mock_use_results_rollup.ts new file mode 100644 index 0000000000000..d3259d8c4c6d8 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/mock/use_results_rollup/mock_use_results_rollup.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { auditbeatWithAllResults } from '../pattern_rollup/mock_auditbeat_pattern_rollup'; + +export const mockUseResultsRollup = { + onCheckCompleted: jest.fn(), + patternIndexNames: { + 'auditbeat-*': [ + '.ds-auditbeat-8.6.1-2023.02.07-000001', + 'auditbeat-custom-index-1', + 'auditbeat-custom-empty-index-1', + ], + }, + patternRollups: { + 'auditbeat-*': auditbeatWithAllResults, + }, + totalDocsCount: 19127, + totalIncompatible: 4, + totalIndices: 3, + totalIndicesChecked: 3, + totalSameFamily: 0, + totalSizeInBytes: 18820446, + updatePatternIndexNames: jest.fn(), + updatePatternRollup: jest.fn(), +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/stat/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat/index.test.tsx similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/stat/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat/index.test.tsx index 6979be1c8af32..0db273d5d3024 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/stat/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat/index.test.tsx @@ -10,7 +10,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { Props, Stat, arePropsEqualOneLevelDeep } from '.'; -import { TestExternalProviders } from '../../../../../mock/test_providers/test_providers'; +import { TestExternalProviders } from '../mock/test_providers/test_providers'; describe('Stat', () => { it('renders stat with badge', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/stat/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat/index.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/stat/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat/index.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/stat_label/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat_label/translations.ts similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/stat_label/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stat_label/translations.ts diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/index.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stats_rollup/index.test.tsx similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/index.test.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stats_rollup/index.test.tsx index ba470748727bc..6b8106f33c157 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/index.test.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stats_rollup/index.test.tsx @@ -12,7 +12,7 @@ import userEvent from '@testing-library/user-event'; import { TestDataQualityProviders, TestExternalProviders, -} from '../../../../mock/test_providers/test_providers'; +} from '../mock/test_providers/test_providers'; import { StatsRollup } from '.'; describe('StatsRollup', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/index.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stats_rollup/index.tsx similarity index 92% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/index.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stats_rollup/index.tsx index 0a36dbf0e3ab3..7a0fb2deaf5bb 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/pattern/pattern_summary/stats_rollup/index.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stats_rollup/index.tsx @@ -9,10 +9,11 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { EMPTY_STAT, getIncompatibleStatBadgeColor } from '../../../../helpers'; -import { useDataQualityContext } from '../../../data_quality_context'; -import * as i18n from '../../../stat_label/translations'; -import { Stat } from './stat'; +import { EMPTY_STAT } from '../constants'; +import { useDataQualityContext } from '../data_quality_context'; +import * as i18n from '../stat_label/translations'; +import { Stat } from '../stat'; +import { getIncompatibleStatBadgeColor } from '../utils/get_incompatible_stat_badge_color'; const StyledStatWrapperFlexItem = styled(EuiFlexItem)` padding: 0 ${({ theme }) => theme.eui.euiSize}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/stub/get_check_state/index.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stub/get_check_state/index.ts similarity index 84% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/stub/get_check_state/index.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stub/get_check_state/index.ts index c1ba27ac91376..12f45c192aa25 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/stub/get_check_state/index.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/stub/get_check_state/index.ts @@ -10,11 +10,11 @@ import { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/ import { getMappingsProperties, getSortedPartitionedFieldMetadata, -} from '../../data_quality_panel/index_properties/helpers'; +} from '../../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers'; import { mockMappingsResponse } from '../../mock/mappings_response/mock_mappings_response'; -import { UseIndicesCheckCheckState } from '../../use_indices_check/types'; -import { getUnallowedValues } from '../../use_unallowed_values/helpers'; -import { getUnallowedValueRequestItems } from '../../data_quality_panel/allowed_values/helpers'; +import { UseIndicesCheckCheckState } from '../../hooks/use_indices_check/types'; +import { getUnallowedValues } from '../../utils/fetch_unallowed_values'; +import { getUnallowedValueRequestItems } from '../../utils/get_unallowed_value_request_items'; import { EcsFlatTyped } from '../../constants'; import { mockUnallowedValuesResponse } from '../../mock/unallowed_values/mock_unallowed_values'; import { UnallowedValueSearchResult } from '../../types'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/styles.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/styles.tsx similarity index 100% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/styles.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/styles.tsx diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts similarity index 79% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts index 6c78513274de8..3497aa89d97ee 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/translations.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/translations.ts @@ -42,13 +42,6 @@ export const COLD_DESCRIPTION = i18n.translate( } ); -export const COLD_PATTERN_TOOLTIP = ({ indices, pattern }: { indices: number; pattern: string }) => - i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.coldPatternTooltip', { - values: { indices, pattern }, - defaultMessage: - '{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} cold. Cold indices are no longer being updated and are queried infrequently. The information still needs to be searchable, but it’s okay if those queries are slower.', - }); - export const COPIED_RESULTS_TOAST_TITLE = i18n.translate( 'securitySolutionPackages.ecsDataQualityDashboard.toasts.copiedResultsToastTitle', { @@ -166,18 +159,6 @@ export const FROZEN_DESCRIPTION = i18n.translate( } ); -export const FROZEN_PATTERN_TOOLTIP = ({ - indices, - pattern, -}: { - indices: number; - pattern: string; -}) => - i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.frozenPatternTooltip', { - values: { indices, pattern }, - defaultMessage: `{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} frozen. Frozen indices are no longer being updated and are queried rarely. The information still needs to be searchable, but it's okay if those queries are extremely slow.`, - }); - export const HOT_DESCRIPTION = i18n.translate( 'securitySolutionPackages.ecsDataQualityDashboard.hotDescription', { @@ -185,13 +166,6 @@ export const HOT_DESCRIPTION = i18n.translate( } ); -export const HOT_PATTERN_TOOLTIP = ({ indices, pattern }: { indices: number; pattern: string }) => - i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.hotPatternTooltip', { - values: { indices, pattern }, - defaultMessage: - '{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} hot. Hot indices are actively being updated and queried.', - }); - /** The tooltip for the `ILM phase` combo box on the Data Quality Dashboard */ export const INDEX_LIFECYCLE_MANAGEMENT_PHASES: string = i18n.translate( 'securitySolutionPackages.ecsDataQualityDashboard.indexLifecycleManagementPhasesTooltip', @@ -267,18 +241,6 @@ export const UNMANAGED_DESCRIPTION = i18n.translate( } ); -export const UNMANAGED_PATTERN_TOOLTIP = ({ - indices, - pattern, -}: { - indices: number; - pattern: string; -}) => - i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.unmanagedPatternTooltip', { - values: { indices, pattern }, - defaultMessage: `{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} unmanaged by Index Lifecycle Management (ILM)`, - }); - export const WARM_DESCRIPTION = i18n.translate( 'securitySolutionPackages.ecsDataQualityDashboard.warmDescription', { @@ -286,13 +248,6 @@ export const WARM_DESCRIPTION = i18n.translate( } ); -export const WARM_PATTERN_TOOLTIP = ({ indices, pattern }: { indices: number; pattern: string }) => - i18n.translate('securitySolutionPackages.ecsDataQualityDashboard.warmPatternTooltip', { - values: { indices, pattern }, - defaultMessage: - '{indices} {indices, plural, =1 {index} other {indices}} matching the {pattern} pattern {indices, plural, =1 {is} other {are}} warm. Warm indices are no longer being updated but are still being queried.', - }); - export const POST_RESULT_ERROR_TITLE = i18n.translate( 'securitySolutionPackages.ecsDataQualityDashboard.postResultErrorTitle', { defaultMessage: 'Error writing saved data quality check results' } diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/types.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/types.ts similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/types.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/types.ts index dd5dd6dd0a159..916d0f377bf85 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/types.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/types.ts @@ -85,14 +85,6 @@ export interface PartitionedFieldMetadata { sameFamily: EcsBasedFieldMetadata[]; } -export interface PartitionedFieldMetadataStats { - all: number; - custom: number; - ecsCompliant: number; - incompatible: number; - sameFamily: number; -} - export interface UnallowedValueRequestItem { allowedValues: string[]; indexFieldName: string; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/utils/check_index.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/check_index.test.ts similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/utils/check_index.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/check_index.test.ts index 9ea197360356f..2b90f67966c77 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/utils/check_index.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/check_index.test.ts @@ -6,37 +6,40 @@ */ import { checkIndex, EMPTY_PARTITIONED_FIELD_METADATA } from './check_index'; -import { EMPTY_STAT } from '../helpers'; import { mockMappingsResponse } from '../mock/mappings_response/mock_mappings_response'; import { mockUnallowedValuesResponse } from '../mock/unallowed_values/mock_unallowed_values'; import { UnallowedValueRequestItem, UnallowedValueSearchResult } from '../types'; import { getMappingsProperties, getSortedPartitionedFieldMetadata, -} from '../data_quality_panel/index_properties/helpers'; +} from '../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers'; import { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; -import { getUnallowedValues } from '../use_unallowed_values/helpers'; -import { getUnallowedValueRequestItems } from '../data_quality_panel/allowed_values/helpers'; -import { EcsFlatTyped } from '../constants'; +import { getUnallowedValues } from './fetch_unallowed_values'; +import { getUnallowedValueRequestItems } from './get_unallowed_value_request_items'; +import { EcsFlatTyped, EMPTY_STAT } from '../constants'; let mockFetchMappings = jest.fn( (_: { abortController: AbortController; patternOrIndexName: string }) => Promise.resolve(mockMappingsResponse) ); -jest.mock('../use_mappings/helpers', () => ({ - fetchMappings: ({ - abortController, - patternOrIndexName, - }: { - abortController: AbortController; - patternOrIndexName: string; - }) => - mockFetchMappings({ +jest.mock('./fetch_mappings', () => { + const original = jest.requireActual('./fetch_mappings'); + return { + ...original, + fetchMappings: ({ abortController, patternOrIndexName, - }), -})); + }: { + abortController: AbortController; + patternOrIndexName: string; + }) => + mockFetchMappings({ + abortController, + patternOrIndexName, + }), + }; +}); const mockFetchUnallowedValues = jest.fn( (_: { @@ -46,8 +49,8 @@ const mockFetchUnallowedValues = jest.fn( }) => Promise.resolve(mockUnallowedValuesResponse) ); -jest.mock('../use_unallowed_values/helpers', () => { - const original = jest.requireActual('../use_unallowed_values/helpers'); +jest.mock('./fetch_unallowed_values', () => { + const original = jest.requireActual('./fetch_unallowed_values'); return { ...original, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/utils/check_index.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/check_index.ts similarity index 91% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/utils/check_index.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/check_index.ts index 8dd282c4121f0..76094c97f5667 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/utils/check_index.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/check_index.ts @@ -12,20 +12,20 @@ import { } from '@elastic/elasticsearch/lib/api/types'; import { v4 as uuidv4 } from 'uuid'; -import { getUnallowedValueRequestItems } from '../data_quality_panel/allowed_values/helpers'; +import { getUnallowedValueRequestItems } from './get_unallowed_value_request_items'; import { getMappingsProperties, getSortedPartitionedFieldMetadata, -} from '../data_quality_panel/index_properties/helpers'; -import * as i18n from '../data_quality_panel/data_quality_summary/summary_actions/check_all/translations'; +} from '../data_quality_details/indices_details/pattern/index_check_flyout/index_properties/helpers'; +import * as i18n from '../data_quality_summary/summary_actions/check_all/translations'; import type { OnCheckCompleted, PartitionedFieldMetadata, UnallowedValueCount, UnallowedValueSearchResult, } from '../types'; -import { fetchMappings } from '../use_mappings/helpers'; -import { fetchUnallowedValues, getUnallowedValues } from '../use_unallowed_values/helpers'; +import { fetchMappings } from './fetch_mappings'; +import { fetchUnallowedValues, getUnallowedValues } from './fetch_unallowed_values'; import { EcsFlatTyped } from '../constants'; export const EMPTY_PARTITIONED_FIELD_METADATA: PartitionedFieldMetadata = { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_mappings.test.ts similarity index 97% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_mappings.test.ts index b3a31228bb059..b24241b95a510 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_mappings.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { fetchMappings } from './helpers'; +import { fetchMappings } from './fetch_mappings'; import { mockMappingsResponse } from '../mock/mappings_response/mock_mappings_response'; describe('helpers', () => { diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_mappings.ts similarity index 96% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_mappings.ts index 6bee012883c05..090f7e375e5bc 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_mappings/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_mappings.ts @@ -9,7 +9,7 @@ import type { HttpHandler } from '@kbn/core-http-browser'; import type { IndicesGetMappingIndexMappingRecord } from '@elastic/elasticsearch/lib/api/types'; import * as i18n from '../translations'; -import { INTERNAL_API_VERSION } from '../helpers'; +import { INTERNAL_API_VERSION } from '../constants'; export const MAPPINGS_API_ROUTE = '/internal/ecs_data_quality_dashboard/mappings'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/helpers.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_unallowed_values.test.ts similarity index 99% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/helpers.test.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_unallowed_values.test.ts index ade9970277c50..00dc04dedf27a 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/helpers.test.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_unallowed_values.test.ts @@ -12,10 +12,10 @@ import { getUnallowedValueCount, getUnallowedValues, isBucket, -} from './helpers'; +} from './fetch_unallowed_values'; import { mockUnallowedValuesResponse } from '../mock/unallowed_values/mock_unallowed_values'; import { UnallowedValueRequestItem, UnallowedValueSearchResult } from '../types'; -import { INTERNAL_API_VERSION } from '../helpers'; +import { INTERNAL_API_VERSION } from '../constants'; describe('helpers', () => { let originalFetch: (typeof global)['fetch']; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/helpers.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_unallowed_values.ts similarity index 98% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/helpers.ts rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_unallowed_values.ts index aa25a5fe00b44..b19481546a285 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/use_unallowed_values/helpers.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/fetch_unallowed_values.ts @@ -6,7 +6,8 @@ */ import type { HttpHandler } from '@kbn/core-http-browser'; -import { INTERNAL_API_VERSION } from '../helpers'; + +import { INTERNAL_API_VERSION } from '../constants'; import * as i18n from '../translations'; import type { Bucket, @@ -15,8 +16,6 @@ import type { UnallowedValueSearchResult, } from '../types'; -const UNALLOWED_VALUES_API_ROUTE = '/internal/ecs_data_quality_dashboard/unallowed_field_values'; - export const isBucket = (maybeBucket: unknown): maybeBucket is Bucket => maybeBucket != null && typeof (maybeBucket as Bucket).key === 'string' && @@ -65,6 +64,7 @@ export const getUnallowedValues = ({ }, {}); }; +const UNALLOWED_VALUES_API_ROUTE = '/internal/ecs_data_quality_dashboard/unallowed_field_values'; export async function fetchUnallowedValues({ abortController, httpFetch, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.test.ts new file mode 100644 index 0000000000000..b2ff66941b395 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getIlmPhaseDescription } from './get_ilm_phase_description'; +import { + COLD_DESCRIPTION, + FROZEN_DESCRIPTION, + HOT_DESCRIPTION, + UNMANAGED_DESCRIPTION, + WARM_DESCRIPTION, +} from '../translations'; + +describe('helpers', () => { + describe('getIlmPhaseDescription', () => { + const phases: Array<{ + phase: string; + expected: string; + }> = [ + { + phase: 'hot', + expected: HOT_DESCRIPTION, + }, + { + phase: 'warm', + expected: WARM_DESCRIPTION, + }, + { + phase: 'cold', + expected: COLD_DESCRIPTION, + }, + { + phase: 'frozen', + expected: FROZEN_DESCRIPTION, + }, + { + phase: 'unmanaged', + expected: UNMANAGED_DESCRIPTION, + }, + { + phase: 'something-else', + expected: ' ', + }, + ]; + + phases.forEach(({ phase, expected }) => { + test(`it returns ${expected} when phase is ${phase}`, () => { + expect(getIlmPhaseDescription(phase)).toBe(expected); + }); + }); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.ts new file mode 100644 index 0000000000000..27f20cd28e1a4 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_ilm_phase_description.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import * as i18n from '../translations'; + +/** + * Returns an i18n description of an an ILM phase + */ +export const getIlmPhaseDescription = (phase: string): string => { + switch (phase) { + case 'hot': + return i18n.HOT_DESCRIPTION; + case 'warm': + return i18n.WARM_DESCRIPTION; + case 'cold': + return i18n.COLD_DESCRIPTION; + case 'frozen': + return i18n.FROZEN_DESCRIPTION; + case 'unmanaged': + return i18n.UNMANAGED_DESCRIPTION; + default: + return ' '; + } +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_incompatible_stat_badge_color.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_incompatible_stat_badge_color.test.ts new file mode 100644 index 0000000000000..44283436f7477 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_incompatible_stat_badge_color.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getIncompatibleStatBadgeColor } from './get_incompatible_stat_badge_color'; + +describe('getIncompatibleStatBadgeColor', () => { + describe('when incompatible is greater than 0', () => { + it('returns danger', () => { + expect(getIncompatibleStatBadgeColor(1)).toBe('danger'); + }); + }); + + describe('when incompatible is 0', () => { + it('returns hollow', () => { + expect(getIncompatibleStatBadgeColor(0)).toBe('hollow'); + }); + }); + + describe('when incompatible is undefined', () => { + it('returns hollow', () => { + expect(getIncompatibleStatBadgeColor(undefined)).toBe('hollow'); + }); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_incompatible_stat_badge_color.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_incompatible_stat_badge_color.ts new file mode 100644 index 0000000000000..fcaa660bba934 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_incompatible_stat_badge_color.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 const getIncompatibleStatBadgeColor = (incompatible: number | undefined): string => + incompatible != null && incompatible > 0 ? 'danger' : 'hollow'; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/allowed_values/helpers.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_unallowed_value_request_items.tsx similarity index 94% rename from x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/allowed_values/helpers.tsx rename to x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_unallowed_value_request_items.tsx index fd356b9fe60d5..8ce15c11b7000 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality/data_quality_panel/allowed_values/helpers.tsx +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_unallowed_value_request_items.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import type { EcsFlatTyped } from '../../constants'; -import type { EcsFieldMetadata, UnallowedValueRequestItem } from '../../types'; +import type { EcsFlatTyped } from '../constants'; +import type { EcsFieldMetadata, UnallowedValueRequestItem } from '../types'; export const hasAllowedValues = ({ ecsMetadata, diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_unallowed_values_request_items.test.tsx b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_unallowed_values_request_items.test.tsx new file mode 100644 index 0000000000000..c2a35bc989625 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/get_unallowed_values_request_items.test.tsx @@ -0,0 +1,154 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EcsFlatTyped } from '../constants'; +import { + getUnallowedValueRequestItems, + getValidValues, + hasAllowedValues, +} from './get_unallowed_value_request_items'; + +describe('hasAllowedValues', () => { + test('it returns true for a field that has `allowed_values`', () => { + expect( + hasAllowedValues({ + ecsMetadata: EcsFlatTyped, + fieldName: 'event.category', + }) + ).toBe(true); + }); + + test('it returns false for a field that does NOT have `allowed_values`', () => { + expect( + hasAllowedValues({ + ecsMetadata: EcsFlatTyped, + fieldName: 'host.name', + }) + ).toBe(false); + }); + + test('it returns false for a field that does NOT exist in `ecsMetadata`', () => { + expect( + hasAllowedValues({ + ecsMetadata: EcsFlatTyped, + fieldName: 'does.NOT.exist', + }) + ).toBe(false); + }); +}); + +describe('getValidValues', () => { + test('it returns the expected valid values', () => { + expect(getValidValues(EcsFlatTyped['event.category'])).toEqual( + expect.arrayContaining([ + 'authentication', + 'configuration', + 'database', + 'driver', + 'email', + 'file', + 'host', + 'iam', + 'intrusion_detection', + 'malware', + 'network', + 'package', + 'process', + 'registry', + 'session', + 'threat', + 'vulnerability', + 'web', + ]) + ); + }); + + test('it returns an empty array when the `field` does NOT have `allowed_values`', () => { + expect(getValidValues(EcsFlatTyped['host.name'])).toEqual([]); + }); + + test('it returns an empty array when `field` is undefined', () => { + expect(getValidValues(undefined)).toEqual([]); + }); +}); + +describe('getUnallowedValueRequestItems', () => { + test('it returns the expected request items', () => { + expect( + getUnallowedValueRequestItems({ + ecsMetadata: EcsFlatTyped, + indexName: 'auditbeat-*', + }) + ).toEqual([ + { + indexName: 'auditbeat-*', + indexFieldName: 'event.category', + allowedValues: expect.arrayContaining([ + 'authentication', + 'configuration', + 'database', + 'driver', + 'email', + 'file', + 'host', + 'iam', + 'intrusion_detection', + 'malware', + 'network', + 'package', + 'process', + 'registry', + 'session', + 'threat', + 'vulnerability', + 'web', + ]), + }, + { + indexName: 'auditbeat-*', + indexFieldName: 'event.kind', + allowedValues: expect.arrayContaining([ + 'alert', + 'enrichment', + 'event', + 'metric', + 'state', + 'pipeline_error', + 'signal', + ]), + }, + { + indexName: 'auditbeat-*', + indexFieldName: 'event.outcome', + allowedValues: expect.arrayContaining(['failure', 'success', 'unknown']), + }, + { + indexName: 'auditbeat-*', + indexFieldName: 'event.type', + allowedValues: expect.arrayContaining([ + 'access', + 'admin', + 'allowed', + 'change', + 'connection', + 'creation', + 'deletion', + 'denied', + 'end', + 'error', + 'group', + 'indicator', + 'info', + 'installation', + 'protocol', + 'start', + 'user', + ]), + }, + ]); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/stats.test.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/stats.test.ts new file mode 100644 index 0000000000000..ad91466634ea7 --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/stats.test.ts @@ -0,0 +1,252 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + auditbeatNoResults, + auditbeatWithAllResults, +} from '../mock/pattern_rollup/mock_auditbeat_pattern_rollup'; +import { packetbeatWithSomeErrors } from '../mock/pattern_rollup/mock_packetbeat_pattern_rollup'; +import { mockStatsPacketbeatIndex } from '../mock/stats/mock_stats_auditbeat_index'; +import { mockStatsAuditbeatIndex } from '../mock/stats/mock_stats_packetbeat_index'; +import { DataQualityCheckResult } from '../types'; +import { + getDocsCount, + getSizeInBytes, + getTotalPatternIncompatible, + getTotalPatternIndicesChecked, +} from './stats'; + +describe('getTotalPatternIndicesChecked', () => { + test('it returns zero when `patternRollup` is undefined', () => { + expect(getTotalPatternIndicesChecked(undefined)).toEqual(0); + }); + + test('it returns zero when `patternRollup` does NOT have any results', () => { + expect(getTotalPatternIndicesChecked(auditbeatNoResults)).toEqual(0); + }); + + test('it returns the expected total when all indices in `patternRollup` have results', () => { + expect(getTotalPatternIndicesChecked(auditbeatWithAllResults)).toEqual(3); + }); + + test('it returns the expected total when some indices in `patternRollup` have errors', () => { + expect(getTotalPatternIndicesChecked(packetbeatWithSomeErrors)).toEqual(1); + }); +}); + +describe('getDocsCount', () => { + test('it returns the expected docs count when `stats` contains the `indexName`', () => { + const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; + const expectedCount = mockStatsPacketbeatIndex[indexName].num_docs; + + expect( + getDocsCount({ + indexName, + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(expectedCount); + }); + + test('it returns zero when `stats` does NOT contain the `indexName`', () => { + const indexName = 'not-gonna-find-it'; + + expect( + getDocsCount({ + indexName, + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(0); + }); + + test('it returns zero when `stats` is null', () => { + const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; + + expect( + getDocsCount({ + indexName, + stats: null, + }) + ).toEqual(0); + }); + + test('it returns the expected total for a green index, where `primaries.docs.count` and `total.docs.count` have different values', () => { + const indexName = 'auditbeat-custom-index-1'; + + expect( + getDocsCount({ + indexName, + stats: mockStatsAuditbeatIndex, + }) + ).toEqual(mockStatsAuditbeatIndex[indexName].num_docs); + }); +}); + +describe('getSizeInBytes', () => { + test('it returns the expected size when `stats` contains the `indexName`', () => { + const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; + const expectedCount = mockStatsPacketbeatIndex[indexName].size_in_bytes; + + expect( + getSizeInBytes({ + indexName, + stats: mockStatsPacketbeatIndex, + }) + ).toEqual(expectedCount); + }); + + test('it returns undefined when `stats` does NOT contain the `indexName`', () => { + const indexName = 'not-gonna-find-it'; + + expect( + getSizeInBytes({ + indexName, + stats: mockStatsPacketbeatIndex, + }) + ).toBeUndefined(); + }); + + test('it returns undefined when `stats` is null', () => { + const indexName = '.ds-packetbeat-8.6.1-2023.02.04-000001'; + + expect( + getSizeInBytes({ + indexName, + stats: null, + }) + ).toBeUndefined(); + }); + + test('it returns the expected size for a green index, where `primaries.store.size_in_bytes` and `total.store.size_in_bytes` have different values', () => { + const indexName = 'auditbeat-custom-index-1'; + + expect( + getSizeInBytes({ + indexName, + stats: mockStatsAuditbeatIndex, + }) + ).toEqual(mockStatsAuditbeatIndex[indexName].size_in_bytes); + }); +}); + +describe('getTotalPatternIncompatible', () => { + test('it returns zero when multiple indices in the results results have a count of zero', () => { + const results: Record = { + '.ds-packetbeat-8.5.3-2023.02.04-000001': { + docsCount: 1630289, + error: null, + ilmPhase: 'hot', + incompatible: 0, + indexName: '.ds-packetbeat-8.5.3-2023.02.04-000001', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'packetbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + '.ds-packetbeat-8.6.1-2023.02.04-000001': { + docsCount: 1628343, + error: null, + ilmPhase: 'hot', + incompatible: 0, + indexName: '.ds-packetbeat-8.6.1-2023.02.04-000001', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'packetbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + }; + + expect(getTotalPatternIncompatible(results)).toEqual(0); + }); + + test("it returns the expected total when some indices have incompatible fields, but others don't", () => { + const results: Record = { + '.ds-auditbeat-8.6.1-2023.02.07-000001': { + docsCount: 18086, + error: null, + ilmPhase: 'hot', + incompatible: 0, + indexName: '.ds-auditbeat-8.6.1-2023.02.07-000001', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + 'auditbeat-custom-index-1': { + docsCount: 4, + error: null, + ilmPhase: 'unmanaged', + incompatible: 3, + indexName: 'auditbeat-custom-index-1', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + 'auditbeat-custom-empty-index-1': { + docsCount: 0, + error: null, + ilmPhase: 'unmanaged', + incompatible: 1, + indexName: 'auditbeat-custom-empty-index-1', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + }; + + expect(getTotalPatternIncompatible(results)).toEqual(4); + }); + + test('it returns the expected total when some indices have undefined incompatible counts', () => { + const results: Record = { + '.ds-auditbeat-8.6.1-2023.02.07-000001': { + docsCount: 18086, + error: null, + ilmPhase: 'hot', + incompatible: undefined, // <-- this index has an undefined `incompatible` + indexName: '.ds-auditbeat-8.6.1-2023.02.07-000001', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + 'auditbeat-custom-index-1': { + docsCount: 4, + error: null, + ilmPhase: 'unmanaged', + incompatible: 3, + indexName: 'auditbeat-custom-index-1', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + 'auditbeat-custom-empty-index-1': { + docsCount: 0, + error: null, + ilmPhase: 'unmanaged', + incompatible: 1, + indexName: 'auditbeat-custom-empty-index-1', + markdownComments: ['foo', 'bar', 'baz'], + pattern: 'auditbeat-*', + sameFamily: 0, + checkedAt: Date.now(), + }, + }; + + expect(getTotalPatternIncompatible(results)).toEqual(4); + }); + + test('it returns zero when `results` is empty', () => { + expect(getTotalPatternIncompatible({})).toEqual(0); + }); + + test('it returns undefined when `results` is undefined', () => { + expect(getTotalPatternIncompatible(undefined)).toBeUndefined(); + }); +}); diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/stats.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/stats.ts new file mode 100644 index 0000000000000..b8f60be24a87c --- /dev/null +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/impl/data_quality_panel/utils/stats.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 { DataQualityCheckResult, MeteringStatsIndex, PatternRollup } from '../types'; + +export const getSizeInBytes = ({ + indexName, + stats, +}: { + indexName: string; + stats: Record | null; +}): number | undefined => (stats && stats[indexName]?.size_in_bytes) ?? undefined; + +export const getDocsCount = ({ + indexName, + stats, +}: { + indexName: string; + stats: Record | null; +}): number => (stats && stats[indexName]?.num_docs) ?? 0; + +export const getTotalPatternIndicesChecked = (patternRollup: PatternRollup | undefined): number => { + if (patternRollup != null && patternRollup.results != null) { + const allResults = Object.values(patternRollup.results); + const nonErrorResults = allResults.filter(({ error }) => error == null); + + return nonErrorResults.length; + } else { + return 0; + } +}; + +export const getTotalPatternIncompatible = ( + results: Record | undefined +): number | undefined => { + if (results == null) { + return undefined; + } + + const allResults = Object.values(results); + + return allResults.reduce((acc, { incompatible }) => acc + (incompatible ?? 0), 0); +}; diff --git a/x-pack/packages/security-solution/ecs_data_quality_dashboard/index.ts b/x-pack/packages/security-solution/ecs_data_quality_dashboard/index.ts index 5f9ab020ea21f..96288f2bfec6c 100644 --- a/x-pack/packages/security-solution/ecs_data_quality_dashboard/index.ts +++ b/x-pack/packages/security-solution/ecs_data_quality_dashboard/index.ts @@ -5,9 +5,9 @@ * 2.0. */ -export { DataQualityPanel } from './impl/data_quality'; +export { DataQualityPanel } from './impl/data_quality_panel'; -export { getIlmPhaseDescription } from './impl/data_quality/helpers'; +export { getIlmPhaseDescription } from './impl/data_quality_panel/utils/get_ilm_phase_description'; export { DATA_QUALITY_PROMPT_CONTEXT_PILL, @@ -18,6 +18,6 @@ export { INDEX_LIFECYCLE_MANAGEMENT_PHASES, SELECT_ONE_OR_MORE_ILM_PHASES, DATA_QUALITY_DASHBOARD_CONVERSATION_ID, -} from './impl/data_quality/translations'; +} from './impl/data_quality_panel/translations'; -export { ECS_REFERENCE_URL } from './impl/data_quality/data_quality_panel/index_properties/markdown/helpers'; +export { ECS_REFERENCE_URL } from './impl/data_quality_panel/data_quality_details/indices_details/pattern/index_check_flyout/index_properties/markdown/helpers'; diff --git a/x-pack/plugins/actions/server/lib/action_executor.test.ts b/x-pack/plugins/actions/server/lib/action_executor.test.ts index b2e6badae3c59..560d5dc3ecea5 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.test.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.test.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { KibanaRequest } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { ActionExecutor } from './action_executor'; @@ -18,7 +17,7 @@ import { } from '@kbn/core/server/mocks'; import { eventLoggerMock } from '@kbn/event-log-plugin/server/mocks'; import { spacesServiceMock } from '@kbn/spaces-plugin/server/spaces_service/spaces_service.mock'; -import { ActionType as ConnectorType } from '../types'; +import { ActionType as ConnectorType, ConnectorUsageCollector } from '../types'; import { actionsAuthorizationMock, actionsMock } from '../mocks'; import { asBackgroundTaskExecutionSource, @@ -150,6 +149,10 @@ const connectorSavedObject = { references: [], }; +interface ActionUsage { + request_body_bytes: number; +} + const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { return { event: { @@ -163,6 +166,7 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { }, id: CONNECTOR_ID, name: '1', + type_id: 'test', }, ...(unsecured ? {} @@ -190,10 +194,23 @@ const getBaseExecuteStartEventLogDoc = (unsecured: boolean) => { }; }; -const getBaseExecuteEventLogDoc = (unsecured: boolean) => { +const getBaseExecuteEventLogDoc = ( + unsecured: boolean, + actionUsage: ActionUsage = { request_body_bytes: 0 } +) => { const base = getBaseExecuteStartEventLogDoc(unsecured); return { ...base, + kibana: { + ...base.kibana, + action: { + ...base.kibana.action, + execution: { + ...base.kibana.action.execution, + usage: actionUsage, + }, + }, + }, event: { ...base.event, action: 'execute', @@ -211,9 +228,12 @@ const getBaseExecuteEventLogDoc = (unsecured: boolean) => { }; }; +const mockGetRequestBodyByte = jest.spyOn(ConnectorUsageCollector.prototype, 'getRequestBodyByte'); + beforeEach(() => { jest.resetAllMocks(); jest.clearAllMocks(); + mockGetRequestBodyByte.mockReturnValue(0); spacesMock.getSpaceId.mockReturnValue('some-namespace'); loggerMock.get.mockImplementation(() => loggerMock); const mockRealm = { name: 'default_native', type: 'native' }; @@ -237,6 +257,7 @@ describe('Action Executor', () => { const label = executeUnsecure ? 'executes unsecured' : 'executes'; test(`successfully ${label}`, async () => { + mockGetRequestBodyByte.mockReturnValue(300); encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce( connectorSavedObject ); @@ -280,13 +301,15 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:1: 1'); expect(eventLogger.logEvent).toHaveBeenCalledTimes(2); const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); - const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + const execDoc = getBaseExecuteEventLogDoc(executeUnsecure, { request_body_bytes: 300 }); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, execStartDoc); expect(eventLogger.logEvent).toHaveBeenNthCalledWith(2, execDoc); }); @@ -353,6 +376,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, source: executionSource.source, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:1: 1'); @@ -360,6 +384,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -431,6 +456,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); @@ -438,6 +464,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -513,6 +540,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); } @@ -532,6 +560,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -540,6 +569,7 @@ describe('Action Executor', () => { ...execStartDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -569,6 +599,7 @@ describe('Action Executor', () => { ...execDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -890,6 +921,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -921,6 +953,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -989,6 +1022,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith('executing action test:preconfigured: Preconfigured'); @@ -996,6 +1030,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -1026,6 +1061,12 @@ describe('Action Executor', () => { ...execDoc.kibana.action, id: 'preconfigured', name: 'Preconfigured', + execution: { + ...execStartDoc.kibana.action.execution, + usage: { + request_body_bytes: 0, + }, + }, }, saved_objects: [ { @@ -1074,6 +1115,7 @@ describe('Action Executor', () => { params: { foo: true }, logger: loggerMock, request: {}, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(loggerMock.debug).toBeCalledWith( @@ -1083,6 +1125,7 @@ describe('Action Executor', () => { const execStartDoc = getBaseExecuteStartEventLogDoc(executeUnsecure); const execDoc = getBaseExecuteEventLogDoc(executeUnsecure); + expect(eventLogger.logEvent).toHaveBeenNthCalledWith(1, { ...execStartDoc, kibana: { @@ -1091,6 +1134,7 @@ describe('Action Executor', () => { ...execStartDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -1120,6 +1164,7 @@ describe('Action Executor', () => { ...execDoc.kibana.action, id: 'system-connector-.cases', name: 'System action: .cases', + type_id: '.cases', }, saved_objects: [ { @@ -1290,6 +1335,7 @@ describe('Action Executor', () => { }, params: { foo: true }, logger: loggerMock, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); } }); @@ -1385,6 +1431,7 @@ describe('Event log', () => { }, name: undefined, id: 'action1', + type_id: 'test', }, alert: { rule: { @@ -1430,6 +1477,7 @@ describe('Event log', () => { }, name: 'action-1', id: '1', + type_id: 'test', }, alert: { rule: { @@ -1483,6 +1531,7 @@ describe('Event log', () => { }, name: 'action-1', id: '1', + type_id: 'test', }, alert: { rule: { @@ -1559,9 +1608,13 @@ describe('Event log', () => { gen_ai: { usage: mockGenAi.usage, }, + usage: { + request_body_bytes: 0, + }, }, name: 'action-1', id: '1', + type_id: '.gen-ai', }, alert: { rule: { @@ -1655,9 +1708,13 @@ describe('Event log', () => { total_tokens: 35, }, }, + usage: { + request_body_bytes: 0, + }, }, name: 'action-1', id: '1', + type_id: '.gen-ai', }, alert: { rule: { diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index 685e18c585ae0..c302b0da3e886 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -23,6 +23,7 @@ import { IEventLogger, SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/se import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { getErrorSource } from '@kbn/task-manager-plugin/server/task_running'; import { GEN_AI_TOKEN_COUNT_EVENT } from './event_based_telemetry'; +import { ConnectorUsageCollector } from '../usage/connector_usage_collector'; import { getGenAiTokenTracking, shouldTrackGenAiToken } from './gen_ai_token_tracking'; import { validateConfig, @@ -293,6 +294,7 @@ export class ActionExecutor { actionExecutionId, isInMemory: this.actionInfo.isInMemory, ...(source ? { source } : {}), + actionTypeId: this.actionInfo.actionTypeId, }); eventLogger.logEvent(event); @@ -394,6 +396,14 @@ export class ActionExecutor { const { actionTypeId, name, config, secrets } = actionInfo; + const loggerId = actionTypeId.startsWith('.') ? actionTypeId.substring(1) : actionTypeId; + const logger = this.actionExecutorContext!.logger.get(loggerId); + + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: actionId, + }); + if (!this.actionInfo || this.actionInfo.actionId !== actionId) { this.actionInfo = actionInfo; } @@ -434,9 +444,6 @@ export class ActionExecutor { return err.result; } - const loggerId = actionTypeId.startsWith('.') ? actionTypeId.substring(1) : actionTypeId; - const logger = this.actionExecutorContext!.logger.get(loggerId); - if (span) { span.name = `${executeLabel} ${actionTypeId}`; span.addLabels({ @@ -477,6 +484,7 @@ export class ActionExecutor { actionExecutionId, isInMemory: this.actionInfo.isInMemory, ...(source ? { source } : {}), + actionTypeId, }); eventLogger.startTiming(event); @@ -510,6 +518,7 @@ export class ActionExecutor { logger, source, ...(actionType.isSystemActionType ? { request } : {}), + connectorUsageCollector, }); if (rawResult && rawResult.status === 'error') { @@ -548,6 +557,11 @@ export class ActionExecutor { event.user = event.user || {}; event.user.name = currentUser?.username; event.user.id = currentUser?.profile_uid; + set( + event, + 'kibana.action.execution.usage.request_body_bytes', + connectorUsageCollector.getRequestBodyByte() + ); if (result.status === 'ok') { span?.setOutcome('success'); diff --git a/x-pack/plugins/actions/server/lib/axios_utils.test.ts b/x-pack/plugins/actions/server/lib/axios_utils.test.ts index c5e23f6cd3db3..bee09a90ed27b 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.test.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import axios, { AxiosInstance } from 'axios'; +import axios, { AxiosError, AxiosInstance } from 'axios'; import { Agent as HttpsAgent } from 'https'; import HttpProxyAgent from 'http-proxy-agent'; import { HttpsProxyAgent } from 'https-proxy-agent'; @@ -21,6 +21,7 @@ import { import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '../actions_config.mock'; import { getCustomAgents } from './get_custom_agents'; +import { ConnectorUsageCollector } from '../usage/connector_usage_collector'; const TestUrl = 'https://elastic.co/foo/bar/baz'; @@ -79,6 +80,80 @@ describe('request', () => { }); }); + test('adds request body bytes from request header on a successful request when connectorUsageCollector is provided', async () => { + const contentLength = 12; + axiosMock.mockImplementation(() => ({ + status: 200, + headers: { 'content-type': 'application/json' }, + data: { incidentId: '123' }, + request: { + headers: { 'Content-Length': contentLength }, + getHeader: () => contentLength, + }, + })); + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + await request({ + axios, + url: '/test', + logger, + data: { test: 12345 }, + configurationUtilities, + connectorUsageCollector, + }); + + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); + }); + + test('adds request body bytes from request header on a failed', async () => { + const contentLength = 12; + axiosMock.mockImplementation( + () => + new AxiosError('failed', '500', undefined, { + headers: { 'Content-Length': contentLength }, + }) + ); + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + + try { + await request({ + axios, + url: '/test', + logger, + configurationUtilities, + connectorUsageCollector, + }); + } catch (e) { + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); + } + }); + + test('adds request body bytes from data when request header does not exist', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + const data = { test: 12345 }; + + await request({ + axios, + url: '/test', + logger, + data, + configurationUtilities, + connectorUsageCollector, + }); + + expect(connectorUsageCollector.getRequestBodyByte()).toBe( + Buffer.byteLength(JSON.stringify(data), 'utf8') + ); + }); + test('it have been called with proper proxy agent for a valid url', async () => { configurationUtilities.getProxySettings.mockReturnValue({ proxySSLSettings: { diff --git a/x-pack/plugins/actions/server/lib/axios_utils.ts b/x-pack/plugins/actions/server/lib/axios_utils.ts index 3852f2a33755b..254ad1a36f6e2 100644 --- a/x-pack/plugins/actions/server/lib/axios_utils.ts +++ b/x-pack/plugins/actions/server/lib/axios_utils.ts @@ -17,7 +17,7 @@ import { import { Logger } from '@kbn/core/server'; import { getCustomAgents } from './get_custom_agents'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { SSLSettings } from '../types'; +import { ConnectorUsageCollector, SSLSettings } from '../types'; import { combineHeadersWithBasicAuthHeader } from './get_basic_auth_header'; export const request = async ({ @@ -30,6 +30,7 @@ export const request = async ({ headers, sslOverrides, timeout, + connectorUsageCollector, ...config }: { axios: AxiosInstance; @@ -41,6 +42,7 @@ export const request = async ({ headers?: Record; timeout?: number; sslOverrides?: SSLSettings; + connectorUsageCollector?: ConnectorUsageCollector; } & AxiosRequestConfig): Promise => { if (!isEmpty(axios?.defaults?.baseURL ?? '')) { throw new Error( @@ -64,18 +66,31 @@ export const request = async ({ headers, }); - return await axios(url, { - ...restConfig, - method, - headers: headersWithBasicAuth, - ...(data ? { data } : {}), - // use httpAgent and httpsAgent and set axios proxy: false, to be able to handle fail on invalid certs - httpAgent, - httpsAgent, - proxy: false, - maxContentLength, - timeout: Math.max(settingsTimeout, timeout ?? 0), - }); + try { + const result = await axios(url, { + ...restConfig, + method, + headers: headersWithBasicAuth, + ...(data ? { data } : {}), + // use httpAgent and httpsAgent and set axios proxy: false, to be able to handle fail on invalid certs + httpAgent, + httpsAgent, + proxy: false, + maxContentLength, + timeout: Math.max(settingsTimeout, timeout ?? 0), + }); + + if (connectorUsageCollector) { + connectorUsageCollector.addRequestBodyBytes(result, data); + } + + return result; + } catch (error) { + if (connectorUsageCollector) { + connectorUsageCollector.addRequestBodyBytes(error, data); + } + throw error; + } }; export const patch = async ({ @@ -84,12 +99,14 @@ export const patch = async ({ data, logger, configurationUtilities, + connectorUsageCollector, }: { axios: AxiosInstance; url: string; data: T; logger: Logger; configurationUtilities: ActionsConfigurationUtilities; + connectorUsageCollector?: ConnectorUsageCollector; }): Promise => { return request({ axios, @@ -98,6 +115,7 @@ export const patch = async ({ method: 'patch', data, configurationUtilities, + connectorUsageCollector, }); }; diff --git a/x-pack/plugins/actions/server/lib/connector_token_client.test.ts b/x-pack/plugins/actions/server/lib/connector_token_client.test.ts index baedd2ff07beb..b2b8c7487b475 100644 --- a/x-pack/plugins/actions/server/lib/connector_token_client.test.ts +++ b/x-pack/plugins/actions/server/lib/connector_token_client.test.ts @@ -37,6 +37,7 @@ beforeAll(() => { beforeEach(() => { clock.reset(); jest.resetAllMocks(); + jest.restoreAllMocks(); connectorTokenClient = new ConnectorTokenClient({ unsecuredSavedObjectsClient, encryptedSavedObjectsClient, diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts index cb6390a4b3335..46f13ae1182ac 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.test.ts @@ -33,6 +33,7 @@ describe('createActionEventLogRecordObject', () => { spaceId: 'default', name: 'test name', actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ '@timestamp': '1970-01-01T00:00:00.000Z', @@ -64,6 +65,7 @@ describe('createActionEventLogRecordObject', () => { }, action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -92,6 +94,7 @@ describe('createActionEventLogRecordObject', () => { }, ], actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -118,6 +121,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -145,6 +149,7 @@ describe('createActionEventLogRecordObject', () => { }, ], actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -163,6 +168,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -192,6 +198,7 @@ describe('createActionEventLogRecordObject', () => { ], name: 'test name', actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -220,6 +227,7 @@ describe('createActionEventLogRecordObject', () => { }, action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -255,6 +263,7 @@ describe('createActionEventLogRecordObject', () => { }, ], actionExecutionId: '123abc', + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -289,6 +298,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', @@ -319,6 +329,7 @@ describe('createActionEventLogRecordObject', () => { ], actionExecutionId: '123abc', source: asHttpRequestExecutionSource(httpServerMock.createKibanaRequest()), + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -345,6 +356,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { source: 'http_request', @@ -376,6 +388,7 @@ describe('createActionEventLogRecordObject', () => { ], actionExecutionId: '123abc', source: asHttpRequestExecutionSource(httpServerMock.createKibanaRequest()), + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -402,6 +415,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { source: 'http_request', @@ -433,6 +447,7 @@ describe('createActionEventLogRecordObject', () => { ], actionExecutionId: '123abc', isInMemory: true, + actionTypeId: '.slack', }) ).toStrictEqual({ event: { @@ -460,6 +475,7 @@ describe('createActionEventLogRecordObject', () => { ], action: { name: 'test name', + type_id: '.slack', id: '1', execution: { uuid: '123abc', diff --git a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts index 4f8bf08966c59..c3b7a3b35f512 100644 --- a/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts +++ b/x-pack/plugins/actions/server/lib/create_action_event_log_record_object.ts @@ -37,6 +37,7 @@ interface CreateActionEventLogRecordParams { relatedSavedObjects?: RelatedSavedObjects; isInMemory?: boolean; source?: ActionExecutionSource; + actionTypeId: string; } export function createActionEventLogRecordObject(params: CreateActionEventLogRecordParams): Event { @@ -54,6 +55,7 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec isInMemory, actionId, source, + actionTypeId, } = params; const kibanaAlertRule = { @@ -89,6 +91,7 @@ export function createActionEventLogRecordObject(params: CreateActionEventLogRec action: { ...(name ? { name } : {}), id: actionId, + type_id: actionTypeId, execution: { uuid: actionExecutionId, }, diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts index 91e2df1972de8..aa32dd8853dba 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.test.ts @@ -12,12 +12,14 @@ import { actionsConfigMock } from '../actions_config.mock'; import { actionsMock } from '../mocks'; import { TestCaseConnector } from './mocks'; import { ActionsConfigurationUtilities } from '../actions_config'; +import { ConnectorUsageCollector } from '../usage'; describe('CaseConnector', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; let service: TestCaseConnector; + let connectorUsageCollector: ConnectorUsageCollector; const pushToServiceIncidentParamsSchema = { name: schema.string(), category: schema.nullable(schema.string()), @@ -57,6 +59,11 @@ describe('CaseConnector', () => { }, pushToServiceIncidentParamsSchema ); + + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('Sub actions', () => { @@ -191,7 +198,7 @@ describe('CaseConnector', () => { describe('pushToService', () => { it('should create an incident if externalId is null', async () => { - const res = await service.pushToService(pushToServiceParams); + const res = await service.pushToService(pushToServiceParams, connectorUsageCollector); expect(res).toEqual({ id: 'create-incident', title: 'Test incident', @@ -201,10 +208,13 @@ describe('CaseConnector', () => { }); it('should update an incident if externalId is not null', async () => { - const res = await service.pushToService({ - incident: { ...pushToServiceParams.incident, externalId: 'test-id' }, - comments: [], - }); + const res = await service.pushToService( + { + incident: { ...pushToServiceParams.incident, externalId: 'test-id' }, + comments: [], + }, + connectorUsageCollector + ); expect(res).toEqual({ id: 'update-incident', @@ -215,13 +225,16 @@ describe('CaseConnector', () => { }); it('should add comments', async () => { - const res = await service.pushToService({ - ...pushToServiceParams, - comments: [ - { comment: 'comment-1', commentId: 'comment-id-1' }, - { comment: 'comment-2', commentId: 'comment-id-2' }, - ], - }); + const res = await service.pushToService( + { + ...pushToServiceParams, + comments: [ + { comment: 'comment-1', commentId: 'comment-id-1' }, + { comment: 'comment-2', commentId: 'comment-id-2' }, + ], + }, + connectorUsageCollector + ); expect(res).toEqual({ id: 'create-incident', @@ -242,11 +255,14 @@ describe('CaseConnector', () => { }); it.each([[undefined], [null]])('should throw if externalId is %p', async (comments) => { - const res = await service.pushToService({ - ...pushToServiceParams, - // @ts-expect-error - comments, - }); + const res = await service.pushToService( + { + ...pushToServiceParams, + // @ts-expect-error + comments, + }, + connectorUsageCollector + ); expect(res).toEqual({ id: 'create-incident', @@ -257,10 +273,13 @@ describe('CaseConnector', () => { }); it('should not add comments if comments are an empty array', async () => { - const res = await service.pushToService({ - ...pushToServiceParams, - comments: [], - }); + const res = await service.pushToService( + { + ...pushToServiceParams, + comments: [], + }, + connectorUsageCollector + ); expect(res).toEqual({ id: 'create-incident', diff --git a/x-pack/plugins/actions/server/sub_action_framework/case.ts b/x-pack/plugins/actions/server/sub_action_framework/case.ts index 24a0512378912..1d942b210dbf9 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/case.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/case.ts @@ -9,22 +9,38 @@ import { schema, Type } from '@kbn/config-schema'; import { ExternalServiceIncidentResponse, PushToServiceResponse } from './types'; import { SubActionConnector } from './sub_action_connector'; import { ServiceParams } from './types'; +import { ConnectorUsageCollector } from '../usage'; export interface CaseConnectorInterface { - addComment: ({ incidentId, comment }: { incidentId: string; comment: string }) => Promise; - createIncident: (incident: Incident) => Promise; - updateIncident: ({ - incidentId, - incident, - }: { - incidentId: string; - incident: Incident; - }) => Promise; - getIncident: ({ id }: { id: string }) => Promise; - pushToService: (params: { - incident: { externalId: string | null } & Incident; - comments: Array<{ commentId: string; comment: string }>; - }) => Promise; + addComment: ( + { incidentId, comment }: { incidentId: string; comment: string }, + connectorUsageCollector: ConnectorUsageCollector + ) => Promise; + createIncident: ( + incident: Incident, + connectorUsageCollector: ConnectorUsageCollector + ) => Promise; + updateIncident: ( + { + incidentId, + incident, + }: { + incidentId: string; + incident: Incident; + }, + connectorUsageCollector: ConnectorUsageCollector + ) => Promise; + getIncident: ( + { id }: { id: string }, + connectorUsageCollector: ConnectorUsageCollector + ) => Promise; + pushToService: ( + params: { + incident: { externalId: string | null } & Incident; + comments: Array<{ commentId: string; comment: string }>; + }, + connectorUsageCollector: ConnectorUsageCollector + ) => Promise; } export abstract class CaseConnector @@ -56,50 +72,71 @@ export abstract class CaseConnector; + public abstract addComment( + { + incidentId, + comment, + }: { + incidentId: string; + comment: string; + }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise; - public abstract createIncident(incident: Incident): Promise; - public abstract updateIncident({ - incidentId, - incident, - }: { - incidentId: string; - incident: Incident; - }): Promise; - public abstract getIncident({ id }: { id: string }): Promise; + public abstract createIncident( + incident: Incident, + connectorUsageCollector: ConnectorUsageCollector + ): Promise; + public abstract updateIncident( + { + incidentId, + incident, + }: { + incidentId: string; + incident: Incident; + }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise; + public abstract getIncident( + { id }: { id: string }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise; - public async pushToService(params: { - incident: { externalId: string | null } & Incident; - comments: Array<{ commentId: string; comment: string }>; - }) { + public async pushToService( + params: { + incident: { externalId: string | null } & Incident; + comments: Array<{ commentId: string; comment: string }>; + }, + connectorUsageCollector: ConnectorUsageCollector + ) { const { incident, comments } = params; const { externalId, ...rest } = incident; let res: PushToServiceResponse; if (externalId != null) { - res = await this.updateIncident({ - incidentId: externalId, - incident: rest as Incident, - }); + res = await this.updateIncident( + { + incidentId: externalId, + incident: rest as Incident, + }, + connectorUsageCollector + ); } else { - res = await this.createIncident(rest as Incident); + res = await this.createIncident(rest as Incident, connectorUsageCollector); } if (comments && Array.isArray(comments) && comments.length > 0) { res.comments = []; for (const currentComment of comments) { - await this.addComment({ - incidentId: res.id, - comment: currentComment.comment, - }); + await this.addComment( + { + incidentId: res.id, + comment: currentComment.comment, + }, + connectorUsageCollector + ); res.comments = [ ...(res.comments ?? []), diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts index 35b1fa43c6ce3..1b8bdf0adcaee 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.test.ts @@ -21,6 +21,7 @@ import { } from './mocks'; import { IService, ServiceParams } from './types'; import { getErrorSource, TaskErrorSource } from '@kbn/task-manager-plugin/server/task_running'; +import { ConnectorUsageCollector } from '../usage'; describe('Executor', () => { const actionId = 'test-action-id'; @@ -30,6 +31,7 @@ describe('Executor', () => { let logger: MockedLogger; let services: ReturnType; let mockedActionsConfig: jest.Mocked; + let connectorUsageCollector: ConnectorUsageCollector; const createExecutor = (Service: IService) => { const connector = { @@ -55,6 +57,10 @@ describe('Executor', () => { logger = loggingSystemMock.createLogger(); services = actionsMock.createServices(); mockedActionsConfig = actionsConfigMock.create(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); it('should execute correctly', async () => { @@ -68,6 +74,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }); expect(res).toEqual({ @@ -90,6 +97,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }); expect(res).toEqual({ @@ -112,6 +120,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }); expect(res).toEqual({ @@ -132,6 +141,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }); expect(res).toEqual({ @@ -153,6 +163,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }) ).rejects.toThrowError('You should register at least one subAction for your connector type'); }); @@ -169,6 +180,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }) ).rejects.toThrowError( 'Sub action "not-exist" is not registered. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -187,6 +199,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }); } catch (e) { expect(getErrorSource(e)).toBe(TaskErrorSource.USER); @@ -208,6 +221,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }) ).rejects.toThrowError( 'Method "not-exist" does not exists in service. Sub action: "testUrl". Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -226,6 +240,7 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }) ).rejects.toThrowError( 'Method "notAFunction" must be a function. Connector id: test-action-id. Connector name: Test. Connector type: .test' @@ -244,9 +259,50 @@ describe('Executor', () => { services, configurationUtilities: mockedActionsConfig, logger, + connectorUsageCollector, }) ).rejects.toThrowError( 'Request validation failed (Error: [id]: expected value of type [string] but got [undefined])' ); }); + + it('Passes connectorUsageCollector to the subAction method as a second param', async () => { + let echoSpy; + + const subActionParams = { id: 'test-id' }; + const connector = { + id: '.test', + name: 'Test', + minimumLicenseRequired: 'basic' as const, + supportedFeatureIds: ['alerting'], + schema: { + config: TestConfigSchema, + secrets: TestSecretsSchema, + }, + getService: (serviceParams: ServiceParams) => { + const service = new TestExecutor(serviceParams); + echoSpy = jest.spyOn(service, 'echo').mockResolvedValue(subActionParams); + return service; + }, + }; + + const executor = buildExecutor({ + configurationUtilities: mockedActionsConfig, + logger, + connector, + }); + + await executor({ + actionId, + params: { subAction: 'echo', subActionParams }, + config, + secrets, + services, + configurationUtilities: mockedActionsConfig, + logger, + connectorUsageCollector, + }); + + expect(echoSpy).toHaveBeenCalledWith(subActionParams, connectorUsageCollector); + }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/executor.ts b/x-pack/plugins/actions/server/sub_action_framework/executor.ts index d9f2f693c175d..a8fbcb6e05984 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/executor.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/executor.ts @@ -30,7 +30,15 @@ export const buildExecutor = < logger: Logger; configurationUtilities: ActionsConfigurationUtilities; }): ExecutorType => { - return async ({ actionId, params, config, secrets, services, request }) => { + return async ({ + actionId, + params, + config, + secrets, + services, + request, + connectorUsageCollector, + }) => { const subAction = params.subAction; const subActionParams = params.subActionParams; @@ -88,7 +96,7 @@ export const buildExecutor = < } } - const data = await func.call(service, subActionParams); + const data = await func.call(service, subActionParams, connectorUsageCollector); return { status: 'ok', data: data ?? {}, actionId }; }; }; diff --git a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts index f6c8e86dd5af3..28e4a2abc224e 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/mocks.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/mocks.ts @@ -8,6 +8,7 @@ import { schema, Type, TypeOf } from '@kbn/config-schema'; import { AxiosError } from 'axios'; +import { ConnectorUsageCollector } from '../usage'; import { SubActionConnector } from './sub_action_connector'; import { CaseConnector } from './case'; import { ExternalServiceIncidentResponse, ServiceParams } from './types'; @@ -57,36 +58,54 @@ export class TestSubActionConnector extends SubActionConnector | null }) { - const res = await this.request({ - url, - data, - headers: { 'X-Test-Header': 'test' }, - responseSchema: schema.object({ status: schema.string() }), - }); + public async testUrl( + { url, data = {} }: { url: string; data?: Record | null }, + connectorUsageCollector: ConnectorUsageCollector + ) { + const res = await this.request( + { + url, + data, + headers: { 'X-Test-Header': 'test' }, + responseSchema: schema.object({ status: schema.string() }), + }, + connectorUsageCollector + ); return res; } - public async testData({ data }: { data: Record }) { - const res = await this.request({ - url: 'https://example.com', - data: this.removeNullOrUndefinedFields(data), - headers: { 'X-Test-Header': 'test' }, - responseSchema: schema.object({ status: schema.string() }), - }); + public async testData( + { data }: { data: Record }, + connectorUsageCollector: ConnectorUsageCollector + ) { + const res = await this.request( + { + url: 'https://example.com', + data: this.removeNullOrUndefinedFields(data), + headers: { 'X-Test-Header': 'test' }, + responseSchema: schema.object({ status: schema.string() }), + }, + connectorUsageCollector + ); return res; } - public async testAuth({ headers }: { headers?: Record } = {}) { - const res = await this.request({ - url: 'https://example.com', - data: {}, - auth: { username: 'username', password: 'password' }, - headers: { 'X-Test-Header': 'test', ...headers }, - responseSchema: schema.object({ status: schema.string() }), - }); + public async testAuth( + { headers }: { headers?: Record } = {}, + connectorUsageCollector: ConnectorUsageCollector + ) { + const res = await this.request( + { + url: 'https://example.com', + data: {}, + auth: { username: 'username', password: 'password' }, + headers: { 'X-Test-Header': 'test', ...headers }, + responseSchema: schema.object({ status: schema.string() }), + }, + connectorUsageCollector + ); return res; } diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts index 1358684d86093..ed599c3f30f71 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.test.ts @@ -13,6 +13,7 @@ import { actionsMock } from '../mocks'; import { TestSubActionConnector } from './mocks'; import { ActionsConfigurationUtilities } from '../actions_config'; import * as utils from '../lib/axios_utils'; +import { ConnectorUsageCollector } from '../usage'; jest.mock('axios'); @@ -43,6 +44,7 @@ describe('SubActionConnector', () => { let services: ReturnType; let mockedActionsConfig: jest.Mocked; let service: TestSubActionConnector; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.resetAllMocks(); @@ -70,6 +72,11 @@ describe('SubActionConnector', () => { secrets: { username: 'elastic', password: 'changeme' }, services, }); + + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('Sub actions', () => { @@ -85,34 +92,37 @@ describe('SubActionConnector', () => { describe('URL validation', () => { it('removes double slashes correctly', async () => { - await service.testUrl({ url: 'https://example.com//api///test-endpoint' }); + await service.testUrl( + { url: 'https://example.com//api///test-endpoint' }, + connectorUsageCollector + ); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com/api/test-endpoint'); }); it('removes the ending slash correctly', async () => { - await service.testUrl({ url: 'https://example.com/' }); + await service.testUrl({ url: 'https://example.com/' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0].url).toBe('https://example.com'); }); it('throws an error if the url is invalid', async () => { expect.assertions(1); - await expect(async () => service.testUrl({ url: 'invalid-url' })).rejects.toThrow( - 'URL Error: Invalid URL: invalid-url' - ); + await expect(async () => + service.testUrl({ url: 'invalid-url' }, connectorUsageCollector) + ).rejects.toThrow('URL Error: Invalid URL: invalid-url'); }); it('throws an error if the url starts with backslashes', async () => { expect.assertions(1); - await expect(async () => service.testUrl({ url: '//example.com/foo' })).rejects.toThrow( - 'URL Error: Invalid URL: //example.com/foo' - ); + await expect(async () => + service.testUrl({ url: '//example.com/foo' }, connectorUsageCollector) + ).rejects.toThrow('URL Error: Invalid URL: //example.com/foo'); }); it('throws an error if the protocol is not supported', async () => { expect.assertions(1); - await expect(async () => service.testUrl({ url: 'ftp://example.com' })).rejects.toThrow( - 'URL Error: Invalid protocol' - ); + await expect(async () => + service.testUrl({ url: 'ftp://example.com' }, connectorUsageCollector) + ).rejects.toThrow('URL Error: Invalid protocol'); }); it('throws if the host is the URI is not allowed', async () => { @@ -122,15 +132,15 @@ describe('SubActionConnector', () => { throw new Error('URI is not allowed'); }); - await expect(async () => service.testUrl({ url: 'https://example.com' })).rejects.toThrow( - 'error configuring connector action: URI is not allowed' - ); + await expect(async () => + service.testUrl({ url: 'https://example.com' }, connectorUsageCollector) + ).rejects.toThrow('error configuring connector action: URI is not allowed'); }); }); describe('Data', () => { it('sets data to an empty object if the data are null', async () => { - await service.testUrl({ url: 'https://example.com', data: null }); + await service.testUrl({ url: 'https://example.com', data: null }, connectorUsageCollector); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -138,7 +148,10 @@ describe('SubActionConnector', () => { }); it('pass data to axios correctly if not null', async () => { - await service.testUrl({ url: 'https://example.com', data: { foo: 'foo' } }); + await service.testUrl( + { url: 'https://example.com', data: { foo: 'foo' } }, + connectorUsageCollector + ); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -146,7 +159,10 @@ describe('SubActionConnector', () => { }); it('removeNullOrUndefinedFields: removes null values and undefined values correctly', async () => { - await service.testData({ data: { foo: 'foo', bar: null, baz: undefined } }); + await service.testData( + { data: { foo: 'foo', bar: null, baz: undefined } }, + connectorUsageCollector + ); expect(requestMock).toHaveBeenCalledTimes(1); const { data } = requestMock.mock.calls[0][0]; @@ -167,7 +183,7 @@ describe('SubActionConnector', () => { describe('Fetching', () => { it('fetch correctly', async () => { - const res = await service.testUrl({ url: 'https://example.com' }); + const res = await service.testUrl({ url: 'https://example.com' }, connectorUsageCollector); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -181,6 +197,7 @@ describe('SubActionConnector', () => { 'X-Test-Header': 'test', }, url: 'https://example.com', + connectorUsageCollector, }); expect(logger.debug).toBeCalledWith( @@ -192,7 +209,9 @@ describe('SubActionConnector', () => { it('validates the response correctly', async () => { requestMock.mockReturnValue({ data: { invalidField: 'test' } }); - await expect(async () => service.testUrl({ url: 'https://example.com' })).rejects.toThrow( + await expect(async () => + service.testUrl({ url: 'https://example.com' }, connectorUsageCollector) + ).rejects.toThrow( 'Response validation failed (Error: [status]: expected value of type [string] but got [undefined])' ); }); @@ -202,9 +221,9 @@ describe('SubActionConnector', () => { throw createAxiosError(); }); - await expect(async () => service.testUrl({ url: 'https://example.com' })).rejects.toThrow( - 'Message: An error occurred. Code: 500' - ); + await expect(async () => + service.testUrl({ url: 'https://example.com' }, connectorUsageCollector) + ).rejects.toThrow('Message: An error occurred. Code: 500'); expect(logger.debug).toHaveBeenLastCalledWith( 'Request to external service failed. Connector Id: test-id. Connector type: .test. Method: get. URL: https://example.com' @@ -212,7 +231,7 @@ describe('SubActionConnector', () => { }); it('converts auth axios property to a basic auth header if provided', async () => { - await service.testAuth(); + await service.testAuth(undefined, connectorUsageCollector); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -227,11 +246,15 @@ describe('SubActionConnector', () => { Authorization: `Basic ${Buffer.from('username:password').toString('base64')}`, }, url: 'https://example.com', + connectorUsageCollector, }); }); it('does not override an authorization header if provided', async () => { - await service.testAuth({ headers: { Authorization: 'Bearer my_token' } }); + await service.testAuth( + { headers: { Authorization: 'Bearer my_token' } }, + connectorUsageCollector + ); expect(requestMock).toHaveBeenCalledTimes(1); expect(requestMock).toBeCalledWith({ @@ -246,6 +269,7 @@ describe('SubActionConnector', () => { Authorization: 'Bearer my_token', }, url: 'https://example.com', + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts index d5ad5391628bc..fe59feab4376b 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts @@ -24,6 +24,7 @@ import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { KibanaRequest } from '@kbn/core-http-server'; import { inspect } from 'util'; +import { ConnectorUsageCollector } from '../usage'; import { assertURL } from './helpers/validators'; import { ActionsConfigurationUtilities } from '../actions_config'; import { SubAction, SubActionRequestParams } from './types'; @@ -130,15 +131,18 @@ export abstract class SubActionConnector { protected abstract getResponseErrorMessage(error: AxiosError): string; - protected async request({ - url, - data, - method = 'get', - responseSchema, - headers, - timeout, - ...config - }: SubActionRequestParams): Promise> { + protected async request( + { + url, + data, + method = 'get', + responseSchema, + headers, + timeout, + ...config + }: SubActionRequestParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise> { try { this.assertURL(url); this.ensureUriAllowed(url); @@ -160,6 +164,7 @@ export abstract class SubActionConnector { configurationUtilities: this.configurationUtilities, headers: this.getHeaders(auth, headers as AxiosHeaders), timeout, + connectorUsageCollector, }); this.validateResponse(responseSchema, res.data); diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index aa6c7b26cf0ae..487e7630d40f9 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -39,11 +39,11 @@ export type ActionTypeSecrets = Record; export type ActionTypeParams = Record; export type ConnectorTokenClientContract = PublicMethodsOf; -import type { ActionExecutionSource } from './lib'; import { Connector, ConnectorWithExtraFindData } from './application/connector/types'; -export type { ActionExecutionSource } from './lib'; - +import type { ActionExecutionSource } from './lib'; export { ActionExecutionSourceType } from './lib'; +import { ConnectorUsageCollector } from './usage'; +export { ConnectorUsageCollector } from './usage'; export interface Services { savedObjectsClient: SavedObjectsClientContract; @@ -88,6 +88,7 @@ export interface ActionTypeExecutorOptions< configurationUtilities: ActionsConfigurationUtilities; source?: ActionExecutionSource; request?: KibanaRequest; + connectorUsageCollector: ConnectorUsageCollector; } export type ActionResult = Connector; diff --git a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts index 8331f6890486c..066c477947e2c 100644 --- a/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts +++ b/x-pack/plugins/actions/server/unsecured_actions_client/unsecured_actions_client.ts @@ -12,11 +12,8 @@ import { ExecuteOptions, ExecutionResponse, } from '../create_unsecured_execute_function'; -import { - ActionExecutorContract, - asNotificationExecutionSource, - type RelatedSavedObjects, -} from '../lib'; +import { ActionExecutorContract, asNotificationExecutionSource } from '../lib'; +import type { RelatedSavedObjects } from '../lib'; import { ActionTypeExecutorResult, InMemoryConnector } from '../types'; import { asBackgroundTaskExecutionSource } from '../lib/action_execution_source'; import { ConnectorWithExtraFindData } from '../application/connector/types'; diff --git a/x-pack/plugins/actions/server/usage/connector_usage_collector.test.ts b/x-pack/plugins/actions/server/usage/connector_usage_collector.test.ts new file mode 100644 index 0000000000000..dcf071685f24f --- /dev/null +++ b/x-pack/plugins/actions/server/usage/connector_usage_collector.test.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ConnectorUsageCollector } from '../types'; +import { AxiosHeaders, AxiosResponse } from 'axios'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; + +describe('ConnectorUsageCollector', () => { + const logger = loggingSystemMock.createLogger(); + + test('it collects requestBodyBytes from response.request.headers', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + const data = { test: 'foo' }; + const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); + + const axiosResponse: AxiosResponse = { + data, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + request: { + headers: { 'Content-Length': contentLength }, + getHeader: () => contentLength, + }, + }; + + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); + + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); + + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); + + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength + contentLength); + }); + test('it collects requestBodyBytes from data when header is is missing', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + const data = { test: 'foo' }; + const contentLength = Buffer.byteLength(JSON.stringify(data), 'utf8'); + + const axiosResponse: AxiosResponse = { + data, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + request: { + getHeader: () => undefined, + }, + }; + + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); + + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength); + + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); + + expect(connectorUsageCollector.getRequestBodyByte()).toBe(contentLength + contentLength); + }); + + test('it logs an error when the body cannot be stringified ', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + + const data = { + name: 'arun', + }; + + // @ts-ignore + data.foo = data; // this is to force JSON.stringify to throw + + const axiosResponse: AxiosResponse = { + data, + status: 200, + statusText: 'OK', + headers: {}, + config: { headers: new AxiosHeaders() }, + request: { + getHeader: () => undefined, + }, + }; + + connectorUsageCollector.addRequestBodyBytes(axiosResponse, data); + + expect(logger.error).toHaveBeenCalledTimes(1); + expect(logger.error).toHaveBeenCalledWith( + expect.stringContaining("Request body bytes couldn't be calculated, Error: ") + ); + }); +}); diff --git a/x-pack/plugins/actions/server/usage/connector_usage_collector.ts b/x-pack/plugins/actions/server/usage/connector_usage_collector.ts new file mode 100644 index 0000000000000..542be0ebf7c70 --- /dev/null +++ b/x-pack/plugins/actions/server/usage/connector_usage_collector.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AxiosError, AxiosResponse } from 'axios'; +import { Logger } from '@kbn/core/server'; +import { isUndefined } from 'lodash'; + +interface ConnectorUsage { + requestBodyBytes: number; +} + +export class ConnectorUsageCollector { + private connectorId: string; + private usage: ConnectorUsage = { + requestBodyBytes: 0, + }; + + private logger: Logger; + + constructor({ logger, connectorId }: { logger: Logger; connectorId: string }) { + this.logger = logger; + this.connectorId = connectorId; + } + + public addRequestBodyBytes(result?: AxiosError | AxiosResponse, body: string | object = '') { + const contentLength = result?.request?.getHeader('content-length'); + let bytes = 0; + + if (!isUndefined(contentLength)) { + bytes = parseInt(contentLength, 10); + } else { + try { + const sBody = typeof body === 'string' ? body : JSON.stringify(body); + bytes = Buffer.byteLength(sBody, 'utf8'); + } catch (e) { + this.logger.error( + `Request body bytes couldn't be calculated, Error: ${e.message}, connectorId:${this.connectorId}` + ); + } + } + + this.usage.requestBodyBytes = this.usage.requestBodyBytes + bytes; + } + + public getRequestBodyByte() { + return this.usage.requestBodyBytes; + } +} diff --git a/x-pack/plugins/actions/server/usage/index.ts b/x-pack/plugins/actions/server/usage/index.ts index 722ad76014f07..d4faf364b7295 100644 --- a/x-pack/plugins/actions/server/usage/index.ts +++ b/x-pack/plugins/actions/server/usage/index.ts @@ -6,3 +6,4 @@ */ export { registerActionsUsageCollector } from './actions_usage_collector'; +export { ConnectorUsageCollector } from './connector_usage_collector'; diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts b/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts index e9e706331f360..4f0aa0fb003df 100644 --- a/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts +++ b/x-pack/plugins/alerting/server/alerts_client/lib/get_summarized_alerts_query.ts @@ -324,7 +324,6 @@ export const getQueryByScopedQueries = ({ aggs: { alertId: { top_hits: { - size: 1, _source: { includes: [ALERT_UUID], }, diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts index 08d183771b53c..ccc1bb9ea8427 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts @@ -12,7 +12,7 @@ import { IndicesDataStreamIndex, } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { errors as EsErrors } from '@elastic/elasticsearch'; -import { ReplaySubject, Subject } from 'rxjs'; +import { ReplaySubject, Subject, of } from 'rxjs'; import { AlertsService } from './alerts_service'; import { IRuleTypeAlerts, RecoveredActionGroup } from '../types'; import { retryUntil } from './test_utils'; @@ -219,6 +219,7 @@ const ruleTypeWithAlertDefinition: jest.Mocked = { describe('Alerts Service', () => { let pluginStop$: Subject; + const elasticsearchAndSOAvailability$ = of(true); beforeEach(() => { jest.resetAllMocks(); @@ -251,6 +252,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -275,6 +277,46 @@ describe('Alerts Service', () => { expect(componentTemplate3.name).toEqual('.alerts-ecs-mappings'); }); + test('should not initialize common resources if ES is not ready', async () => { + const test$ = new Subject(); + const alertsService = new AlertsService({ + logger, + elasticsearchClientPromise: Promise.resolve(clusterClient), + pluginStop$, + kibanaVersion: '8.8.0', + dataStreamAdapter, + elasticsearchAndSOAvailability$: test$, + }); + + await retryUntil( + 'alert service initialized', + async () => alertsService.isInitialized() === true + ); + expect(alertsService.isInitialized()).toEqual(false); + + // ES is ready, should initialize the resources + test$.next(true); + await retryUntil( + 'alert service initialized', + async () => alertsService.isInitialized() === true + ); + expect(alertsService.isInitialized()).toEqual(true); + expect(clusterClient.ilm.putLifecycle).toHaveBeenCalledTimes( + useDataStreamForAlerts ? 0 : 1 + ); + if (!useDataStreamForAlerts) { + expect(clusterClient.ilm.putLifecycle).toHaveBeenCalledWith(IlmPutBody); + } + expect(clusterClient.cluster.putComponentTemplate).toHaveBeenCalledTimes(3); + + const componentTemplate1 = clusterClient.cluster.putComponentTemplate.mock.calls[0][0]; + expect(componentTemplate1.name).toEqual('.alerts-framework-mappings'); + const componentTemplate2 = clusterClient.cluster.putComponentTemplate.mock.calls[1][0]; + expect(componentTemplate2.name).toEqual('.alerts-legacy-alert-mappings'); + const componentTemplate3 = clusterClient.cluster.putComponentTemplate.mock.calls[2][0]; + expect(componentTemplate3.name).toEqual('.alerts-ecs-mappings'); + }); + test('should log error and set initialized to false if adding ILM policy throws error', async () => { if (useDataStreamForAlerts) return; @@ -285,6 +327,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -306,6 +349,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -386,6 +430,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -427,6 +472,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -1447,6 +1493,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -1508,6 +1555,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -1546,6 +1594,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -1644,6 +1693,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -1765,6 +1815,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -1846,6 +1897,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -1944,6 +1996,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -2006,6 +2059,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -2072,6 +2126,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -2145,6 +2200,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); alertsService.register(TestRegistrationContext); @@ -2198,6 +2254,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -2218,6 +2275,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -2238,6 +2296,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -2266,6 +2325,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -2297,6 +2357,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -2333,6 +2394,7 @@ describe('Alerts Service', () => { pluginStop$, kibanaVersion: '8.8.0', dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil( @@ -2367,6 +2429,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', timeoutMs: 10, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil('error logger called', async () => logger.error.mock.calls.length > 0); @@ -2383,6 +2446,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', timeoutMs: 10, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await retryUntil('debug logger called', async () => logger.debug.mock.calls.length > 0); diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts index 10161b4e09635..f37481c9ccb86 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts @@ -7,7 +7,7 @@ import { isEmpty, isEqual, omit } from 'lodash'; import { Logger, ElasticsearchClient } from '@kbn/core/server'; -import { Observable } from 'rxjs'; +import { filter, firstValueFrom, Observable } from 'rxjs'; import { alertFieldMap, ecsFieldMap, legacyAlertFieldMap } from '@kbn/alerts-as-data-utils'; import { DEFAULT_NAMESPACE_STRING } from '@kbn/core-saved-objects-utils-server'; import { @@ -58,6 +58,7 @@ interface AlertsServiceParams { elasticsearchClientPromise: Promise; timeoutMs?: number; dataStreamAdapter: DataStreamAdapter; + elasticsearchAndSOAvailability$: Observable; } export interface CreateAlertsClientParams extends LegacyAlertsClientParams { @@ -131,7 +132,10 @@ export class AlertsService implements IAlertsService { this.dataStreamAdapter = options.dataStreamAdapter; // Kick off initialization of common assets and save the promise - this.commonInitPromise = this.initializeCommon(this.options.timeoutMs); + this.commonInitPromise = this.initializeCommon( + this.options.elasticsearchAndSOAvailability$, + this.options.timeoutMs + ); // Create helper for initializing context-specific resources this.resourceInitializationHelper = createResourceInstallationHelper( @@ -181,7 +185,10 @@ export class AlertsService implements IAlertsService { if (!this.initialized) { if (!this.isInitializing) { this.options.logger.info(`Retrying common resource initialization`); - initPromise = this.initializeCommon(this.options.timeoutMs); + initPromise = this.initializeCommon( + this.options.elasticsearchAndSOAvailability$, + this.options.timeoutMs + ); } else { this.options.logger.info( `Skipped retrying common resource initialization because it is already being retried.` @@ -295,8 +302,16 @@ export class AlertsService implements IAlertsService { * - ILM policy - common policy shared by all AAD indices * - Component template - common mappings for fields populated and used by the framework */ - private async initializeCommon(timeoutMs?: number): Promise { + private async initializeCommon( + elasticsearchAndSOAvailability$: Observable, + timeoutMs?: number + ): Promise { this.isInitializing = true; + // Wait to install resources until ES is ready + await firstValueFrom( + elasticsearchAndSOAvailability$.pipe(filter((areESAndSOAvailable) => areESAndSOAvailable)) + ); + try { this.options.logger.debug(`Initializing resources for AlertsService`); const esClient = await this.options.elasticsearchClientPromise; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index d310c6e3567c3..447dab2b94715 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -6,7 +6,14 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { BehaviorSubject, ReplaySubject, Subject } from 'rxjs'; +import { + BehaviorSubject, + ReplaySubject, + Subject, + Observable, + map, + distinctUntilChanged, +} from 'rxjs'; import { pick } from 'lodash'; import { UsageCollectionSetup, UsageCounter } from '@kbn/usage-collection-plugin/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; @@ -33,6 +40,7 @@ import { ServiceStatus, SavedObjectsBulkGetObject, ServiceStatusLevels, + CoreStatus, } from '@kbn/core/server'; import { LICENSE_TYPE, @@ -254,6 +262,8 @@ export class AlertingPlugin { this.licenseState = new LicenseState(plugins.licensing.license$); this.security = plugins.security; + const elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); + const useDataStreamForAlerts = !!plugins.serverless; this.dataStreamAdapter = getDataStreamAdapter({ useDataStreamForAlerts }); @@ -315,6 +325,7 @@ export class AlertingPlugin { elasticsearchClientPromise: core .getStartServices() .then(([{ elasticsearch }]) => elasticsearch.client.asInternalUser), + elasticsearchAndSOAvailability$, }); } } @@ -677,3 +688,16 @@ export class AlertingPlugin { this.pluginStop$.complete(); } } + +export function getElasticsearchAndSOAvailability( + core$: Observable +): Observable { + return core$.pipe( + map( + ({ elasticsearch, savedObjects }) => + elasticsearch.level === ServiceStatusLevels.available && + savedObjects.level === ServiceStatusLevels.available + ), + distinctUntilChanged() + ); +} diff --git a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts index 84181bb512a78..9b65f6613baaf 100644 --- a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts @@ -47,7 +47,7 @@ import { alertingEventLoggerMock } from '../lib/alerting_event_logger/alerting_e import { alertsMock } from '../mocks'; import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { AlertsService } from '../alerts_service'; -import { ReplaySubject } from 'rxjs'; +import { of, ReplaySubject } from 'rxjs'; import { getDataStreamAdapter } from '../alerts_service/lib/data_stream_adapter'; import { AlertInstanceContext, @@ -124,12 +124,14 @@ type TaskRunnerFactoryInitializerParamsType = jest.Mocked & { const clusterClient = elasticsearchServiceMock.createClusterClient().asInternalUser; const alertingEventLogger = alertingEventLoggerMock.create(); +const elasticsearchAndSOAvailability$ = of(true); const alertsService = new AlertsService({ logger, pluginStop$: new ReplaySubject(1), kibanaVersion: '8.8.0', elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), + elasticsearchAndSOAvailability$, }); const backfillClient = backfillClientMock.create(); const dataPlugin = dataPluginMock.createStartContract(); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index d5d071208e398..4739ec5a91d3b 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -220,6 +220,7 @@ describe('Task Runner', () => { beforeEach(() => { jest.resetAllMocks(); + jest.restoreAllMocks(); // clear spy mock implementations logger.isLevelEnabled.mockReturnValue(true); jest .requireMock('../lib/wrap_scoped_cluster_client') @@ -1969,7 +1970,7 @@ describe('Task Runner', () => { }); test('should set unexpected errors as framework-error', async () => { - (getExecutorServicesModule.getExecutorServices as jest.Mock).mockImplementation(() => { + jest.spyOn(getExecutorServicesModule, 'getExecutorServices').mockImplementation(() => { throw new Error('test'); }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts index 9f5ad725465e7..851bdddaed62a 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts @@ -65,7 +65,7 @@ import * as RuleRunMetricsStoreModule from '../lib/rule_run_metrics_store'; import { legacyAlertsClientMock } from '../alerts_client/legacy_alerts_client.mock'; import { ruleRunMetricsStoreMock } from '../lib/rule_run_metrics_store.mock'; import { AlertsService } from '../alerts_service'; -import { ReplaySubject } from 'rxjs'; +import { ReplaySubject, Subject } from 'rxjs'; import { IAlertsClient } from '../alerts_client/types'; import { getDataStreamAdapter } from '../alerts_service/lib/data_stream_adapter'; import { @@ -180,6 +180,7 @@ describe('Task Runner', () => { const ruleRunMetricsStore = ruleRunMetricsStoreMock.create(); const maintenanceWindowClient = maintenanceWindowClientMock.create(); const connectorAdapterRegistry = new ConnectorAdapterRegistry(); + const elasticsearchAndSOAvailability$ = new Subject(); type TaskRunnerFactoryInitializerParamsType = jest.Mocked & { actionsPlugin: jest.Mocked; @@ -387,7 +388,10 @@ describe('Task Runner', () => { kibanaVersion: '8.8.0', elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), + elasticsearchAndSOAvailability$, }); + elasticsearchAndSOAvailability$.next(true); + const spy = jest .spyOn(alertsService, 'getContextInitializationPromise') .mockResolvedValue({ result: true }); @@ -446,12 +450,12 @@ describe('Task Runner', () => { expect(logger.debug).toHaveBeenCalledTimes(useDataStreamForAlerts ? 9 : 10); let debugCall = 1; - expect(logger.debug).nthCalledWith(debugCall++, `Initializing resources for AlertsService`); expect(logger.debug).nthCalledWith( debugCall++, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { tags: ['1', 'test'] } ); + expect(logger.debug).nthCalledWith(debugCall++, `Initializing resources for AlertsService`); if (!useDataStreamForAlerts) { expect(logger.debug).nthCalledWith( @@ -516,7 +520,10 @@ describe('Task Runner', () => { kibanaVersion: '8.8.0', elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), + elasticsearchAndSOAvailability$, }); + elasticsearchAndSOAvailability$.next(true); + const spy = jest .spyOn(alertsService, 'getContextInitializationPromise') .mockResolvedValue({ result: true }); diff --git a/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx index 8251e0a1f18fa..d063c2fea3421 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx @@ -6,9 +6,7 @@ */ import React from 'react'; -import { screen, waitFor } from '@testing-library/react'; -import type { AppMockRenderer } from '../../common/mock'; -import { createAppMockRenderer } from '../../common/mock'; +import { screen, waitFor, render } from '@testing-library/react'; import { Severity } from './severity'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; @@ -16,28 +14,21 @@ import { FormTestComponent } from '../../common/test_utils'; const onSubmit = jest.fn(); -// FLAKY: https://github.com/elastic/kibana/issues/188951 -describe.skip('Severity form field', () => { - let appMockRender: AppMockRenderer; - - beforeEach(() => { - appMockRender = createAppMockRenderer(); - }); - +describe('Severity form field', () => { it('renders', async () => { - appMockRender.render( + render( ); expect(await screen.findByTestId('caseSeverity')).toBeInTheDocument(); - expect(await screen.findByTestId('case-severity-selection')).not.toHaveAttribute('disabled'); + expect(await screen.findByTestId('case-severity-selection')).toBeEnabled(); }); // default to LOW in this test configuration it('defaults to the correct value', async () => { - appMockRender.render( + render( @@ -48,7 +39,7 @@ describe.skip('Severity form field', () => { }); it('selects the correct value when changed', async () => { - appMockRender.render( + render( @@ -70,12 +61,12 @@ describe.skip('Severity form field', () => { }); it('disables when loading data', async () => { - appMockRender.render( + render( ); - expect(await screen.findByTestId('case-severity-selection')).toHaveAttribute('disabled'); + expect(await screen.findByTestId('case-severity-selection')).toBeDisabled(); }); }); diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index 720251dee5a77..b35780c438403 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { KSPM_POLICY_TEMPLATE, CSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { AwsCredentialsTypeFieldMap, GcpCredentialsTypeFieldMap, @@ -13,8 +14,6 @@ import { } from './types_old'; export const CLOUD_SECURITY_INTERTAL_PREFIX_ROUTE_PATH = '/internal/cloud_security_posture/'; -export const STATUS_ROUTE_PATH = '/internal/cloud_security_posture/status'; -export const STATUS_API_CURRENT_VERSION = '1'; export const STATS_ROUTE_PATH = '/internal/cloud_security_posture/stats/{policy_template}'; @@ -31,10 +30,6 @@ export const CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH = '/internal/cloud_security_posture/rules/_bulk_action'; export const CSP_BENCHMARK_RULES_BULK_ACTION_API_CURRENT_VERSION = '1'; -export const CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH = - '/internal/cloud_security_posture/rules/_get_states'; -export const CSP_GET_BENCHMARK_RULES_STATE_API_CURRENT_VERSION = '1'; - export const GET_DETECTION_RULE_ALERTS_STATUS_PATH = '/internal/cloud_security_posture/detection_engine_rules/alerts/_status'; export const DETECTION_RULE_ALERTS_STATUS_API_CURRENT_VERSION = '1'; @@ -45,11 +40,6 @@ export const CLOUD_SECURITY_POSTURE_PACKAGE_NAME = 'cloud_security_posture'; export const CDR_MISCONFIGURATIONS_DATA_VIEW_NAME = 'Latest Cloud Security Misconfigurations'; export const CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX = 'security_solution_cdr_latest_misconfigurations'; -export const CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN = - 'logs-cloud_security_posture.findings_latest-default'; -export const CDR_LATEST_THIRD_PARTY_MISCONFIGURATIONS_INDEX_PATTERN = - 'logs-*_latest_misconfigurations_cdr'; -export const CDR_MISCONFIGURATIONS_INDEX_PATTERN = `${CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN},${CDR_LATEST_THIRD_PARTY_MISCONFIGURATIONS_INDEX_PATTERN}`; export const CDR_VULNERABILITIES_DATA_VIEW_NAME = 'Latest Cloud Security Vulnerabilities'; export const CDR_VULNERABILITIES_DATA_VIEW_ID_PREFIX = @@ -65,8 +55,6 @@ export const LATEST_FINDINGS_INDEX_TEMPLATE_NAME = 'logs-cloud_security_posture. export const LATEST_FINDINGS_INDEX_DEFAULT_NS = 'logs-cloud_security_posture.findings_latest-default'; -export const LATEST_FINDINGS_RETENTION_POLICY = '26h'; - export const BENCHMARK_SCORE_INDEX_TEMPLATE_NAME = 'logs-cloud_security_posture.scores'; export const BENCHMARK_SCORE_INDEX_PATTERN = 'logs-cloud_security_posture.scores-*'; export const BENCHMARK_SCORE_INDEX_DEFAULT_NS = 'logs-cloud_security_posture.scores-default'; @@ -127,8 +115,6 @@ export const CIS_GCP = 'cis_gcp'; export const CIS_K8S = 'cis_k8s'; export const CIS_EKS = 'cis_eks'; export const CIS_AZURE = 'cis_azure'; -export const KSPM_POLICY_TEMPLATE = 'kspm'; -export const CSPM_POLICY_TEMPLATE = 'cspm'; export const VULN_MGMT_POLICY_TEMPLATE = 'vuln_mgmt'; export const CNVM_POLICY_TEMPLATE = 'cnvm'; export const SUPPORTED_POLICY_TEMPLATES = [ diff --git a/x-pack/plugins/cloud_security_posture/common/schemas/stats.ts b/x-pack/plugins/cloud_security_posture/common/schemas/stats.ts index e8b3657996e0f..3b2fa14c06b30 100644 --- a/x-pack/plugins/cloud_security_posture/common/schemas/stats.ts +++ b/x-pack/plugins/cloud_security_posture/common/schemas/stats.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../constants'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; // this pages follows versioning interface strategy https://docs.elastic.dev/kibana-dev-docs/versioning-interfaces diff --git a/x-pack/plugins/cloud_security_posture/common/types/index.ts b/x-pack/plugins/cloud_security_posture/common/types/index.ts index 04fa2a95a8d5e..c59071d114251 100644 --- a/x-pack/plugins/cloud_security_posture/common/types/index.ts +++ b/x-pack/plugins/cloud_security_posture/common/types/index.ts @@ -16,8 +16,6 @@ export * as benchmarkV2 from './benchmarks/v2'; // Explicit export of everything from latest export type { - cspBenchmarkRuleMetadataSchema, - CspBenchmarkRuleMetadata, CspBenchmarkRule, FindCspBenchmarkRuleRequest, FindCspBenchmarkRuleResponse, diff --git a/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts b/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts index a00bf1a8077e6..7c0a536de79a5 100644 --- a/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts +++ b/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts @@ -6,7 +6,8 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; -import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../constants'; + +import { cspBenchmarkRuleMetadataSchema } from '@kbn/cloud-security-posture-common/schema'; export const DEFAULT_BENCHMARK_RULES_PER_PAGE = 25; @@ -14,36 +15,8 @@ export const DEFAULT_BENCHMARK_RULES_PER_PAGE = 25; export type FindCspBenchmarkRuleRequest = TypeOf; -export type CspBenchmarkRuleMetadata = TypeOf; - export type CspBenchmarkRule = TypeOf; -export const cspBenchmarkRuleMetadataSchema = schema.object({ - audit: schema.string(), - benchmark: schema.object({ - name: schema.string(), - posture_type: schema.maybe( - schema.oneOf([schema.literal(CSPM_POLICY_TEMPLATE), schema.literal(KSPM_POLICY_TEMPLATE)]) - ), - id: schema.string(), - version: schema.string(), - rule_number: schema.maybe(schema.string()), - }), - default_value: schema.maybe(schema.string()), - description: schema.string(), - id: schema.string(), - impact: schema.maybe(schema.string()), - name: schema.string(), - profile_applicability: schema.string(), - rationale: schema.string(), - references: schema.maybe(schema.string()), - rego_rule_id: schema.string(), - remediation: schema.string(), - section: schema.string(), - tags: schema.arrayOf(schema.string()), - version: schema.string(), -}); - export const cspBenchmarkRuleSchema = schema.object({ metadata: cspBenchmarkRuleMetadataSchema, }); diff --git a/x-pack/plugins/cloud_security_posture/common/types/rules/v4.ts b/x-pack/plugins/cloud_security_posture/common/types/rules/v4.ts index 33134eed32e38..231fb4c65a9bb 100644 --- a/x-pack/plugins/cloud_security_posture/common/types/rules/v4.ts +++ b/x-pack/plugins/cloud_security_posture/common/types/rules/v4.ts @@ -6,15 +6,11 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; +import { ruleStateAttributes, rulesStates } from '@kbn/cloud-security-posture-common/schema'; import { BenchmarksCisId } from '../latest'; import { DEFAULT_BENCHMARK_RULES_PER_PAGE } from './v3'; -export type { - cspBenchmarkRuleMetadataSchema, - CspBenchmarkRuleMetadata, - cspBenchmarkRuleSchema, - CspBenchmarkRule, - FindCspBenchmarkRuleResponse, -} from './v3'; +export type { cspBenchmarkRuleSchema, CspBenchmarkRule, FindCspBenchmarkRuleResponse } from './v3'; export type FindCspBenchmarkRuleRequest = TypeOf; @@ -26,8 +22,6 @@ export type CspBenchmarkRulesBulkActionRequestSchema = TypeOf< export type RuleStateAttributes = TypeOf; -export type CspBenchmarkRulesStates = TypeOf; - export type CspSettings = TypeOf; export const findCspBenchmarkRuleRequestSchema = schema.object({ @@ -143,16 +137,6 @@ export interface CspBenchmarkRulesBulkActionResponse { message: string; } -const ruleStateAttributes = schema.object({ - muted: schema.boolean(), - benchmark_id: schema.string(), - benchmark_version: schema.string(), - rule_number: schema.string(), - rule_id: schema.string(), -}); - -const rulesStates = schema.recordOf(schema.string(), ruleStateAttributes); - export const cspSettingsSchema = schema.object({ rules: rulesStates, }); diff --git a/x-pack/plugins/cloud_security_posture/common/types/rules/v5.ts b/x-pack/plugins/cloud_security_posture/common/types/rules/v5.ts index 6f30ed446531a..1d70528d457ea 100644 --- a/x-pack/plugins/cloud_security_posture/common/types/rules/v5.ts +++ b/x-pack/plugins/cloud_security_posture/common/types/rules/v5.ts @@ -7,20 +7,13 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { DEFAULT_BENCHMARK_RULES_PER_PAGE } from './v3'; -export type { - cspBenchmarkRuleMetadataSchema, - CspBenchmarkRuleMetadata, - cspBenchmarkRuleSchema, - CspBenchmarkRule, - FindCspBenchmarkRuleResponse, -} from './v3'; +export type { cspBenchmarkRuleSchema, CspBenchmarkRule, FindCspBenchmarkRuleResponse } from './v3'; export type { PageUrlParams, rulesToUpdate, CspBenchmarkRulesBulkActionRequestSchema, CspBenchmarkRulesBulkActionResponse, RuleStateAttributes, - CspBenchmarkRulesStates, cspSettingsSchema, CspSettings, BulkActionBenchmarkRulesResponse, diff --git a/x-pack/plugins/cloud_security_posture/common/types_old.ts b/x-pack/plugins/cloud_security_posture/common/types_old.ts index 19e18902b7ea1..b5e399e4e639c 100644 --- a/x-pack/plugins/cloud_security_posture/common/types_old.ts +++ b/x-pack/plugins/cloud_security_posture/common/types_old.ts @@ -5,11 +5,11 @@ * 2.0. */ import { type TypeOf } from '@kbn/config-schema'; -import { CspFinding } from './schemas/csp_finding'; +import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { SUPPORTED_CLOUDBEAT_INPUTS, SUPPORTED_POLICY_TEMPLATES } from './constants'; import { getComplianceDashboardSchema } from './schemas/stats'; -import type { CspBenchmarkRuleMetadata } from './types/latest'; export type AwsCredentialsType = | 'assume_role' @@ -100,44 +100,6 @@ export interface ComplianceDashboardDataV2 { benchmarks: BenchmarkData[]; } -export type CspStatusCode = - | 'indexed' // latest findings index exists and has results - | 'indexing' // index timeout was not surpassed since installation, assumes data is being indexed - | 'unprivileged' // user lacks privileges for the latest findings index - | 'index-timeout' // index timeout was surpassed since installation - | 'not-deployed' // no healthy agents were deployed - | 'not-installed' // number of installed csp integrations is 0; - | 'waiting_for_results'; // have healthy agents but no findings at all, assumes data is being indexed for the 1st time - -export type IndexStatus = - | 'not-empty' // Index contains documents - | 'empty' // Index doesn't contain documents (or doesn't exist) - | 'unprivileged'; // User doesn't have access to query the index - -export interface IndexDetails { - index: string; - status: IndexStatus; -} - -export interface BaseCspSetupBothPolicy { - status: CspStatusCode; - installedPackagePolicies: number; - healthyAgents: number; -} - -export interface BaseCspSetupStatus { - indicesDetails: IndexDetails[]; - latestPackageVersion: string; - cspm: BaseCspSetupBothPolicy; - kspm: BaseCspSetupBothPolicy; - vuln_mgmt: BaseCspSetupBothPolicy; - isPluginInitialized: boolean; - installedPackageVersion?: string | undefined; - hasMisconfigurationsFindings?: boolean; -} - -export type CspSetupStatus = BaseCspSetupStatus; - export type BenchmarkId = CspBenchmarkRuleMetadata['benchmark']['id']; export type BenchmarkName = CspBenchmarkRuleMetadata['benchmark']['name']; export type RuleSection = CspBenchmarkRuleMetadata['section']; diff --git a/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.test.ts b/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.test.ts index a067ef4e1871a..fa514fe0fc2a5 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.test.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CspBenchmarkRuleMetadata } from '../types'; +import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common'; import { convertRuleTagsToMatchAllKQL, convertRuleTagsToMatchAnyKQL, diff --git a/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.ts b/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.ts index 61567211c8d22..4ae8385290955 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/detection_rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CspBenchmarkRuleMetadata } from '../types/latest'; +import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common'; const CSP_RULE_TAG = 'Cloud Security'; const CSP_RULE_TAG_USE_CASE = 'Use Case: Configuration Audit'; diff --git a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts index 6222b457e7ad6..950803c2c65c9 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/helpers.ts @@ -6,6 +6,7 @@ */ import { Truthy } from 'lodash'; +import type { BaseCspSetupStatus } from '@kbn/cloud-security-posture-common'; import { NewPackagePolicy, NewPackagePolicyInput, @@ -25,7 +26,6 @@ import { import type { BenchmarkId, Score, - BaseCspSetupStatus, AwsCredentialsType, GcpCredentialsType, AzureCredentialsType, diff --git a/x-pack/plugins/cloud_security_posture/common/utils/rules_states.ts b/x-pack/plugins/cloud_security_posture/common/utils/rules_states.ts index a343c91af91f9..9a142729e410b 100644 --- a/x-pack/plugins/cloud_security_posture/common/utils/rules_states.ts +++ b/x-pack/plugins/cloud_security_posture/common/utils/rules_states.ts @@ -5,7 +5,7 @@ * 2.0. */ import { QueryDslQueryContainer } from '@kbn/data-views-plugin/common/types'; -import { CspBenchmarkRulesStates } from '../types/latest'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; export const buildMutedRulesFilter = ( rulesStates: CspBenchmarkRulesStates 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 index 41b40da90a6d4..304230498d4f4 100644 --- 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 @@ -8,7 +8,7 @@ import { useQuery } from '@tanstack/react-query'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; -import { CspClientPluginStartDeps } from '../../types'; +import { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; /** * Hook to retrieve a Data View by it's Index Pattern title diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_fetch_detection_rules_alerts_status.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_fetch_detection_rules_alerts_status.ts index ed4b2933dddd0..d95c692bee0c4 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_fetch_detection_rules_alerts_status.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_fetch_detection_rules_alerts_status.ts @@ -34,5 +34,7 @@ export const useFetchDetectionRulesAlertsStatus = (tags: string[]) => { version: DETECTION_RULE_ALERTS_STATUS_API_CURRENT_VERSION, query: { tags }, }), + // Disabling retry to prevent stuck on loading state when the request fails due to permissions + retry: false, }); }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/api/use_setup_status_api.ts b/x-pack/plugins/cloud_security_posture/public/common/api/use_setup_status_api.ts index 35f49282a475e..003f841772285 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/api/use_setup_status_api.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/api/use_setup_status_api.ts @@ -6,9 +6,9 @@ */ import { useQuery, type UseQueryOptions } from '@tanstack/react-query'; +import { STATUS_API_CURRENT_VERSION, STATUS_ROUTE_PATH } from '@kbn/cloud-security-posture-common'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { useKibana } from '../hooks/use_kibana'; -import { type CspSetupStatus } from '../../../common/types_old'; -import { STATUS_API_CURRENT_VERSION, STATUS_ROUTE_PATH } from '../../../common/constants'; const getCspSetupStatusQueryKey = 'csp_status_key'; 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 e973633210d9c..77497d16cd76c 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 @@ -6,13 +6,10 @@ */ import { useQuery, UseQueryOptions } from '@tanstack/react-query'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { useKibana } from '../hooks/use_kibana'; import { ComplianceDashboardDataV2, PosturePolicyTemplate } from '../../../common/types_old'; -import { - CSPM_POLICY_TEMPLATE, - KSPM_POLICY_TEMPLATE, - STATS_ROUTE_PATH, -} from '../../../common/constants'; +import { STATS_ROUTE_PATH } from '../../../common/constants'; // TODO: consolidate both hooks into one hook with a dynamic key export const CSPM_STATS_QUERY_KEY = ['csp_cspm_dashboard_stats']; diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index 8054917ba7462..8eb996dd15643 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import { euiThemeVars } from '@kbn/ui-theme'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import type { CloudSecurityPolicyTemplate, PostureInput } from '../../common/types_old'; import { CLOUDBEAT_EKS, @@ -15,8 +16,6 @@ import { CLOUDBEAT_GCP, CLOUDBEAT_AZURE, CLOUDBEAT_VULN_MGMT_AWS, - KSPM_POLICY_TEMPLATE, - CSPM_POLICY_TEMPLATE, VULN_MGMT_POLICY_TEMPLATE, CLOUDBEAT_VULN_MGMT_GCP, CLOUDBEAT_VULN_MGMT_AZURE, @@ -35,7 +34,6 @@ export const statusColors = { }; export const CSP_MOMENT_FORMAT = 'MMMM D, YYYY @ HH:mm:ss.SSS'; -export const MAX_FINDINGS_TO_LOAD = 500; export const DEFAULT_VISIBLE_ROWS_PER_PAGE = 25; export const LOCAL_STORAGE_DATA_TABLE_PAGE_SIZE_KEY = 'cloudPosture:dataTable:pageSize'; diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_benchmark_dynamic_values.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_benchmark_dynamic_values.ts index 5fe3f8f69050a..7f9a2b5fd35f6 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_benchmark_dynamic_values.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_benchmark_dynamic_values.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { useCspIntegrationLink } from '../navigation/use_csp_integration_link'; -import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../../common/constants'; import { BenchmarksCisId } from '../../../common/types/benchmarks/v2'; type BenchmarkDynamicNames = diff --git a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_kibana.ts b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_kibana.ts index 1c6f252080e11..a392e9213dffc 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/hooks/use_kibana.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/hooks/use_kibana.ts @@ -7,7 +7,7 @@ import type { CoreStart } from '@kbn/core/public'; import { useKibana as useKibanaBase } from '@kbn/kibana-react-plugin/public'; -import type { CspClientPluginStartDeps } from '../../types'; +import type { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; type CspKibanaContext = CoreStart & CspClientPluginStartDeps; diff --git a/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts index d01aac0c57577..055495b59dd11 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/navigation/constants.ts @@ -6,14 +6,8 @@ */ import { i18n } from '@kbn/i18n'; -import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../../common/constants'; -import { PosturePolicyTemplate } from '../../../common/types_old'; -import type { - CspBenchmarksPage, - CspIntegrationDocNavigationItem, - CspPage, - CspPageNavigationItem, -} from './types'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; +import type { CspBenchmarksPage, CspPage, CspPageNavigationItem } from './types'; const NAV_ITEMS_NAMES = { DASHBOARD: i18n.translate('xpack.csp.navigation.dashboardNavItemLabel', { @@ -116,10 +110,7 @@ export const findingsNavigation = { const ELASTIC_BASE_SHORT_URL = 'https://ela.st'; -export const cspIntegrationDocsNavigation: Record< - PosturePolicyTemplate, - CspIntegrationDocNavigationItem -> = { +export const cspIntegrationDocsNavigation = { kspm: { overviewPath: `${ELASTIC_BASE_SHORT_URL}/${KSPM_POLICY_TEMPLATE}`, getStartedPath: `${ELASTIC_BASE_SHORT_URL}/${KSPM_POLICY_TEMPLATE}-get-started`, @@ -127,5 +118,8 @@ export const cspIntegrationDocsNavigation: Record< cspm: { overviewPath: `${ELASTIC_BASE_SHORT_URL}/${CSPM_POLICY_TEMPLATE}`, getStartedPath: `${ELASTIC_BASE_SHORT_URL}/${CSPM_POLICY_TEMPLATE}-get-started`, + awsGetStartedPath: `https://www.elastic.co/guide/en/security/current/cspm-get-started.html`, + gcpGetStartedPath: `https://www.elastic.co/guide/en/security/current/cspm-get-started-gcp.html`, + azureGetStartedPath: `https://www.elastic.co/guide/en/security/current/cspm-get-started-azure.html`, }, }; diff --git a/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts b/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts index 8f4cbabc9f9ba..f436558e085d9 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/navigation/types.ts @@ -35,8 +35,3 @@ export type CloudSecurityPosturePageId = | 'cloud_security_posture-findings' | 'cloud_security_posture-benchmarks' | 'cloud_security_posture-benchmarks-rules'; - -export interface CspIntegrationDocNavigationItem { - overviewPath: string; - getStartedPath: string; -} diff --git a/x-pack/plugins/cloud_security_posture/public/common/types.ts b/x-pack/plugins/cloud_security_posture/public/common/types.ts index d0d491c256e0e..62e0abe677679 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/types.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { Criteria } from '@elastic/eui'; -import type { BoolQuery, Filter, Query, EsQueryConfig } from '@kbn/es-query'; +import type { Filter, Query, EsQueryConfig } from '@kbn/es-query'; export interface FindingsBaseURLQuery { query: Query; @@ -24,12 +24,6 @@ export interface FindingsBaseESQueryConfig { config: EsQueryConfig; } -export interface FindingsBaseEsQuery { - query?: { - bool: BoolQuery; - }; -} - export type Sort = NonNullable['sort']>; interface RuleSeverityMapping { diff --git a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx index 7b63673707056..1e81f883c69f3 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/cloud_security_data_table/cloud_security_data_table.tsx @@ -27,10 +27,10 @@ import { AddFieldFilterHandler } from '@kbn/unified-field-list'; import { generateFilters } from '@kbn/data-plugin/public'; import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { MAX_FINDINGS_TO_LOAD } from '@kbn/cloud-security-posture-common'; import { useKibana } from '../../common/hooks/use_kibana'; import { CloudPostureDataTableResult } from '../../common/hooks/use_cloud_posture_data_table'; import { EmptyState } from '../empty_state'; -import { MAX_FINDINGS_TO_LOAD } from '../../common/constants'; import { useStyles } from './use_styles'; import { AdditionalControls } from './additional_controls'; import { useDataViewContext } from '../../common/contexts/data_view_context'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx index 745540d5a4b0b..42c775fad3006 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/aws_credentials_form.tsx @@ -216,7 +216,7 @@ export const AwsCredentialsForm = ({ setupFormat, group, fields, - integrationLink, + elasticDocLink, hasCloudFormationTemplate, onSetupFormatChange, } = useAwsCredentialsForm({ @@ -237,7 +237,7 @@ export const AwsCredentialsForm = ({ defaultMessage="Utilize AWS CloudFormation (a built-in AWS tool) or a series of manual steps to set up and deploy CSPM for assessing your AWS environment's security posture. Refer to our {gettingStartedLink} guide for details." values={{ gettingStartedLink: ( - + {group.info} - + + - + ); }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts index 5c9603ee17cc5..0e562c17b552a 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/aws_credentials_form/hooks.ts @@ -87,7 +87,7 @@ export const useAwsCredentialsForm = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [setupFormat, input.type]); - const integrationLink = cspIntegrationDocsNavigation.cspm.getStartedPath; + const elasticDocLink = cspIntegrationDocsNavigation.cspm.awsGetStartedPath; useCloudFormationTemplate({ packageInfo, @@ -136,7 +136,7 @@ export const useAwsCredentialsForm = ({ setupFormat, group, fields, - integrationLink, + elasticDocLink, hasCloudFormationTemplate, onSetupFormatChange, }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx index 2b0aaec9bb8af..25f7be8c8f4ee 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form.tsx @@ -38,7 +38,7 @@ import { CIS_AZURE_SETUP_FORMAT_TEST_SUBJECTS } from '../../test_subjects'; import { AZURE_CREDENTIALS_TYPE_SELECTOR_TEST_SUBJ } from '../../test_subjects'; interface AzureSetupInfoContentProps { - integrationLink: string; + documentationLink: string; } export type SetupFormat = typeof AZURE_SETUP_FORMAT.ARM_TEMPLATE | typeof AZURE_SETUP_FORMAT.MANUAL; @@ -58,7 +58,7 @@ export const AZURE_CREDENTIALS_TYPE = { MANAGED_IDENTITY: 'managed_identity', } as const; -export const AzureSetupInfoContent = ({ integrationLink }: AzureSetupInfoContentProps) => { +export const AzureSetupInfoContent = ({ documentationLink }: AzureSetupInfoContentProps) => { return ( <> @@ -74,13 +74,13 @@ export const AzureSetupInfoContent = ({ integrationLink }: AzureSetupInfoContent + ), @@ -221,19 +221,19 @@ const AzureCredentialTypeSelector = ({ ); -const TemporaryManualSetup = ({ integrationLink }: { integrationLink: string }) => { +const TemporaryManualSetup = ({ documentationLink }: { documentationLink: string }) => { return ( <> + ), @@ -356,7 +356,7 @@ export const AzureCredentialsForm = ({ azureCredentialsType, setupFormat, onSetupFormatChange, - integrationLink, + documentationLink, hasArmTemplateUrl, } = useAzureCredentialsForm({ newPolicy, @@ -410,7 +410,7 @@ export const AzureCredentialsForm = ({ return ( <> - + )} {setupFormat === AZURE_SETUP_FORMAT.MANUAL && !isPackageVersionValidForManualFields && ( - + )} {setupFormat === AZURE_SETUP_FORMAT.MANUAL && isPackageVersionValidForManualFields && ( <> diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form_agentless.tsx index dbe816e326f31..d8a88e5754864 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form_agentless.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/azure_credentials_form/azure_credentials_form_agentless.tsx @@ -31,14 +31,14 @@ export const AzureCredentialsFormAgentless = ({ updatePolicy, packageInfo, }: AzureCredentialsFormProps) => { - const integrationLink = cspIntegrationDocsNavigation.cspm.getStartedPath; + const documentationLink = cspIntegrationDocsNavigation.cspm.azureGetStartedPath; const options = getAzureCredentialsFormOptions(); const group = options[AZURE_CREDENTIALS_TYPE.SERVICE_PRINCIPAL_WITH_CLIENT_SECRET]; const fields = getInputVarsFields(input, group.fields); return ( <> - + + + + ), + }} /> ) : ( + + + ), + }} /> )} @@ -510,7 +531,7 @@ export const GcpCredentialsForm = ({ )} - + ); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credentials_form_agentless.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credentials_form_agentless.tsx index 6712b332e20b0..9cced3c87729b 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credentials_form_agentless.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credentials_form_agentless.tsx @@ -252,7 +252,7 @@ export const GcpCredentialsFormAgentless = ({ packageInfo={packageInfo} /> - + ); diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index 76134c4d41df0..7590e998cd0c2 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -917,7 +917,7 @@ describe('', () => { expect(getByText('Getting Started')).toHaveAttribute( 'href', - 'https://ela.st/cspm-get-started' + 'https://www.elastic.co/guide/en/security/current/cspm-get-started.html' ); }); @@ -934,7 +934,7 @@ describe('', () => { expect(getByTestId('externalLink')).toHaveAttribute( 'href', - 'https://ela.st/cspm-get-started' + 'https://www.elastic.co/guide/en/security/current/cspm-get-started.html' ); }); @@ -1224,7 +1224,10 @@ describe('', () => { ); - expect(getByText('documentation')).toHaveAttribute('href', 'https://ela.st/cspm-get-started'); + expect(getByText('documentation')).toHaveAttribute( + 'href', + 'https://www.elastic.co/guide/en/security/current/cspm-get-started-gcp.html' + ); }); it(`renders Google Cloud Shell forms when Setup Access is set to Google Cloud Shell`, () => { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index f70fb3a18f690..f57b5d453d81f 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -28,6 +28,7 @@ import type { PackagePolicyReplaceDefineStepExtensionComponentProps, } from '@kbn/fleet-plugin/public/types'; import { PackageInfo, PackagePolicy } from '@kbn/fleet-plugin/common'; +import { CSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import { useIsSubscriptionStatusValid } from '../../common/hooks/use_is_subscription_status_valid'; @@ -39,7 +40,6 @@ import { CLOUDBEAT_AWS, CLOUDBEAT_VANILLA, CLOUDBEAT_VULN_MGMT_AWS, - CSPM_POLICY_TEMPLATE, SUPPORTED_POLICY_TEMPLATES, } from '../../../common/constants'; import { diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx index ee76d40e1dcac..c0c489f935be0 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx @@ -10,12 +10,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { NewPackagePolicy, PackageInfo } from '@kbn/fleet-plugin/common'; import { SetupTechnology } from '@kbn/fleet-plugin/public'; import { PackagePolicyReplaceDefineStepExtensionComponentProps } from '@kbn/fleet-plugin/public/types'; -import { - CSPM_POLICY_TEMPLATE, - KSPM_POLICY_TEMPLATE, - VULN_MGMT_POLICY_TEMPLATE, - CNVM_POLICY_TEMPLATE, -} from '../../../common/constants'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; +import { VULN_MGMT_POLICY_TEMPLATE, CNVM_POLICY_TEMPLATE } from '../../../common/constants'; import type { PostureInput, CloudSecurityPolicyTemplate } from '../../../common/types_old'; import { getPolicyTemplateInputOptions, type NewPackagePolicyPostureInput } from './utils'; import { RadioGroup } from './csp_boxed_radio_group'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 656c70a0dcbfd..5fc4ab08e414c 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -13,6 +13,7 @@ import type { RegistryVarsEntry, } from '@kbn/fleet-plugin/common'; import { SetupTechnology } from '@kbn/fleet-plugin/public'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import merge from 'lodash/merge'; import semverValid from 'semver/functions/valid'; import semverCoerce from 'semver/functions/coerce'; @@ -24,8 +25,6 @@ import { CLOUDBEAT_GCP, CLOUDBEAT_VANILLA, CLOUDBEAT_VULN_MGMT_AWS, - CSPM_POLICY_TEMPLATE, - KSPM_POLICY_TEMPLATE, SUPPORTED_CLOUDBEAT_INPUTS, SUPPORTED_POLICY_TEMPLATES, VULN_MGMT_POLICY_TEMPLATE, diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx index 97dfce7b84c1e..096c6f0e8aae5 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/no_findings_states/no_findings_states.tsx @@ -20,7 +20,8 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; -import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '../../../common/constants'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; +import type { IndexDetails, CspStatusCode } from '@kbn/cloud-security-posture-common'; import { FullSizeCenteredPage } from '../full_size_centered_page'; import { useCISIntegrationPoliciesLink } from '../../common/navigation/use_navigate_to_cis_integration_policies'; import { @@ -30,7 +31,7 @@ import { } from '../test_subjects'; import { CloudPosturePage, PACKAGE_NOT_INSTALLED_TEST_SUBJECT } from '../cloud_posture_page'; import { useCspSetupStatusApi } from '../../common/api/use_setup_status_api'; -import type { IndexDetails, PostureTypes, CspStatusCode } from '../../../common/types_old'; +import type { PostureTypes } from '../../../common/types_old'; import noDataIllustration from '../../assets/illustrations/no_data_illustration.svg'; import { useCspIntegrationLink } from '../../common/navigation/use_csp_integration_link'; import { NO_FINDINGS_STATUS_REFRESH_INTERVAL_MS } from '../../common/constants'; diff --git a/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx b/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx index a2b1aa1d0d831..a15cf0aacd6fa 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/no_vulnerabilities_states.tsx @@ -21,11 +21,11 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; +import type { IndexDetails } from '@kbn/cloud-security-posture-common'; import { VULN_MGMT_POLICY_TEMPLATE } from '../../common/constants'; import { FullSizeCenteredPage } from './full_size_centered_page'; import { CloudPosturePage } from './cloud_posture_page'; import { useCspSetupStatusApi } from '../common/api/use_setup_status_api'; -import type { IndexDetails } from '../../common/types_old'; import { NO_VULNERABILITIES_STATUS_TEST_SUBJ, CNVM_NOT_INSTALLED_ACTION_SUBJ, diff --git a/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx b/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx index 87d6d109b7db0..5db9482c8b41a 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/take_action.tsx @@ -21,7 +21,7 @@ import { toMountPoint } from '@kbn/react-kibana-mount'; import type { HttpSetup } from '@kbn/core/public'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n as kbnI18n } from '@kbn/i18n'; -import { QueryClient, useQueryClient } from '@tanstack/react-query'; +import { QueryClient, useMutation, useQueryClient } from '@tanstack/react-query'; import type { RuleResponse } from '../common/types'; import { CREATE_RULE_ACTION_SUBJ, TAKE_ACTION_SUBJ } from './test_subjects'; import { useKibana } from '../common/hooks/use_kibana'; @@ -38,6 +38,22 @@ interface TakeActionProps { isDataGridControlColumn?: boolean; } +export const showCreateDetectionRuleErrorToast = ( + cloudSecurityStartServices: CloudSecurityPostureStartServices, + error: Error +) => { + return cloudSecurityStartServices.notifications.toasts.addDanger({ + title: kbnI18n.translate('xpack.csp.takeAction.createRuleErrorTitle', { + defaultMessage: 'Unable to create detection rule', + }), + text: kbnI18n.translate('xpack.csp.takeAction.createRuleErrorDescription', { + defaultMessage: 'An error occurred while creating the detection rule: {errorMessage}.', + values: { errorMessage: error.message }, + }), + 'data-test-subj': 'csp:toast-error', + }); +}; + export const showCreateDetectionRuleSuccessToast = ( cloudSecurityStartServices: CloudSecurityPostureStartServices, http: HttpSetup, @@ -92,78 +108,6 @@ export const showCreateDetectionRuleSuccessToast = ( }); }; -export const showChangeBenchmarkRuleStatesSuccessToast = ( - cloudSecurityStartServices: CloudSecurityPostureStartServices, - isBenchmarkRuleMuted: boolean, - data: { - numberOfRules: number; - numberOfDetectionRules: number; - } -) => { - const { notifications, analytics, i18n, theme } = cloudSecurityStartServices; - const startServices = { analytics, i18n, theme }; - - return notifications.toasts.addSuccess({ - toastLifeTimeMs: 10000, - color: 'success', - iconType: '', - 'data-test-subj': 'csp:toast-success-rule-state-change', - title: toMountPoint( - - - {isBenchmarkRuleMuted ? ( - - ) : ( - - )} - - , - startServices - ), - text: toMountPoint( -

- {isBenchmarkRuleMuted ? ( - - ) : ( - <> - - {!isBenchmarkRuleMuted && data.numberOfDetectionRules > 0 && ( - - - - )} - - )} -
, - startServices - ), - }); -}; - /* * This component is used to create a detection rule from Flyout. * It accepts a createRuleFn parameter which is used to create a rule in a generic way. @@ -269,20 +213,33 @@ const CreateDetectionRule = ({ }) => { const { http, ...startServices } = useKibana().services; + const { mutate } = useMutation({ + mutationFn: () => { + return createRuleFn(http); + }, + onMutate: () => { + setIsLoading(true); + closePopover(); + }, + onSuccess: (ruleResponse) => { + showCreateDetectionRuleSuccessToast(startServices, http, ruleResponse); + // Triggering a refetch of rules and alerts to update the UI + queryClient.invalidateQueries([DETECTION_ENGINE_RULES_KEY]); + queryClient.invalidateQueries([DETECTION_ENGINE_ALERTS_KEY]); + }, + onError: (error: Error) => { + showCreateDetectionRuleErrorToast(startServices, error); + }, + onSettled: () => { + setIsLoading(false); + }, + }); + return ( { - closePopover(); - setIsLoading(true); - const ruleResponse = await createRuleFn(http); - setIsLoading(false); - showCreateDetectionRuleSuccessToast(startServices, http, ruleResponse); - // Triggering a refetch of rules and alerts to update the UI - queryClient.invalidateQueries([DETECTION_ENGINE_RULES_KEY]); - queryClient.invalidateQueries([DETECTION_ENGINE_ALERTS_KEY]); - }} + onClick={() => mutate()} data-test-subj={CREATE_RULE_ACTION_SUBJ} > ', () => { const renderCloudSummarySection = (alterMockData = {}) => { 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 64d0a225f20d4..1528239562826 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 @@ -15,6 +15,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { css } from '@emotion/react'; +import { CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { useCspIntegrationLink } from '../../../common/navigation/use_csp_integration_link'; import { DASHBOARD_COUNTER_CARDS, DASHBOARD_SUMMARY_CONTAINER } from '../test_subjects'; import { CspCounterCard, CspCounterCardProps } from '../../../components/csp_counter_card'; @@ -28,12 +29,7 @@ import type { } from '../../../../common/types_old'; import { RisksTable } from '../compliance_charts/risks_table'; import { NavFilter, useNavigateFindings } from '../../../common/hooks/use_navigate_findings'; -import { - CSPM_POLICY_TEMPLATE, - KSPM_POLICY_TEMPLATE, - RULE_FAILED, - RULE_PASSED, -} from '../../../../common/constants'; +import { RULE_FAILED, RULE_PASSED } from '../../../../common/constants'; import { AccountsEvaluatedWidget } from '../../../components/accounts_evaluated_widget'; import { FINDINGS_GROUPING_OPTIONS } from '../../../common/constants'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts index 4b01603b4c03b..4693459c0985d 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/__mocks__/findings.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { CspFinding } from '../../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; export const mockFindingsHit: CspFinding = { result: { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts index e79f737b11a3c..10e79145cd02e 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/configurations.handlers.mock.ts @@ -6,7 +6,7 @@ */ import { estypes } from '@elastic/elasticsearch'; -import { CspFinding } from '../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { isArray } from 'lodash'; import { http, HttpResponse } from 'msw'; import { v4 as uuidV4 } from 'uuid'; 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 8b1d54b5a1798..f782d90474a3c 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 @@ -17,7 +17,7 @@ import { MemoryRouter } from '@kbn/shared-ux-router'; import { findingsNavigation } from '../../common/navigation/constants'; import userEvent from '@testing-library/user-event'; import { FilterManager } from '@kbn/data-plugin/public'; -import { CspClientPluginStartDeps } from '../../types'; +import { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import * as statusHandlers from '../../../server/routes/status/status.handlers.mock'; import { bsearchFindingsHandler, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_detection_rule_counter.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_detection_rule_counter.tsx index 0ab35a37c8ee4..7a3ef68a21ad9 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_detection_rule_counter.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_detection_rule_counter.tsx @@ -7,7 +7,7 @@ import type { HttpSetup } from '@kbn/core/public'; import React from 'react'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { DetectionRuleCounter } from '../../../components/detection_rule_counter'; import { getFindingsDetectionRuleSearchTags } from '../../../../common/utils/detection_rules'; import { createDetectionRuleFromBenchmarkRule } from '../utils/create_detection_rule_from_benchmark'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.test.tsx index 118ebb86e0d64..a2fbc66188acd 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.test.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.test.tsx @@ -5,11 +5,11 @@ * 2.0. */ import React from 'react'; +import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; import userEvent from '@testing-library/user-event'; import { FindingsRuleFlyout } from './findings_flyout'; import { render, screen } from '@testing-library/react'; import { TestProvider } from '../../../test/test_provider'; -import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '../../../../common/constants'; import { mockFindingsHit, mockWizFinding } from '../__mocks__/findings'; const onPaginate = jest.fn(); diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx index 4d8c5b6569efd..e1086f81367a3 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/findings_flyout.tsx @@ -35,11 +35,11 @@ import type { HttpSetup } from '@kbn/core/public'; import { generatePath } from 'react-router-dom'; import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { CSP_DATASET, getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name'; import { truthy } from '../../../../common/utils/helpers'; import { benchmarksNavigation } from '../../../common/navigation/constants'; import cisLogoIcon from '../../../assets/icons/cis_logo.svg'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; import { CspEvaluationBadge } from '../../../components/csp_evaluation_badge'; import { TakeAction } from '../../../components/take_action'; import { TableTab } from './table_tab'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx index 30f8237de91b0..712ea0399cf1d 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/json_tab.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { CodeEditor } from '@kbn/code-editor'; import { XJsonLang } from '@kbn/monaco'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; export const JsonTab = ({ data }: { data: CspFinding }) => (
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 38c526df1e758..d25d6d63d213f 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 @@ -18,19 +18,19 @@ import React, { useMemo } from 'react'; import moment from 'moment'; import type { EuiDescriptionListProps, EuiAccordionProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; import { FormattedMessage } from '@kbn/i18n-react'; import { isEmpty } from 'lodash'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name'; import { truthy } from '../../../../common/utils/helpers'; import { CSP_MOMENT_FORMAT } from '../../../common/constants'; import { INTERNAL_FEATURE_FLAGS, CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX, - CDR_MISCONFIGURATIONS_INDEX_PATTERN, } from '../../../../common/constants'; import { useDataView } from '../../../common/api/use_data_view'; import { useKibana } from '../../../common/hooks/use_kibana'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; import { BenchmarkIcons, CodeBlock, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx index 6a7eea41410e9..26007205f43fe 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/rule_tab.tsx @@ -9,7 +9,7 @@ import { EuiBadge, EuiDescriptionList } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { RulesDetectionRuleCounter } from '../../rules/rules_detection_rule_counter'; import { BenchmarkIcons, CspFlyoutMarkdown, EMPTY_VALUE, RuleNameLink } from './findings_flyout'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx index 075291c434592..ad449c4ddccdc 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/findings_flyout/table_tab.tsx @@ -15,7 +15,7 @@ import { import React from 'react'; import { getFlattenedObject } from '@kbn/std'; import { i18n } from '@kbn/i18n'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; interface FlattenedItem { key: string; // flattened dot notation object path for CspFinding; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx index 2d9e1c3f25ae1..209c5ed2b2d06 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_table.tsx @@ -11,7 +11,7 @@ import { DataTableRecord } from '@kbn/discover-utils/types'; import { HttpSetup } from '@kbn/core-http-browser'; import { i18n } from '@kbn/i18n'; import { EuiDataGridCellValueElementProps, EuiFlexItem, EuiSpacer } from '@elastic/eui'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import { getDatasetDisplayName } from '../../../common/utils/get_dataset_display_name'; import * as TEST_SUBJECTS from '../test_subjects'; import { FindingsDistributionBar } from '../layout/findings_distribution_bar'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_get_benchmark_rules_state_api.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_get_benchmark_rules_state_api.ts index ceada5c3148eb..cf79ef80b1196 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_get_benchmark_rules_state_api.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_get_benchmark_rules_state_api.ts @@ -6,11 +6,11 @@ */ import { useQuery } from '@tanstack/react-query'; -import { CspBenchmarkRulesStates } from '../../../../common/types/latest'; import { CSP_GET_BENCHMARK_RULES_STATE_API_CURRENT_VERSION, CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH, -} from '../../../../common/constants'; +} from '@kbn/cloud-security-posture-common'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; import { useKibana } from '../../../common/hooks/use_kibana'; export const getRuleStatesKey = ['get_rules_state_key']; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx index 9c1125257520e..532998f0f712f 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_grouped_findings.tsx @@ -10,7 +10,7 @@ import type { IKibanaSearchResponse } from '@kbn/search-types'; import { GenericBuckets, GroupingQuery, RootAggregation } from '@kbn/grouping/src'; import { useQuery } from '@tanstack/react-query'; import { lastValueFrom } from 'rxjs'; -import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '../../../../common/constants'; +import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; import { useKibana } from '../../../common/hooks/use_kibana'; import { showErrorToast } from '../../../common/utils/show_error_toast'; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts index 3af41c5921416..5a77337ba171c 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings.ts @@ -11,18 +11,17 @@ import type { IKibanaSearchResponse, IKibanaSearchRequest } from '@kbn/search-ty import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildDataTableRecord } from '@kbn/discover-utils'; import { EsHitRecord } from '@kbn/discover-utils/types'; -import { CspFinding } from '../../../../common/schemas/csp_finding'; -import { useKibana } from '../../../common/hooks/use_kibana'; -import type { FindingsBaseEsQuery } from '../../../common/types'; -import { getAggregationCount, getFindingsCountAggQuery } from '../utils/utils'; +import { MAX_FINDINGS_TO_LOAD } from '@kbn/cloud-security-posture-common'; import { CDR_MISCONFIGURATIONS_INDEX_PATTERN, LATEST_FINDINGS_RETENTION_POLICY, -} from '../../../../common/constants'; -import { MAX_FINDINGS_TO_LOAD } from '../../../common/constants'; +} from '@kbn/cloud-security-posture-common'; +import type { CspBenchmarkRulesStates, CspFinding } from '@kbn/cloud-security-posture-common'; +import type { FindingsBaseEsQuery } from '@kbn/cloud-security-posture'; +import { useKibana } from '../../../common/hooks/use_kibana'; +import { getAggregationCount, getFindingsCountAggQuery } from '../utils/utils'; import { showErrorToast } from '../../../common/utils/show_error_toast'; import { useGetCspBenchmarkRulesStatesApi } from './use_get_benchmark_rules_state_api'; -import { CspBenchmarkRulesStates } from '../../../../common/types/latest'; import { buildMutedRulesFilter } from '../../../../common/utils/rules_states'; interface UseFindingsOptions extends FindingsBaseEsQuery { diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx index 0235960207e27..d94f063933b0e 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/use_latest_findings_grouping.tsx @@ -15,13 +15,13 @@ import { } from '@kbn/grouping/src'; import { useMemo } from 'react'; import { buildEsQuery, Filter } from '@kbn/es-query'; +import { LATEST_FINDINGS_RETENTION_POLICY } from '@kbn/cloud-security-posture-common'; import { FINDINGS_GROUPING_OPTIONS, LOCAL_STORAGE_FINDINGS_GROUPING_KEY, } from '../../../common/constants'; import { useDataViewContext } from '../../../common/contexts/data_view_context'; import { Evaluation } from '../../../../common/types_old'; -import { LATEST_FINDINGS_RETENTION_POLICY } from '../../../../common/constants'; import { FindingsGroupingAggregation, FindingsRootGroupingAggregation, diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx index 755ecb86c73ba..61d4a5cc7d6dc 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/layout/findings_search_bar.tsx @@ -10,10 +10,10 @@ import { EuiThemeComputed, useEuiTheme } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { i18n } from '@kbn/i18n'; import type { Filter } from '@kbn/es-query'; +import type { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import { useDataViewContext } from '../../../common/contexts/data_view_context'; import { SecuritySolutionContext } from '../../../application/security_solution_context'; import type { FindingsBaseURLQuery } from '../../../common/types'; -import type { CspClientPluginStartDeps } from '../../../types'; import { PLUGIN_NAME } from '../../../../common'; type SearchBarQueryProps = Pick; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_benchmark.ts b/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_benchmark.ts index d77e6ddf6389c..289c6c2cb153f 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_benchmark.ts +++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/utils/create_detection_rule_from_benchmark.ts @@ -6,11 +6,10 @@ */ import { HttpSetup } from '@kbn/core/public'; +import { LATEST_FINDINGS_RETENTION_POLICY } from '@kbn/cloud-security-posture-common'; import { CspBenchmarkRule } from '../../../../common/types/latest'; -import { - FINDINGS_INDEX_PATTERN, - LATEST_FINDINGS_RETENTION_POLICY, -} from '../../../../common/constants'; +import { FINDINGS_INDEX_PATTERN } from '../../../../common/constants'; + import { createDetectionRule } from '../../../common/api/create_detection_rule'; import { generateBenchmarkRuleTags } from '../../../../common/utils/detection_rules'; 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 264a8229d11a3..0bafc004a5e11 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 @@ -23,19 +23,13 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { HttpSetup } from '@kbn/core/public'; -import { useKibana } from '../../common/hooks/use_kibana'; -import { getFindingsDetectionRuleSearchTags } from '../../../common/utils/detection_rules'; -import { CspBenchmarkRuleMetadata } from '../../../common/types/latest'; +import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common'; 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 './use_change_csp_rule_state'; import { CspBenchmarkRulesWithStates } from './rules_container'; -import { - showChangeBenchmarkRuleStatesSuccessToast, - TakeAction, -} from '../../components/take_action'; -import { useFetchDetectionRulesByTags } from '../../common/api/use_fetch_detection_rules_by_tags'; +import { TakeAction } from '../../components/take_action'; import { createDetectionRuleFromBenchmarkRule } from '../configurations/utils/create_detection_rule_from_benchmark'; export const RULES_FLYOUT_SWITCH_BUTTON = 'rule-flyout-switch-button'; @@ -66,13 +60,9 @@ type RuleTab = (typeof tabs)[number]['id']; export const RuleFlyout = ({ onClose, rule }: RuleFlyoutProps) => { const [tab, setTab] = useState('overview'); - const { mutate: mutateRuleState } = useChangeCspRuleState(); - const { data: rulesData } = useFetchDetectionRulesByTags( - getFindingsDetectionRuleSearchTags(rule.metadata) - ); - const { notifications, analytics, i18n: i18nStart, theme } = useKibana().services; - const startServices = { notifications, analytics, i18n: i18nStart, theme }; + const isRuleMuted = rule?.state === 'muted'; + const { mutate: mutateRuleState } = useChangeCspRuleState(); const switchRuleStates = async () => { if (rule.metadata.benchmark.rule_number) { @@ -83,14 +73,10 @@ export const RuleFlyout = ({ onClose, rule }: RuleFlyoutProps) => { rule_id: rule.metadata.id, }; const nextRuleStates = isRuleMuted ? 'unmute' : 'mute'; - await mutateRuleState({ + 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 05bed9ce85cd3..54513283cec5c 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 @@ -20,16 +20,10 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { uniqBy } from 'lodash'; -import { HttpSetup } from '@kbn/core/public'; -import { CloudSecurityPostureStartServices } from '../../types'; -import { useKibana } from '../../common/hooks/use_kibana'; -import { getFindingsDetectionRuleSearchTags } from '../../../common/utils/detection_rules'; import { ColumnNameWithTooltip } from '../../components/column_name_with_tooltip'; import type { CspBenchmarkRulesWithStates, RulesState } from './rules_container'; import * as TEST_SUBJECTS from './test_subjects'; -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'; +import { useChangeCspRuleState } from './use_change_csp_rule_state'; export const RULES_ROWS_ENABLE_SWITCH_BUTTON = 'rules-row-enable-switch-button'; export const RULES_ROW_SELECT_ALL_CURRENT_PAGE = 'cloud-security-fields-selector-item-all'; @@ -50,7 +44,6 @@ type GetColumnProps = Pick< RulesTableProps, 'onRuleClick' | 'selectedRules' | 'setSelectedRules' > & { - mutateRulesStates: (ruleStateUpdateRequest: RuleStateUpdateRequest) => void; items: CspBenchmarkRulesWithStates[]; setIsAllRulesSelectedThisPage: (isAllRulesSelected: boolean) => void; isAllRulesSelectedThisPage: boolean; @@ -58,8 +51,6 @@ type GetColumnProps = Pick< currentPageRulesArray: CspBenchmarkRulesWithStates[], selectedRulesArray: CspBenchmarkRulesWithStates[] ) => boolean; - http: HttpSetup; - startServices: CloudSecurityPostureStartServices; }; export const RulesTable = ({ @@ -111,8 +102,6 @@ export const RulesTable = ({ const [isAllRulesSelectedThisPage, setIsAllRulesSelectedThisPage] = useState(false); - const { mutate: mutateRulesStates } = useChangeCspRuleState(); - const isCurrentPageRulesASubset = ( currentPageRulesArray: CspBenchmarkRulesWithStates[], selectedRulesArray: CspBenchmarkRulesWithStates[] @@ -128,16 +117,13 @@ export const RulesTable = ({ return true; }; - const { http, notifications, analytics, i18n: i18nStart, theme } = useKibana().services; useEffect(() => { if (selectedRules.length >= items.length && items.length > 0 && selectedRules.length > 0) setIsAllRulesSelectedThisPage(true); else setIsAllRulesSelectedThisPage(false); }, [items.length, selectedRules.length]); - const startServices = { notifications, analytics, i18n: i18nStart, theme }; const columns = getColumns({ - mutateRulesStates, selectedRules, setSelectedRules, items, @@ -145,8 +131,6 @@ export const RulesTable = ({ isAllRulesSelectedThisPage, isCurrentPageRulesASubset, onRuleClick, - http, - startServices, }); return ( @@ -168,15 +152,12 @@ export const RulesTable = ({ }; const getColumns = ({ - mutateRulesStates, selectedRules, setSelectedRules, items, isAllRulesSelectedThisPage, isCurrentPageRulesASubset, onRuleClick, - http, - startServices, }: GetColumnProps): Array> => [ { field: 'action', @@ -281,52 +262,43 @@ const getColumns = ({ align: 'right', width: '100px', truncateText: true, - render: (_name, rule: CspBenchmarkRulesWithStates) => { - const rulesObjectRequest = { - benchmark_id: rule?.metadata.benchmark.id, - benchmark_version: rule?.metadata.benchmark.version, - /* Rule number always exists from 8.7 */ - rule_number: rule?.metadata.benchmark.rule_number!, - rule_id: rule?.metadata.id, - }; - const isRuleMuted = rule?.state === 'muted'; - const nextRuleState = isRuleMuted ? 'unmute' : 'mute'; - 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 detectionRulesForSelectedRule = ( - await fetchDetectionRulesByTags( - getFindingsDetectionRuleSearchTags(rule.metadata), - { match: 'all' }, - http - ) - ).total; - - mutateRulesStates({ - newState: nextRuleState, - ruleIds: [rulesObjectRequest], - }); - - showChangeBenchmarkRuleStatesSuccessToast(startServices, isRuleMuted, { - numberOfRules: 1, - numberOfDetectionRules: detectionRulesForSelectedRule || 0, - }); - } - }; - return ( - - - - - - ); - }, + render: (_name, rule: CspBenchmarkRulesWithStates) => , }, ]; + +const RuleStateSwitch = ({ rule }: { rule: CspBenchmarkRulesWithStates }) => { + const isRuleMuted = rule?.state === 'muted'; + const nextRuleState = isRuleMuted ? 'unmute' : 'mute'; + + const { mutate: mutateRulesStates } = useChangeCspRuleState(); + + const rulesObjectRequest = { + benchmark_id: rule?.metadata.benchmark.id, + benchmark_version: rule?.metadata.benchmark.version, + /* Rule number always exists from 8.7 */ + rule_number: rule?.metadata.benchmark.rule_number!, + rule_id: rule?.metadata.id, + }; + const changeCspRuleStateFn = async () => { + if (rule?.metadata.benchmark.rule_number) { + mutateRulesStates({ + newState: nextRuleState, + ruleIds: [rulesObjectRequest], + }); + } + }; + return ( + + + + + + ); +}; 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 3350dc26156d5..a7c69326d3964 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 @@ -23,16 +23,12 @@ import useDebounce from 'react-use/lib/useDebounce'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import { useKibana } from '../../common/hooks/use_kibana'; -import { getFindingsDetectionRuleSearchTagsFromArrayOfRules } from '../../../common/utils/detection_rules'; 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'; -import { useFetchDetectionRulesByTags } from '../../common/api/use_fetch_detection_rules_by_tags'; export const RULES_BULK_ACTION_BUTTON = 'bulk-action-button'; export const RULES_BULK_ACTION_OPTION_ENABLE = 'bulk-action-option-enable'; @@ -245,15 +241,8 @@ const CurrentPageOfTotal = ({ }; const { mutate: mutateRulesStates } = useChangeCspRuleState(); - const { data: detectionRulesForSelectedRules } = useFetchDetectionRulesByTags( - getFindingsDetectionRuleSearchTagsFromArrayOfRules(selectedRules.map((rule) => rule.metadata)), - { match: 'any' } - ); - - const { notifications, analytics, i18n: i18nStart, theme } = useKibana().services; - const startServices = { notifications, analytics, i18n: i18nStart, theme }; - const changeRulesState = async (state: 'mute' | 'unmute') => { + const changeCspRuleState = (state: 'mute' | 'unmute') => { const bulkSelectedRules: RuleStateAttributesWithoutStates[] = selectedRules.map( (e: CspBenchmarkRulesWithStates) => ({ benchmark_id: e?.metadata.benchmark.id, @@ -269,19 +258,15 @@ const CurrentPageOfTotal = ({ ruleIds: bulkSelectedRules, }); setIsPopoverOpen(false); - showChangeBenchmarkRuleStatesSuccessToast(startServices, state !== 'mute', { - numberOfRules: bulkSelectedRules.length, - numberOfDetectionRules: detectionRulesForSelectedRules?.total || 0, - }); } - }; - const changeCspRuleStateMute = async () => { - await changeRulesState('mute'); setSelectedRules([]); }; - const changeCspRuleStateUnmute = async () => { - await changeRulesState('unmute'); - setSelectedRules([]); + + const changeCspRuleStateMute = () => { + changeCspRuleState('mute'); + }; + const changeCspRuleStateUnmute = () => { + changeCspRuleState('unmute'); }; const areAllSelectedRulesMuted = selectedRules.every((rule) => rule?.state === 'muted'); 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 deleted file mode 100644 index bbf175b107f6e..0000000000000 --- a/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { 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_change_csp_rule_state.tsx b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.tsx new file mode 100644 index 0000000000000..9b616062b0050 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/public/pages/rules/use_change_csp_rule_state.tsx @@ -0,0 +1,204 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { useQueryClient, useMutation } from '@tanstack/react-query'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n as kbnI18n } from '@kbn/i18n'; +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 { + CspBenchmarkRulesBulkActionResponse, + RuleStateAttributes, +} from '../../../common/types/latest'; +import { CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH } from '../../../common/constants'; +import { CloudSecurityPostureStartServices } from '../../types'; +import { useKibana } from '../../common/hooks/use_kibana'; + +export type RuleStateAttributesWithoutStates = Omit; +export interface RuleStateUpdateRequest { + newState: 'mute' | 'unmute'; + ruleIds: RuleStateAttributesWithoutStates[]; +} + +export const showChangeBenchmarkRulesStatesErrorToast = ( + cloudSecurityStartServices: CloudSecurityPostureStartServices, + error: Error +) => { + return cloudSecurityStartServices.notifications.toasts.addDanger({ + title: kbnI18n.translate('xpack.csp.rules.changeRuleStateErrorTitle', { + defaultMessage: 'Unable to update rule', + }), + text: kbnI18n.translate('xpack.csp.rules.changeRuleStateErrorText', { + defaultMessage: 'An error occurred while updating the rule: {errorMessage}.', + values: { errorMessage: error.message }, + }), + 'data-test-subj': 'csp:toast-error', + }); +}; + +const showChangeBenchmarkRuleStatesSuccessToast = ( + cloudSecurityStartServices: CloudSecurityPostureStartServices, + data: { + newState: RuleStateUpdateRequest['newState']; + numberOfRules: number; + numberOfDetectionRules: number; + } +) => { + const { notifications, analytics, i18n, theme } = cloudSecurityStartServices; + const startServices = { analytics, i18n, theme }; + + return notifications.toasts.addSuccess({ + toastLifeTimeMs: 10000, + color: 'success', + iconType: '', + 'data-test-subj': 'csp:toast-success-rule-state-change', + title: toMountPoint( + + + {data.newState === 'unmute' ? ( + + ) : ( + + )} + + , + startServices + ), + text: toMountPoint( +
+ {data.newState === 'unmute' ? ( + + ) : ( + <> + + {data.newState === 'mute' && data.numberOfDetectionRules > 0 && ( + + + + )} + + )} +
, + startServices + ), + }); +}; + +export const useChangeCspRuleState = () => { + const { http } = useKibana().services; + + const { notifications, analytics, i18n: i18nStart, theme } = useKibana().services; + + const startServices = { notifications, analytics, i18n: i18nStart, theme }; + + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (ruleStateUpdateRequest: RuleStateUpdateRequest) => { + return 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 }; + }, + onSuccess: (data, variables) => { + 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); + showChangeBenchmarkRuleStatesSuccessToast(startServices, { + newState: variables?.newState, + numberOfRules: Object.keys(data?.updated_benchmark_rules || {})?.length || 0, + numberOfDetectionRules: data?.disabled_detection_rules?.length || 0, + }); + }, + onError: (error: Error, _, context) => { + if (context?.previousCspRules) { + queryClient.setQueryData(CSP_RULES_STATES_QUERY_KEY, context.previousCspRules); + } + showChangeBenchmarkRulesStatesErrorToast(startServices, error); + }, + }); +}; + +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 e712b130e1651..640dc92274481 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 @@ -6,8 +6,8 @@ */ import { useQuery } from '@tanstack/react-query'; -import { CspBenchmarkRulesStates } from '../../../common/types/latest'; -import { CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH } from '../../../common/constants'; +import { CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH } from '@kbn/cloud-security-posture-common'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; import { useKibana } from '../../common/hooks/use_kibana'; export const CSP_RULES_STATES_QUERY_KEY = ['csp_rules_states_v1']; diff --git a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx index 15760e80ad7c2..3b1d3a156f305 100644 --- a/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx +++ b/x-pack/plugins/cloud_security_posture/public/pages/vulnerabilities/hooks/use_latest_vulnerabilities.tsx @@ -16,7 +16,9 @@ import { } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { buildDataTableRecord } from '@kbn/discover-utils'; import { EsHitRecord } from '@kbn/discover-utils/types'; -import { MAX_FINDINGS_TO_LOAD, VULNERABILITY_FIELDS } from '../../../common/constants'; +import { MAX_FINDINGS_TO_LOAD } from '@kbn/cloud-security-posture-common'; +import { FindingsBaseEsQuery } from '@kbn/cloud-security-posture'; +import { VULNERABILITY_FIELDS } from '../../../common/constants'; import { CspVulnerabilityFinding } from '../../../../common/schemas'; import { LATEST_VULNERABILITIES_INDEX_PATTERN, @@ -24,7 +26,6 @@ import { } from '../../../../common/constants'; import { useKibana } from '../../../common/hooks/use_kibana'; import { showErrorToast } from '../../../common/utils/show_error_toast'; -import { FindingsBaseEsQuery } from '../../../common/types'; import { getCaseInsensitiveSortScript } from '../utils/custom_sort_script'; type LatestFindingsRequest = IKibanaSearchRequest; type LatestFindingsResponse = IKibanaSearchResponse< diff --git a/x-pack/plugins/cloud_security_posture/public/plugin.tsx b/x-pack/plugins/cloud_security_posture/public/plugin.tsx index bf014f83c1b0d..d07d930660ec6 100755 --- a/x-pack/plugins/cloud_security_posture/public/plugin.tsx +++ b/x-pack/plugins/cloud_security_posture/public/plugin.tsx @@ -9,14 +9,10 @@ import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import type { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import { CspLoadingState } from './components/csp_loading_state'; import type { CspRouterProps } from './application/csp_router'; -import type { - CspClientPluginSetup, - CspClientPluginStart, - CspClientPluginSetupDeps, - CspClientPluginStartDeps, -} from './types'; +import type { CspClientPluginSetup, CspClientPluginStart, CspClientPluginSetupDeps } from './types'; import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME } from '../common/constants'; import { SetupContext } from './application/setup_context'; diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/dataview.handlers.mock.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/dataview.handlers.mock.ts index fb7a25fbcdadf..62430421f7358 100644 --- a/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/dataview.handlers.mock.ts +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/handlers/dataview.handlers.mock.ts @@ -6,10 +6,8 @@ */ import { http, HttpResponse } from 'msw'; -import { - CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX, - CDR_MISCONFIGURATIONS_INDEX_PATTERN, -} from '../../../../common/constants'; +import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; +import { CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX } from '../../../../common/constants'; const generateDataViewField = (name: string, type: 'string' | 'date' = 'string') => ({ name, diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts index 999f130c275cc..86ec3e3108f27 100644 --- a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server.ts @@ -13,9 +13,9 @@ import { createStubDataView } from '@kbn/data-views-plugin/common/stubs'; import { indexPatternFieldEditorPluginMock as dataViewFieldEditorMock } from '@kbn/data-view-field-editor-plugin/public/mocks'; import SearchBar from '@kbn/unified-search-plugin/public/search_bar/search_bar'; import { http, HttpResponse, JsonBodyType } from 'msw'; +import { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import { defaultHandlers } from './handlers'; import { getMockDependencies } from '../fixtures/get_mock_dependencies'; -import { CspClientPluginStartDeps } from '../../types'; import { MOCK_SERVER_LICENSING_INFO_URL } from './handlers/licensing.handlers.mock'; /** diff --git a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx index 19143d4641836..0a2db4ca59643 100644 --- a/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx +++ b/x-pack/plugins/cloud_security_posture/public/test/mock_server/mock_server_test_provider.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import type { CoreStart } from '@kbn/core/public'; -import { CspClientPluginStartDeps } from '../../types'; +import { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import { TestProvider } from '../test_provider'; import { getMockServerDependencies } from './mock_server'; interface MockServerDependencies { diff --git a/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx b/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx index ab3173ec8c581..278ba2f0b1690 100755 --- a/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx +++ b/x-pack/plugins/cloud_security_posture/public/test/test_provider.tsx @@ -14,7 +14,7 @@ import { Route, Routes } from '@kbn/shared-ux-router'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { coreMock } from '@kbn/core/public/mocks'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import type { CspClientPluginStartDeps } from '../types'; +import type { CspClientPluginStartDeps } from '@kbn/cloud-security-posture'; import { getMockDependencies } from './fixtures/get_mock_dependencies'; interface CspAppDeps { diff --git a/x-pack/plugins/cloud_security_posture/public/types.ts b/x-pack/plugins/cloud_security_posture/public/types.ts index bd45c007112b0..f03d47e43575d 100755 --- a/x-pack/plugins/cloud_security_posture/public/types.ts +++ b/x-pack/plugins/cloud_security_posture/public/types.ts @@ -6,26 +6,12 @@ */ import type { CloudSetup } from '@kbn/cloud-plugin/public'; -import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; -import { DataViewsServicePublic } from '@kbn/data-views-plugin/public'; import type { ComponentType, ReactNode } from 'react'; -import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; -import { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { IndexPatternFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; -import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; -import { CoreStart, ToastsStart } from '@kbn/core/public'; -import { Storage } from '@kbn/kibana-utils-plugin/public'; - -import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; -import type { DiscoverStart } from '@kbn/discover-plugin/public'; -import type { FleetSetup, FleetStart } from '@kbn/fleet-plugin/public'; -import type { - UsageCollectionSetup, - UsageCollectionStart, -} from '@kbn/usage-collection-plugin/public'; -import { SharePluginStart } from '@kbn/share-plugin/public'; -import { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import { UiActionsSetup } from '@kbn/ui-actions-plugin/public'; +import type { DataPublicPluginSetup } from '@kbn/data-plugin/public'; +import { CoreStart } from '@kbn/core/public'; +import type { FleetSetup } from '@kbn/fleet-plugin/public'; +import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import type { CspRouterProps } from './application/csp_router'; import type { CloudSecurityPosturePageId } from './common/navigation/types'; @@ -53,28 +39,6 @@ export interface CspClientPluginSetupDeps { usageCollection?: UsageCollectionSetup; } -export interface CspClientPluginStartDeps { - // required - data: DataPublicPluginStart; - dataViews: DataViewsServicePublic; - dataViewFieldEditor: IndexPatternFieldEditorStart; - unifiedSearch: UnifiedSearchPublicPluginStart; - uiActions: UiActionsStart; - fieldFormats: FieldFormatsStart; - toastNotifications: ToastsStart; - charts: ChartsPluginStart; - discover: DiscoverStart; - fleet: FleetStart; - licensing: LicensingPluginStart; - share: SharePluginStart; - storage: Storage; - spaces: SpacesPluginStart; - cloud: CloudSetup; - - // optional - usageCollection?: UsageCollectionStart; -} - /** * Methods exposed from the security solution to the cloud security posture application. */ diff --git a/x-pack/plugins/cloud_security_posture/server/create_indices/latest_indices.ts b/x-pack/plugins/cloud_security_posture/server/create_indices/latest_indices.ts index 91c7ae74de9e8..2994c88bef290 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_indices/latest_indices.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_indices/latest_indices.ts @@ -5,9 +5,9 @@ * 2.0. */ +import { CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; import { FINDINGS_INDEX_NAME, - CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN, LATEST_FINDINGS_INDEX_TEMPLATE_NAME, LATEST_FINDINGS_INDEX_DEFAULT_NS, VULNERABILITIES_INDEX_NAME, diff --git a/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts b/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts index 556ab0c7c830c..aa428c7083eca 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_transforms/latest_findings_transform.ts @@ -5,11 +5,11 @@ * 2.0. */ import type { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import { LATEST_FINDINGS_RETENTION_POLICY } from '@kbn/cloud-security-posture-common'; import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME, FINDINGS_INDEX_PATTERN, LATEST_FINDINGS_INDEX_DEFAULT_NS, - LATEST_FINDINGS_RETENTION_POLICY, } from '../../common/constants'; const LATEST_FINDINGS_TRANSFORM_V830 = 'cloud_security_posture.findings_latest-default-0.0.1'; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts b/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts index 67eb611f9557e..85d4a7f76a5c9 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/check_index_status.ts @@ -6,8 +6,9 @@ */ import { ElasticsearchClient, type Logger } from '@kbn/core/server'; +import type { IndexStatus } from '@kbn/cloud-security-posture-common'; import { getSafePostureTypeRuntimeMapping } from '../../common/runtime_mappings/get_safe_posture_type_runtime_mapping'; -import { IndexStatus, PostureTypes } from '../../common/types_old'; +import { PostureTypes } from '../../common/types_old'; export interface PostureTypeAndRetention { postureType?: PostureTypes; diff --git a/x-pack/plugins/cloud_security_posture/server/lib/fleet_util.ts b/x-pack/plugins/cloud_security_posture/server/lib/fleet_util.ts index 5a11ddebdd9d3..a82eeb70c3d40 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/fleet_util.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/fleet_util.ts @@ -5,6 +5,7 @@ * 2.0. */ import { flatMap, uniq } from 'lodash'; +import { KSPM_POLICY_TEMPLATE, CSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import type { SavedObjectsClientContract, Logger } from '@kbn/core/server'; import type { AgentPolicyServiceInterface, @@ -23,8 +24,6 @@ import { CloudSecurityPolicyTemplate, PostureTypes } from '../../common/types_ol import { SUPPORTED_POLICY_TEMPLATES, CLOUD_SECURITY_POSTURE_PACKAGE_NAME, - KSPM_POLICY_TEMPLATE, - CSPM_POLICY_TEMPLATE, } from '../../common/constants'; import { CSP_FLEET_PACKAGE_KUERY } from '../../common/utils/helpers'; import { diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts index 5cd7c6dc03766..32043329b0706 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/cloud_accounts_stats_collector.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { ISavedObjectsRepository, Logger } from '@kbn/core/server'; +import { KSPM_POLICY_TEMPLATE, CSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import type { SearchRequest } from '@elastic/elasticsearch/lib/api/types'; import { getPackagePolicyIdRuntimeMapping } from '../../../../common/runtime_mappings/get_package_policy_id_mapping'; import { getIdentifierRuntimeMapping } from '../../../../common/runtime_mappings/get_identifier_runtime_mapping'; @@ -17,8 +18,6 @@ import type { CloudSecurityAccountsStats, } from './types'; import { - CSPM_POLICY_TEMPLATE, - KSPM_POLICY_TEMPLATE, LATEST_FINDINGS_INDEX_DEFAULT_NS, LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, VULN_MGMT_POLICY_TEMPLATE, diff --git a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts index d5db37879554b..baa4601565c85 100644 --- a/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/lib/telemetry/collectors/types.ts @@ -6,7 +6,7 @@ */ import { AggregationsMultiBucketBase } from '@elastic/elasticsearch/lib/api/types'; -import { CspStatusCode } from '../../../../common/types_old'; +import { CspStatusCode } from '@kbn/cloud-security-posture-common'; export type CloudSecurityUsageCollectorType = | 'Indices' diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts index df5db4cb2e1ab..e733f6cc96003 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts @@ -6,12 +6,12 @@ */ import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; import type { FindResult, RulesClient } from '@kbn/alerting-plugin/server'; import type { RuleParams } from '@kbn/alerting-plugin/server/application/rule/types'; import type { CspBenchmarkRule, RulesToUpdate, - CspBenchmarkRulesStates, CspSettings, } from '../../../../common/types/rules/v4'; import { @@ -59,7 +59,7 @@ export const getDetectionRules = async ( filter: convertRuleTagsToMatchAllKQL(ruleTags), searchFields: ['tags'], page: 1, - perPage: 1, + perPage: 100, // Disable up to 100 detection rules per benchmark rule at a time }, }); }) diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts index a55bcd92ab3c8..44dd77cc67059 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/get_states.ts @@ -6,9 +6,9 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH } from '@kbn/cloud-security-posture-common'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; import { CspRouter } from '../../../types'; -import { CSP_GET_BENCHMARK_RULES_STATE_ROUTE_PATH } from '../../../../common/constants'; -import { CspBenchmarkRulesStates } from '../../../../common/types/rules/v4'; import { getCspBenchmarkRulesStatesHandler } from './v1'; export const defineGetCspBenchmarkRulesStatesRoute = (router: CspRouter) => diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/v1.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/v1.ts index 4d28b995cbdaf..1c7ddccf91bba 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/v1.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/get_states/v1.ts @@ -10,7 +10,8 @@ import { } from '@kbn/core-saved-objects-api-server'; import { transformError } from '@kbn/securitysolution-es-utils'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { CspBenchmarkRulesStates, CspSettings } from '../../../../common/types/rules/v4'; +import type { CspBenchmarkRulesStates } from '@kbn/cloud-security-posture-common'; +import { CspSettings } from '../../../../common/types/rules/v4'; import { INTERNAL_CSP_SETTINGS_SAVED_OBJECT_ID, INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts index e793863621340..4cb7ec3c918e6 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/compliance_dashboard/get_clusters.ts @@ -15,7 +15,7 @@ import type { } from '@elastic/elasticsearch/lib/api/types'; import type { Logger } from '@kbn/core/server'; import { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/types'; -import { CspFinding } from '../../../common/schemas/csp_finding'; +import type { CspFinding } from '@kbn/cloud-security-posture-common'; import type { Cluster } from '../../../common/types_old'; import { getPostureStatsFromAggs, failedFindingsAggQuery } from './get_grouped_findings_evaluation'; import type { FailedFindingsQueryResult } from './get_grouped_findings_evaluation'; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/status/status.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/status/status.test.ts index 24d213b92ad8b..e3b844a551a4e 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/status/status.test.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/status/status.test.ts @@ -5,8 +5,9 @@ * 2.0. */ +import { CSPM_POLICY_TEMPLATE } from '@kbn/cloud-security-posture-common'; import { calculateIntegrationStatus } from './status'; -import { CSPM_POLICY_TEMPLATE, VULN_MGMT_POLICY_TEMPLATE } from '../../../common/constants'; +import { VULN_MGMT_POLICY_TEMPLATE } from '../../../common/constants'; import { Installation } from '@kbn/fleet-plugin/common'; const mockInstallation: Installation = { diff --git a/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts b/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts index 868deaed0fd82..2434cf03c8473 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/status/status.ts @@ -6,6 +6,18 @@ */ import { transformError } from '@kbn/securitysolution-es-utils'; +import { + KSPM_POLICY_TEMPLATE, + CSPM_POLICY_TEMPLATE, + STATUS_ROUTE_PATH, + LATEST_FINDINGS_RETENTION_POLICY, + CDR_MISCONFIGURATIONS_INDEX_PATTERN, +} from '@kbn/cloud-security-posture-common'; +import type { + CspSetupStatus, + IndexStatus, + CspStatusCode, +} from '@kbn/cloud-security-posture-common'; import type { SavedObjectsClientContract, Logger, ElasticsearchClient } from '@kbn/core/server'; import type { AgentPolicyServiceInterface, @@ -19,20 +31,15 @@ import { schema } from '@kbn/config-schema'; import { VersionedRoute } from '@kbn/core-http-server/src/versioning/types'; import { CLOUD_SECURITY_POSTURE_PACKAGE_NAME, - STATUS_ROUTE_PATH, LATEST_FINDINGS_INDEX_DEFAULT_NS, FINDINGS_INDEX_PATTERN, BENCHMARK_SCORE_INDEX_DEFAULT_NS, VULNERABILITIES_INDEX_PATTERN, - KSPM_POLICY_TEMPLATE, - CSPM_POLICY_TEMPLATE, POSTURE_TYPES, LATEST_VULNERABILITIES_INDEX_DEFAULT_NS, VULN_MGMT_POLICY_TEMPLATE, POSTURE_TYPE_ALL, LATEST_VULNERABILITIES_RETENTION_POLICY, - LATEST_FINDINGS_RETENTION_POLICY, - CDR_MISCONFIGURATIONS_INDEX_PATTERN, } from '../../../common/constants'; import type { CspApiRequestHandlerContext, @@ -40,12 +47,7 @@ import type { CspRouter, StatusResponseInfo, } from '../../types'; -import type { - CspSetupStatus, - CspStatusCode, - IndexStatus, - PostureTypes, -} from '../../../common/types_old'; +import type { PostureTypes } from '../../../common/types_old'; import { getAgentStatusesByAgentPolicies, getCspAgentPolicies, diff --git a/x-pack/plugins/cloud_security_posture/server/saved_objects/data_views.ts b/x-pack/plugins/cloud_security_posture/server/saved_objects/data_views.ts index 8a9f44b3aec46..e99f0365e6099 100644 --- a/x-pack/plugins/cloud_security_posture/server/saved_objects/data_views.ts +++ b/x-pack/plugins/cloud_security_posture/server/saved_objects/data_views.ts @@ -15,11 +15,11 @@ import { DataViewAttributes } from '@kbn/data-views-plugin/common'; import { SpacesServiceStart } from '@kbn/spaces-plugin/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { CDR_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; import { CDR_MISCONFIGURATIONS_DATA_VIEW_ID_PREFIX, CDR_MISCONFIGURATIONS_DATA_VIEW_NAME, - CDR_MISCONFIGURATIONS_INDEX_PATTERN, CDR_VULNERABILITIES_DATA_VIEW_ID_PREFIX, CDR_VULNERABILITIES_DATA_VIEW_NAME, CDR_VULNERABILITIES_INDEX_PATTERN, diff --git a/x-pack/plugins/cloud_security_posture/server/types.ts b/x-pack/plugins/cloud_security_posture/server/types.ts index 1190c0a1c5556..4524cab151dd2 100644 --- a/x-pack/plugins/cloud_security_posture/server/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/types.ts @@ -30,12 +30,12 @@ import type { PackagePolicyClient, } from '@kbn/fleet-plugin/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; +import type { CspStatusCode, IndexDetails } from '@kbn/cloud-security-posture-common'; import type { FleetStartContract, FleetRequestHandlerContext } from '@kbn/fleet-plugin/server'; import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server'; import type { AlertingPluginSetup } from '@kbn/alerting-plugin/public/plugin'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; -import { CspStatusCode, IndexDetails } from '../common/types_old'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface CspServerPluginSetup {} diff --git a/x-pack/plugins/cloud_security_posture/tsconfig.json b/x-pack/plugins/cloud_security_posture/tsconfig.json index 83891e3269eca..6e19e9b4d09fa 100755 --- a/x-pack/plugins/cloud_security_posture/tsconfig.json +++ b/x-pack/plugins/cloud_security_posture/tsconfig.json @@ -57,7 +57,6 @@ "@kbn/kibana-utils-plugin", "@kbn/ui-actions-plugin", "@kbn/core-http-server-mocks", - "@kbn/field-formats-plugin", "@kbn/data-view-field-editor-plugin", "@kbn/grouping", "@kbn/alerting-plugin", @@ -65,7 +64,9 @@ "@kbn/code-editor-mock", "@kbn/search-types", "@kbn/react-kibana-mount", - "@kbn/spaces-plugin" + "@kbn/spaces-plugin", + "@kbn/cloud-security-posture-common", + "@kbn/cloud-security-posture" ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/data_quality/common/index.ts b/x-pack/plugins/data_quality/common/index.ts index 1b174a9efe524..a1869cd9ac356 100644 --- a/x-pack/plugins/data_quality/common/index.ts +++ b/x-pack/plugins/data_quality/common/index.ts @@ -12,4 +12,8 @@ export const PLUGIN_NAME = i18n.translate('xpack.dataQuality.name', { defaultMessage: 'Data Set Quality', }); -export { DATA_QUALITY_URL_STATE_KEY, datasetQualityUrlSchemaV1 } from './url_schema'; +export { + DATA_QUALITY_URL_STATE_KEY, + datasetQualityUrlSchemaV1, + datasetQualityDetailsUrlSchemaV1, +} from './url_schema'; diff --git a/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_details_locator_path.ts b/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_details_locator_path.ts new file mode 100644 index 0000000000000..31ae8591bb5b8 --- /dev/null +++ b/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_details_locator_path.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 { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/common'; +import { ManagementAppLocatorParams } from '@kbn/management-plugin/common/locator'; +import { LocatorPublic } from '@kbn/share-plugin/common'; +import { DataQualityDetailsLocatorParams } from '@kbn/deeplinks-observability'; +import { datasetQualityDetailsUrlSchemaV1, DATA_QUALITY_URL_STATE_KEY } from '../url_schema'; +import { deepCompactObject } from '../utils/deep_compact_object'; + +interface LocatorPathConstructionParams { + locatorParams: DataQualityDetailsLocatorParams; + useHash: boolean; + managementLocator: LocatorPublic; +} + +export const constructDatasetQualityDetailsLocatorPath = async ( + params: LocatorPathConstructionParams +) => { + const { locatorParams, useHash, managementLocator } = params; + + const pageState = datasetQualityDetailsUrlSchemaV1.urlSchemaRT.encode( + deepCompactObject({ + v: 1, + ...locatorParams, + }) + ); + + const managementPath = await managementLocator.getLocation({ + sectionId: 'data', + appId: 'data_quality/details', + }); + + const path = setStateToKbnUrl( + DATA_QUALITY_URL_STATE_KEY, + pageState, + { useHash, storeInHashQuery: false }, + `${managementPath.app}${managementPath.path}` + ); + + return { + app: '', + path, + state: {}, + }; +}; diff --git a/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_locator_path.ts b/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_locator_path.ts index f5b5b0bf7ce59..4fc97618d33e1 100644 --- a/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_locator_path.ts +++ b/x-pack/plugins/data_quality/common/locators/construct_dataset_quality_locator_path.ts @@ -20,7 +20,7 @@ interface LocatorPathConstructionParams { export const constructDatasetQualityLocatorPath = async (params: LocatorPathConstructionParams) => { const { - locatorParams: { filters, flyout }, + locatorParams: { filters }, useHash, managementLocator, } = params; @@ -29,7 +29,6 @@ export const constructDatasetQualityLocatorPath = async (params: LocatorPathCons deepCompactObject({ v: 1, filters, - flyout, }) ); diff --git a/x-pack/plugins/data_quality/common/locators/dataset_quality_details_locator.ts b/x-pack/plugins/data_quality/common/locators/dataset_quality_details_locator.ts new file mode 100644 index 0000000000000..a25e065b1efb4 --- /dev/null +++ b/x-pack/plugins/data_quality/common/locators/dataset_quality_details_locator.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 type { LocatorDefinition } from '@kbn/share-plugin/public'; +import { + DataQualityDetailsLocatorParams, + DATA_QUALITY_DETAILS_LOCATOR_ID, +} from '@kbn/deeplinks-observability'; +import { DataQualityLocatorDependencies } from './types'; +import { constructDatasetQualityDetailsLocatorPath } from './construct_dataset_quality_details_locator_path'; + +export class DatasetQualityDetailsLocatorDefinition + implements LocatorDefinition +{ + public readonly id = DATA_QUALITY_DETAILS_LOCATOR_ID; + + constructor(protected readonly deps: DataQualityLocatorDependencies) {} + + public readonly getLocation = async (params: DataQualityDetailsLocatorParams) => { + const { useHash, managementLocator } = this.deps; + return await constructDatasetQualityDetailsLocatorPath({ + useHash, + managementLocator, + locatorParams: params, + }); + }; +} diff --git a/x-pack/plugins/data_quality/common/locators/dataset_quality_locator.ts b/x-pack/plugins/data_quality/common/locators/dataset_quality_locator.ts index 4bf804955b6bc..5db4980e4f661 100644 --- a/x-pack/plugins/data_quality/common/locators/dataset_quality_locator.ts +++ b/x-pack/plugins/data_quality/common/locators/dataset_quality_locator.ts @@ -5,13 +5,11 @@ * 2.0. */ -import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; +import type { LocatorDefinition } from '@kbn/share-plugin/public'; import { DataQualityLocatorParams, DATA_QUALITY_LOCATOR_ID } from '@kbn/deeplinks-observability'; import { DataQualityLocatorDependencies } from './types'; import { constructDatasetQualityLocatorPath } from './construct_dataset_quality_locator_path'; -export type DatasetQualityLocator = LocatorPublic; - export class DatasetQualityLocatorDefinition implements LocatorDefinition { diff --git a/x-pack/plugins/data_quality/common/locators/index.ts b/x-pack/plugins/data_quality/common/locators/index.ts index 97df9e70698d7..02d91cadb5fdb 100644 --- a/x-pack/plugins/data_quality/common/locators/index.ts +++ b/x-pack/plugins/data_quality/common/locators/index.ts @@ -5,11 +5,6 @@ * 2.0. */ -import { DatasetQualityLocator } from './dataset_quality_locator'; - export * from './dataset_quality_locator'; +export * from './dataset_quality_details_locator'; export * from './types'; - -export interface DataQualityLocators { - datasetQualityLocator: DatasetQualityLocator; -} diff --git a/x-pack/plugins/data_quality/common/url_schema/dataset_quality_detils_url_schema_v1.ts b/x-pack/plugins/data_quality/common/url_schema/dataset_quality_details_url_schema_v1.ts similarity index 100% rename from x-pack/plugins/data_quality/common/url_schema/dataset_quality_detils_url_schema_v1.ts rename to x-pack/plugins/data_quality/common/url_schema/dataset_quality_details_url_schema_v1.ts diff --git a/x-pack/plugins/data_quality/common/url_schema/dataset_quality_url_schema_v1.ts b/x-pack/plugins/data_quality/common/url_schema/dataset_quality_url_schema_v1.ts index 78c4faeca8cd8..08313ddc4860b 100644 --- a/x-pack/plugins/data_quality/common/url_schema/dataset_quality_url_schema_v1.ts +++ b/x-pack/plugins/data_quality/common/url_schema/dataset_quality_url_schema_v1.ts @@ -6,37 +6,7 @@ */ import * as rt from 'io-ts'; -import { degradedFieldRT, tableRT, timeRangeRT } from './common'; - -const integrationRT = rt.strict({ - name: rt.string, - title: rt.string, - version: rt.string, -}); - -const datasetRT = rt.intersection([ - rt.strict({ - rawName: rt.string, - type: rt.string, - name: rt.string, - namespace: rt.string, - }), - rt.exact( - rt.partial({ - integration: integrationRT, - title: rt.string, - }) - ), -]); - -export const flyoutRT = rt.exact( - rt.partial({ - dataset: datasetRT, - insightsTimeRange: timeRangeRT, - breakdownField: rt.string, - degradedFields: degradedFieldRT, - }) -); +import { tableRT, timeRangeRT } from './common'; export const filtersRT = rt.exact( rt.partial({ @@ -54,7 +24,6 @@ export const urlSchemaRT = rt.exact( rt.partial({ v: rt.literal(1), table: tableRT, - flyout: flyoutRT, filters: filtersRT, }) ); diff --git a/x-pack/plugins/data_quality/common/url_schema/index.ts b/x-pack/plugins/data_quality/common/url_schema/index.ts index 0af03b6d503f5..bf984fa73f129 100644 --- a/x-pack/plugins/data_quality/common/url_schema/index.ts +++ b/x-pack/plugins/data_quality/common/url_schema/index.ts @@ -7,4 +7,4 @@ export { DATA_QUALITY_URL_STATE_KEY } from './common'; export * as datasetQualityUrlSchemaV1 from './dataset_quality_url_schema_v1'; -export * as datasetQualityDetailsUrlSchemaV1 from './dataset_quality_detils_url_schema_v1'; +export * as datasetQualityDetailsUrlSchemaV1 from './dataset_quality_details_url_schema_v1'; diff --git a/x-pack/plugins/data_quality/public/plugin.ts b/x-pack/plugins/data_quality/public/plugin.ts index cb217abf86fec..025268848a9a8 100644 --- a/x-pack/plugins/data_quality/public/plugin.ts +++ b/x-pack/plugins/data_quality/public/plugin.ts @@ -16,7 +16,10 @@ import { AppPluginSetupDependencies, } from './types'; import { PLUGIN_ID, PLUGIN_NAME } from '../common'; -import { DatasetQualityLocatorDefinition } from '../common/locators'; +import { + DatasetQualityLocatorDefinition, + DatasetQualityDetailsLocatorDefinition, +} from '../common/locators'; export class DataQualityPlugin implements @@ -67,6 +70,12 @@ export class DataQualityPlugin managementLocator, }) ); + share.url.locators.create( + new DatasetQualityDetailsLocatorDefinition({ + useHash, + managementLocator, + }) + ); } return {}; diff --git a/x-pack/plugins/data_quality/public/routes/dataset_quality/context.tsx b/x-pack/plugins/data_quality/public/routes/dataset_quality/context.tsx index ddd3227fa1a2b..0614ab02db677 100644 --- a/x-pack/plugins/data_quality/public/routes/dataset_quality/context.tsx +++ b/x-pack/plugins/data_quality/public/routes/dataset_quality/context.tsx @@ -44,13 +44,6 @@ export function DatasetQualityContextProvider({ }); datasetQualityController.service.start(); - if (initialState?.flyout?.dataset) { - datasetQualityController.service.send({ - type: 'OPEN_FLYOUT', - dataset: initialState.flyout.dataset, - }); - } - setController(datasetQualityController); const datasetQualityStateSubscription = datasetQualityController.state$.subscribe((state) => { diff --git a/x-pack/plugins/data_quality/public/routes/dataset_quality/url_schema_v1.ts b/x-pack/plugins/data_quality/public/routes/dataset_quality/url_schema_v1.ts index ee7fd8904a593..072acf88aa460 100644 --- a/x-pack/plugins/data_quality/public/routes/dataset_quality/url_schema_v1.ts +++ b/x-pack/plugins/data_quality/public/routes/dataset_quality/url_schema_v1.ts @@ -5,10 +5,7 @@ * 2.0. */ -import { - DatasetQualityFlyoutOptions, - DatasetQualityPublicStateUpdate, -} from '@kbn/dataset-quality-plugin/public/controller/dataset_quality'; +import { DatasetQualityPublicStateUpdate } from '@kbn/dataset-quality-plugin/public/controller/dataset_quality'; import * as rt from 'io-ts'; import { deepCompactObject } from '../../../common/utils/deep_compact_object'; import { datasetQualityUrlSchemaV1 } from '../../../common/url_schema'; @@ -18,7 +15,6 @@ export const getStateFromUrlValue = ( ): DatasetQualityPublicStateUpdate => deepCompactObject({ table: urlValue.table, - flyout: getFlyoutFromUrlValue(urlValue.flyout), filters: urlValue.filters, }); @@ -27,7 +23,6 @@ export const getUrlValueFromState = ( ): datasetQualityUrlSchemaV1.UrlSchema => deepCompactObject({ table: state.table, - flyout: state.flyout, filters: state.filters, v: 1, }); @@ -45,25 +40,3 @@ const stateFromUrlSchemaRT = new rt.Type< export const stateFromUntrustedUrlRT = datasetQualityUrlSchemaV1.urlSchemaRT.pipe(stateFromUrlSchemaRT); - -const getFlyoutFromUrlValue = ( - flyout?: datasetQualityUrlSchemaV1.UrlSchema['flyout'] -): DatasetQualityFlyoutOptions => - deepCompactObject({ - ...(flyout - ? { - ...flyout, - dataset: flyout.dataset - ? { - ...flyout.dataset, - integration: flyout.dataset.integration - ? { - ...flyout.dataset.integration, - datasets: {}, - } - : undefined, - } - : undefined, - } - : {}), - }); diff --git a/x-pack/plugins/data_quality/public/routes/dataset_quality_details/url_schema_v1.ts b/x-pack/plugins/data_quality/public/routes/dataset_quality_details/url_schema_v1.ts index b97d1bb9100eb..551ae51892adf 100644 --- a/x-pack/plugins/data_quality/public/routes/dataset_quality_details/url_schema_v1.ts +++ b/x-pack/plugins/data_quality/public/routes/dataset_quality_details/url_schema_v1.ts @@ -17,6 +17,7 @@ export const getStateFromUrlValue = ( dataStream: urlValue.dataStream, timeRange: urlValue.timeRange, degradedFields: urlValue.degradedFields, + breakdownField: urlValue.breakdownField, }); export const getUrlValueFromState = ( @@ -26,6 +27,7 @@ export const getUrlValueFromState = ( dataStream: state.dataStream, timeRange: state.timeRange, degradedFields: state.degradedFields, + breakdownField: state.breakdownField, v: 1, }); diff --git a/x-pack/plugins/event_log/generated/mappings.json b/x-pack/plugins/event_log/generated/mappings.json index 98908f516fc96..5fc8128baa7ae 100644 --- a/x-pack/plugins/event_log/generated/mappings.json +++ b/x-pack/plugins/event_log/generated/mappings.json @@ -482,6 +482,10 @@ "type": "keyword", "ignore_above": 1024 }, + "type_id": { + "type": "keyword", + "ignore_above": 1024 + }, "execution": { "properties": { "source": { @@ -508,6 +512,13 @@ } } } + }, + "usage": { + "properties": { + "request_body_bytes": { + "type": "long" + } + } } } } diff --git a/x-pack/plugins/event_log/generated/schemas.ts b/x-pack/plugins/event_log/generated/schemas.ts index f8db21105539e..7542d6db5213a 100644 --- a/x-pack/plugins/event_log/generated/schemas.ts +++ b/x-pack/plugins/event_log/generated/schemas.ts @@ -212,6 +212,7 @@ export const EventSchema = schema.maybe( schema.object({ name: ecsString(), id: ecsString(), + type_id: ecsString(), execution: schema.maybe( schema.object({ source: ecsString(), @@ -227,6 +228,11 @@ export const EventSchema = schema.maybe( ), }) ), + usage: schema.maybe( + schema.object({ + request_body_bytes: ecsStringOrNumber(), + }) + ), }) ), }) diff --git a/x-pack/plugins/event_log/scripts/mappings.js b/x-pack/plugins/event_log/scripts/mappings.js index aa91f7fc5c2d6..770f9e6d45f9a 100644 --- a/x-pack/plugins/event_log/scripts/mappings.js +++ b/x-pack/plugins/event_log/scripts/mappings.js @@ -257,6 +257,10 @@ exports.EcsCustomPropertyMappings = { type: 'keyword', ignore_above: 1024, }, + type_id: { + type: 'keyword', + ignore_above: 1024, + }, execution: { properties: { source: { @@ -284,6 +288,13 @@ exports.EcsCustomPropertyMappings = { }, }, }, + usage: { + properties: { + request_body_bytes: { + type: 'long', + }, + }, + }, }, }, }, diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index 502d3b603f159..fb5ef4ca3ae8d 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -24,7 +24,6 @@ const _allowedExperimentalValues = { agentless: false, enableStrictKQLValidation: true, subfeaturePrivileges: false, - enablePackagesStateMachine: true, advancedPolicySettings: true, useSpaceAwareness: false, enableReusableIntegrationPolicies: true, diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index ac69f0c673289..e639b364343d9 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -118,6 +118,7 @@ export interface FullAgentPolicyMonitoring { enabled: boolean; metrics: boolean; logs: boolean; + traces: boolean; } export interface FullAgentPolicy { 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 437051f03398f..7aebd9aa66869 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 @@ -301,7 +301,7 @@ export const AgentDiagnosticsTab: React.FunctionComponent

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 9ea94aaeb134a..345ea800dffe6 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/server/integration_tests/cloud_preconfiguration.test.ts b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts index 72335f2c94f31..5ffe6b643f77d 100644 --- a/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/integration_tests/cloud_preconfiguration.test.ts @@ -172,6 +172,7 @@ describe('Fleet cloud preconfiguration', () => { enabled: false, logs: false, metrics: false, + traces: false, }, protection: { enabled: false, diff --git a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap index 8518e43fdaf0d..d5ae12c00a9ff 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap +++ b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/full_agent_policy.test.ts.snap @@ -11,6 +11,7 @@ Object { "enabled": false, "logs": false, "metrics": false, + "traces": false, }, "protection": Object { "enabled": false, @@ -180,6 +181,7 @@ Object { "logs": false, "metrics": true, "namespace": "default", + "traces": false, "use_output": "default", }, "protection": Object { @@ -258,6 +260,7 @@ Object { "logs": false, "metrics": true, "namespace": "default", + "traces": false, "use_output": "monitoring-output-id", }, "protection": Object { @@ -336,6 +339,7 @@ Object { "logs": false, "metrics": true, "namespace": "default", + "traces": false, "use_output": "monitoring-output-id", }, "protection": Object { diff --git a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/monitoring_permissions.test.ts.snap b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/monitoring_permissions.test.ts.snap index fc854fd3b774f..91234c443ab76 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/monitoring_permissions.test.ts.snap +++ b/x-pack/plugins/fleet/server/services/agent_policies/__snapshots__/monitoring_permissions.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`getMonitoringPermissions With elastic agent package installed should return default logs and metrics permissions if both are enabled 1`] = ` +exports[`getMonitoringPermissions With elastic agent package installed should return default logs permissions if only logs are enabled 1`] = ` Object { "_elastic_agent_monitoring": Object { "indices": Array [ @@ -15,16 +15,25 @@ Object { }, Object { "names": Array [ - "metrics-elastic_agent.metricbeat-testnamespace123", + "logs-elastic_agent.filebeat-testnamespace123", ], "privileges": Array [ "auto_configure", "create_doc", ], }, + ], + }, +} +`; + +exports[`getMonitoringPermissions With elastic agent package installed should return default logs, metrics, traces permissions if all are enabled 1`] = ` +Object { + "_elastic_agent_monitoring": Object { + "indices": Array [ Object { "names": Array [ - "logs-elastic_agent.filebeat-testnamespace123", + "logs-elastic_agent.metricbeat-testnamespace123", ], "privileges": Array [ "auto_configure", @@ -33,25 +42,16 @@ Object { }, Object { "names": Array [ - "metrics-elastic_agent.filebeat-testnamespace123", + "metrics-elastic_agent.metricbeat-testnamespace123", ], "privileges": Array [ "auto_configure", "create_doc", ], }, - ], - }, -} -`; - -exports[`getMonitoringPermissions With elastic agent package installed should return default logs permissions if only logs are enabled 1`] = ` -Object { - "_elastic_agent_monitoring": Object { - "indices": Array [ Object { "names": Array [ - "logs-elastic_agent.metricbeat-testnamespace123", + "logs-elastic_agent.filebeat-testnamespace123", ], "privileges": Array [ "auto_configure", @@ -60,7 +60,7 @@ Object { }, Object { "names": Array [ - "logs-elastic_agent.filebeat-testnamespace123", + "metrics-elastic_agent.filebeat-testnamespace123", ], "privileges": Array [ "auto_configure", @@ -99,7 +99,15 @@ Object { } `; -exports[`getMonitoringPermissions Without elastic agent package installed should return default logs and metrics permissions if both are enabled 1`] = ` +exports[`getMonitoringPermissions With elastic agent package installed should return default traces permissions if only traces are enabled 1`] = ` +Object { + "_elastic_agent_monitoring": Object { + "indices": Array [], + }, +} +`; + +exports[`getMonitoringPermissions Without elastic agent package installed should return default logs permissions if only logs are enabled 1`] = ` Object { "_elastic_agent_monitoring": Object { "indices": Array [ @@ -122,23 +130,6 @@ Object { "logs-elastic_agent.pf_host_agent-testnamespace123", "logs-elastic_agent.pf_elastic_collector-testnamespace123", "logs-elastic_agent.pf_elastic_symbolizer-testnamespace123", - "metrics-elastic_agent-testnamespace123", - "metrics-elastic_agent.elastic_agent-testnamespace123", - "metrics-elastic_agent.apm_server-testnamespace123", - "metrics-elastic_agent.filebeat-testnamespace123", - "metrics-elastic_agent.filebeat_input-testnamespace123", - "metrics-elastic_agent.fleet_server-testnamespace123", - "metrics-elastic_agent.metricbeat-testnamespace123", - "metrics-elastic_agent.osquerybeat-testnamespace123", - "metrics-elastic_agent.packetbeat-testnamespace123", - "metrics-elastic_agent.endpoint_security-testnamespace123", - "metrics-elastic_agent.auditbeat-testnamespace123", - "metrics-elastic_agent.heartbeat-testnamespace123", - "metrics-elastic_agent.cloudbeat-testnamespace123", - "metrics-elastic_agent.cloud_defend-testnamespace123", - "metrics-elastic_agent.pf_host_agent-testnamespace123", - "metrics-elastic_agent.pf_elastic_collector-testnamespace123", - "metrics-elastic_agent.pf_elastic_symbolizer-testnamespace123", ], "privileges": Array [ "auto_configure", @@ -150,7 +141,7 @@ Object { } `; -exports[`getMonitoringPermissions Without elastic agent package installed should return default logs permissions if only logs are enabled 1`] = ` +exports[`getMonitoringPermissions Without elastic agent package installed should return default logs, metrics, traces permissions if all are enabled 1`] = ` Object { "_elastic_agent_monitoring": Object { "indices": Array [ @@ -173,6 +164,40 @@ Object { "logs-elastic_agent.pf_host_agent-testnamespace123", "logs-elastic_agent.pf_elastic_collector-testnamespace123", "logs-elastic_agent.pf_elastic_symbolizer-testnamespace123", + "metrics-elastic_agent-testnamespace123", + "metrics-elastic_agent.elastic_agent-testnamespace123", + "metrics-elastic_agent.apm_server-testnamespace123", + "metrics-elastic_agent.filebeat-testnamespace123", + "metrics-elastic_agent.filebeat_input-testnamespace123", + "metrics-elastic_agent.fleet_server-testnamespace123", + "metrics-elastic_agent.metricbeat-testnamespace123", + "metrics-elastic_agent.osquerybeat-testnamespace123", + "metrics-elastic_agent.packetbeat-testnamespace123", + "metrics-elastic_agent.endpoint_security-testnamespace123", + "metrics-elastic_agent.auditbeat-testnamespace123", + "metrics-elastic_agent.heartbeat-testnamespace123", + "metrics-elastic_agent.cloudbeat-testnamespace123", + "metrics-elastic_agent.cloud_defend-testnamespace123", + "metrics-elastic_agent.pf_host_agent-testnamespace123", + "metrics-elastic_agent.pf_elastic_collector-testnamespace123", + "metrics-elastic_agent.pf_elastic_symbolizer-testnamespace123", + "traces-elastic_agent-testnamespace123", + "traces-elastic_agent.elastic_agent-testnamespace123", + "traces-elastic_agent.apm_server-testnamespace123", + "traces-elastic_agent.filebeat-testnamespace123", + "traces-elastic_agent.filebeat_input-testnamespace123", + "traces-elastic_agent.fleet_server-testnamespace123", + "traces-elastic_agent.metricbeat-testnamespace123", + "traces-elastic_agent.osquerybeat-testnamespace123", + "traces-elastic_agent.packetbeat-testnamespace123", + "traces-elastic_agent.endpoint_security-testnamespace123", + "traces-elastic_agent.auditbeat-testnamespace123", + "traces-elastic_agent.heartbeat-testnamespace123", + "traces-elastic_agent.cloudbeat-testnamespace123", + "traces-elastic_agent.cloud_defend-testnamespace123", + "traces-elastic_agent.pf_host_agent-testnamespace123", + "traces-elastic_agent.pf_elastic_collector-testnamespace123", + "traces-elastic_agent.pf_elastic_symbolizer-testnamespace123", ], "privileges": Array [ "auto_configure", @@ -217,3 +242,37 @@ Object { }, } `; + +exports[`getMonitoringPermissions Without elastic agent package installed should return default traces permissions if only traces are enabled 1`] = ` +Object { + "_elastic_agent_monitoring": Object { + "indices": Array [ + Object { + "names": Array [ + "traces-elastic_agent-testnamespace123", + "traces-elastic_agent.elastic_agent-testnamespace123", + "traces-elastic_agent.apm_server-testnamespace123", + "traces-elastic_agent.filebeat-testnamespace123", + "traces-elastic_agent.filebeat_input-testnamespace123", + "traces-elastic_agent.fleet_server-testnamespace123", + "traces-elastic_agent.metricbeat-testnamespace123", + "traces-elastic_agent.osquerybeat-testnamespace123", + "traces-elastic_agent.packetbeat-testnamespace123", + "traces-elastic_agent.endpoint_security-testnamespace123", + "traces-elastic_agent.auditbeat-testnamespace123", + "traces-elastic_agent.heartbeat-testnamespace123", + "traces-elastic_agent.cloudbeat-testnamespace123", + "traces-elastic_agent.cloud_defend-testnamespace123", + "traces-elastic_agent.pf_host_agent-testnamespace123", + "traces-elastic_agent.pf_elastic_collector-testnamespace123", + "traces-elastic_agent.pf_elastic_symbolizer-testnamespace123", + ], + "privileges": Array [ + "auto_configure", + "create_doc", + ], + }, + ], + }, +} +`; diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts index 6a084b5dde586..d2ff49b04e340 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.test.ts @@ -221,6 +221,7 @@ describe('getFullAgentPolicy', () => { enabled: false, logs: false, metrics: false, + traces: false, }, }, }); @@ -257,6 +258,7 @@ describe('getFullAgentPolicy', () => { enabled: true, logs: true, metrics: false, + traces: false, }, }, }); @@ -293,12 +295,50 @@ describe('getFullAgentPolicy', () => { enabled: true, logs: false, metrics: true, + traces: false, }, }, }); }); - it('should return a policy with monitoring enabled but no logs/metrics if keep_monitoring_alive is true', async () => { + it('should return a policy with monitoring if monitoring is enabled for traces', async () => { + mockAgentPolicy({ + namespace: 'default', + revision: 1, + monitoring_enabled: ['traces'], + }); + const agentPolicy = await getFullAgentPolicy(savedObjectsClientMock.create(), 'agent-policy'); + + expect(agentPolicy).toMatchObject({ + id: 'agent-policy', + outputs: { + default: { + type: 'elasticsearch', + hosts: ['http://127.0.0.1:9201'], + }, + }, + inputs: [], + revision: 1, + fleet: { + hosts: ['http://fleetserver:8220'], + }, + agent: { + download: { + sourceURI: 'http://default-registry.co', + }, + monitoring: { + namespace: 'default', + use_output: 'default', + enabled: true, + logs: false, + metrics: false, + traces: true, + }, + }, + }); + }); + + it('should return a policy with monitoring enabled but no logs/metrics/traces if keep_monitoring_alive is true', async () => { mockAgentPolicy({ keep_monitoring_alive: true, }); @@ -309,6 +349,7 @@ describe('getFullAgentPolicy', () => { enabled: true, logs: false, metrics: false, + traces: false, }); }); @@ -325,6 +366,7 @@ describe('getFullAgentPolicy', () => { { logs: false, metrics: true, + traces: false, }, 'testnamespace' ); @@ -553,6 +595,7 @@ describe('getFullAgentPolicy', () => { enabled: true, logs: false, metrics: true, + traces: false, }, }, }); @@ -590,6 +633,7 @@ describe('getFullAgentPolicy', () => { enabled: true, logs: false, metrics: true, + traces: false, }, features: { fqdn: { @@ -743,6 +787,7 @@ describe('getFullAgentPolicy', () => { enabled: false, logs: false, metrics: false, + traces: false, }, }, fleet: { diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts index a65b4ce8dc9fd..d00721f08a3d9 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -140,12 +140,13 @@ export async function getFullAgentPolicy( enabled: false, logs: false, metrics: false, + traces: false, }; let monitoring: FullAgentPolicyMonitoring = { ...defaultMonitoringConfig }; - // If the agent policy has monitoring enabled for at least one of "logs" or "metrics", generate - // a monitoring config for the resulting compiled agent policy + // If the agent policy has monitoring enabled for at least one of "logs", "metrics", or "traces" + // generate a monitoring config for the resulting compiled agent policy if (agentPolicy.monitoring_enabled && agentPolicy.monitoring_enabled.length > 0) { monitoring = { namespace: agentPolicy.namespace, @@ -153,6 +154,7 @@ export async function getFullAgentPolicy( enabled: true, logs: agentPolicy.monitoring_enabled.includes(dataTypes.Logs), metrics: agentPolicy.monitoring_enabled.includes(dataTypes.Metrics), + traces: agentPolicy.monitoring_enabled.includes(dataTypes.Traces), }; // If the `keep_monitoring_alive` flag is set, enable monitoring but don't enable logs or metrics. // This allows cloud or other environments to keep the monitoring server alive without tearing it down. @@ -161,6 +163,7 @@ export async function getFullAgentPolicy( enabled: true, logs: false, metrics: false, + traces: false, }; } @@ -249,6 +252,7 @@ export async function getFullAgentPolicy( { logs: agentPolicy.monitoring_enabled?.includes(dataTypes.Logs) ?? false, metrics: agentPolicy.monitoring_enabled?.includes(dataTypes.Metrics) ?? false, + traces: agentPolicy.monitoring_enabled?.includes(dataTypes.Traces) ?? false, }, agentPolicy.namespace ); diff --git a/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.test.ts index f336fd093c3af..0f72997cc3f2c 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.test.ts @@ -19,10 +19,10 @@ const mockedGetPackageInfo = getPackageInfo as jest.Mock { describe('Without elastic agent package installed', () => { - it('should return default logs and metrics permissions if both are enabled', async () => { + it('should return default logs, metrics, traces permissions if all are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: true, metrics: true }, + { logs: true, metrics: true, traces: true }, 'testnamespace123' ); expect(permissions).toMatchSnapshot(); @@ -30,7 +30,7 @@ describe('getMonitoringPermissions', () => { it('should return default logs permissions if only logs are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: true, metrics: false }, + { logs: true, metrics: false, traces: false }, 'testnamespace123' ); expect(permissions).toMatchSnapshot(); @@ -38,16 +38,24 @@ describe('getMonitoringPermissions', () => { it('should return default metrics permissions if only metrics are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: false, metrics: true }, + { logs: false, metrics: true, traces: false }, + 'testnamespace123' + ); + expect(permissions).toMatchSnapshot(); + }); + it('should return default traces permissions if only traces are enabled', async () => { + const permissions = await getMonitoringPermissions( + savedObjectsClientMock.create(), + { logs: false, metrics: false, traces: true }, 'testnamespace123' ); expect(permissions).toMatchSnapshot(); }); - it('should an empty valid permission entry if neither metrics and logs are enabled', async () => { + it('should an empty valid permission entry if neither metrics, logs, nor traces are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: false, metrics: false }, + { logs: false, metrics: false, traces: false }, 'testnamespace123' ); expect(permissions).toEqual({ _elastic_agent_monitoring: { indices: [] } }); @@ -82,10 +90,10 @@ describe('getMonitoringPermissions', () => { ], } as PackageInfo); }); - it('should return default logs and metrics permissions if both are enabled', async () => { + it('should return default logs, metrics, traces permissions if all are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: true, metrics: true }, + { logs: true, metrics: true, traces: true }, 'testnamespace123' ); expect(permissions).toMatchSnapshot(); @@ -93,7 +101,7 @@ describe('getMonitoringPermissions', () => { it('should return default logs permissions if only logs are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: true, metrics: false }, + { logs: true, metrics: false, traces: false }, 'testnamespace123' ); expect(permissions).toMatchSnapshot(); @@ -101,7 +109,15 @@ describe('getMonitoringPermissions', () => { it('should return default metrics permissions if only metrics are enabled', async () => { const permissions = await getMonitoringPermissions( savedObjectsClientMock.create(), - { logs: false, metrics: true }, + { logs: false, metrics: true, traces: false }, + 'testnamespace123' + ); + expect(permissions).toMatchSnapshot(); + }); + it('should return default traces permissions if only traces are enabled', async () => { + const permissions = await getMonitoringPermissions( + savedObjectsClientMock.create(), + { logs: false, metrics: false, traces: true }, 'testnamespace123' ); expect(permissions).toMatchSnapshot(); diff --git a/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.ts b/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.ts index 0729367c2b65b..e03a8e19eb120 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/monitoring_permissions.ts @@ -18,7 +18,10 @@ import { dataTypes } from '../../../common/constants'; import { getDataStreamPrivileges } from './package_policies_to_agent_permissions'; -function buildDefault(enabled: { logs: boolean; metrics: boolean }, namespace: string) { +function buildDefault( + enabled: { logs: boolean; metrics: boolean; traces: boolean }, + namespace: string +) { let names: string[] = []; if (enabled.logs) { names = names.concat( @@ -30,6 +33,11 @@ function buildDefault(enabled: { logs: boolean; metrics: boolean }, namespace: s AGENT_POLICY_DEFAULT_MONITORING_DATASETS.map((dataset) => `metrics-${dataset}-${namespace}`) ); } + if (enabled.traces) { + names = names.concat( + AGENT_POLICY_DEFAULT_MONITORING_DATASETS.map((dataset) => `traces-${dataset}-${namespace}`) + ); + } if (names.length === 0) { return { @@ -53,7 +61,7 @@ function buildDefault(enabled: { logs: boolean; metrics: boolean }, namespace: s export async function getMonitoringPermissions( soClient: SavedObjectsClientContract, - enabled: { logs: boolean; metrics: boolean }, + enabled: { logs: boolean; metrics: boolean; traces: boolean }, namespace: string ): Promise { const installation = await getInstallation({ @@ -85,6 +93,9 @@ export async function getMonitoringPermissions( if (ds.type === dataTypes.Metrics && !enabled.metrics) { return; } + if (ds.type === dataTypes.Traces && !enabled.traces) { + return; + } return getDataStreamPrivileges(ds, namespace); }) .filter( diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts index 53112c5eea673..c6692b55b7efe 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.test.ts @@ -179,426 +179,211 @@ describe('install', () => { }); describe('registry', () => { - describe('with enablePackagesStateMachine = false', () => { - beforeEach(() => { - mockGetBundledPackageByPkgKey.mockResolvedValue(undefined); - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - enablePackagesStateMachine: false, - } as any); - }); + beforeEach(() => { + mockGetBundledPackageByPkgKey.mockResolvedValue(undefined); + }); + afterEach(() => { + (install._installPackage as jest.Mock).mockClear(); + }); - it('should send telemetry on install failure, out of date', async () => { - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.1.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - errorMessage: 'apache-1.1.0 is out-of-date and cannot be installed or updated', - eventType: 'package-install', - installType: 'install', - newVersion: '1.1.0', - packageName: 'apache', - status: 'failure', - }); + it('should send telemetry on install failure, out of date', async () => { + await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'apache-1.1.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should send telemetry on install failure, license error', async () => { - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - errorMessage: 'Installation requires basic license', - eventType: 'package-install', - installType: 'install', - newVersion: '1.3.0', - packageName: 'apache', - status: 'failure', - }); + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'apache-1.1.0 is out-of-date and cannot be installed or updated', + eventType: 'package-install', + installType: 'install', + newVersion: '1.1.0', + packageName: 'apache', + status: 'failure', }); + }); - it('should send telemetry on install success', async () => { - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - eventType: 'package-install', - installType: 'install', - newVersion: '1.3.0', - packageName: 'apache', - status: 'success', - }); + it('should send telemetry on install failure, license error', async () => { + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); + await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should send telemetry on update success', async () => { - jest - .mocked(getInstallationObject) - .mockResolvedValueOnce({ attributes: { version: '1.2.0' } } as any); - - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: '1.2.0', - dryRun: false, - eventType: 'package-install', - installType: 'update', - newVersion: '1.3.0', - packageName: 'apache', - status: 'success', - }); + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'Installation requires basic license', + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'failure', }); + }); - it('should send telemetry on install failure, async error', async () => { - jest.mocked(install._installPackage).mockRejectedValue(new Error('error')); - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - errorMessage: 'error', - eventType: 'package-install', - installType: 'install', - newVersion: '1.3.0', - packageName: 'apache', - status: 'failure', - }); + it('should send telemetry on install success', async () => { + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should install from bundled package if one exists', async () => { - (install._installPackage as jest.Mock).mockResolvedValue({}); - mockGetBundledPackageByPkgKey.mockResolvedValue({ - name: 'test_package', - version: '1.0.0', - getBuffer: async () => Buffer.from('test_package'), - }); - - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'test_package-1.0.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.error).toBeUndefined(); - - expect(install._installPackage).toHaveBeenCalledWith( - expect.objectContaining({ installSource: 'bundled' }) - ); + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'success', }); + }); - it('should fetch latest version if version not provided', async () => { - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'test_package', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.status).toEqual('installed'); - - expect(sendTelemetryEvents).toHaveBeenCalledWith( - expect.anything(), - undefined, - expect.objectContaining({ - newVersion: '1.3.0', - }) - ); - }); + it('should send telemetry on update success', async () => { + jest + .mocked(getInstallationObject) + .mockResolvedValueOnce({ attributes: { version: '1.2.0', installed_kibana: [] } } as any); - it('should do nothing if same version is installed', async () => { - jest.mocked(getInstallationObject).mockResolvedValueOnce({ - attributes: { - version: '1.2.0', - install_status: 'installed', - installed_es: [], - installed_kibana: [], - }, - } as any); - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.2.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.status).toEqual('already_installed'); + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should allow to install fleet_server if internal.fleetServerStandalone is configured', async () => { - jest.mocked(appContextService.getConfig).mockReturnValueOnce({ - internal: { - fleetServerStandalone: true, - }, - } as any); - - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'fleet_server-2.0.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.status).toEqual('installed'); + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: '1.2.0', + dryRun: false, + eventType: 'package-install', + installType: 'update', + newVersion: '1.3.0', + packageName: 'apache', + status: 'success', }); }); - describe('with enablePackagesStateMachine = true', () => { - beforeEach(() => { - mockGetBundledPackageByPkgKey.mockResolvedValue(undefined); - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - enablePackagesStateMachine: true, - } as any); - }); - afterEach(() => { - (install._installPackage as jest.Mock).mockClear(); - }); - afterAll(() => { - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - enablePackagesStateMachine: false, - } as any); - }); + it('should send telemetry on install failure, async error', async () => { + jest + .mocked(installStateMachine._stateMachineInstallPackage) + .mockRejectedValue(new Error('error')); + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - it('should send telemetry on install failure, out of date', async () => { - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.1.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - errorMessage: 'apache-1.1.0 is out-of-date and cannot be installed or updated', - eventType: 'package-install', - installType: 'install', - newVersion: '1.1.0', - packageName: 'apache', - status: 'failure', - }); + await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'apache-1.3.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should send telemetry on install failure, license error', async () => { - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(false); - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - errorMessage: 'Installation requires basic license', - eventType: 'package-install', - installType: 'install', - newVersion: '1.3.0', - packageName: 'apache', - status: 'failure', - }); + expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { + currentVersion: 'not_installed', + dryRun: false, + errorMessage: 'error', + eventType: 'package-install', + installType: 'install', + newVersion: '1.3.0', + packageName: 'apache', + status: 'failure', }); + }); - it('should send telemetry on install success', async () => { - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - eventType: 'package-install', - installType: 'install', - newVersion: '1.3.0', - packageName: 'apache', - status: 'success', - }); + it('should install from bundled package if one exists', async () => { + (installStateMachine._stateMachineInstallPackage as jest.Mock).mockResolvedValue({}); + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + mockGetBundledPackageByPkgKey.mockResolvedValue({ + name: 'test_package', + version: '1.0.0', + getBuffer: async () => Buffer.from('test_package'), }); - it('should send telemetry on update success', async () => { - jest - .mocked(getInstallationObject) - .mockResolvedValueOnce({ attributes: { version: '1.2.0', installed_kibana: [] } } as any); - - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: '1.2.0', - dryRun: false, - eventType: 'package-install', - installType: 'update', - newVersion: '1.3.0', - packageName: 'apache', - status: 'success', - }); + const response = await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'test_package-1.0.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should send telemetry on install failure, async error', async () => { - jest - .mocked(installStateMachine._stateMachineInstallPackage) - .mockRejectedValue(new Error('error')); - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - - await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.3.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(sendTelemetryEvents).toHaveBeenCalledWith(expect.anything(), undefined, { - currentVersion: 'not_installed', - dryRun: false, - errorMessage: 'error', - eventType: 'package-install', - installType: 'install', - newVersion: '1.3.0', - packageName: 'apache', - status: 'failure', - }); - }); + expect(response.error).toBeUndefined(); - it('should install from bundled package if one exists', async () => { - (installStateMachine._stateMachineInstallPackage as jest.Mock).mockResolvedValue({}); - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - mockGetBundledPackageByPkgKey.mockResolvedValue({ - name: 'test_package', - version: '1.0.0', - getBuffer: async () => Buffer.from('test_package'), - }); - - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'test_package-1.0.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.error).toBeUndefined(); - - expect(install._installPackage).toHaveBeenCalledWith( - expect.objectContaining({ installSource: 'bundled' }) - ); - }); + expect(install._installPackage).toHaveBeenCalledWith( + expect.objectContaining({ installSource: 'bundled' }) + ); + }); - it('should fetch latest version if version not provided', async () => { - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'test_package', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.status).toEqual('installed'); - - expect(sendTelemetryEvents).toHaveBeenCalledWith( - expect.anything(), - undefined, - expect.objectContaining({ - newVersion: '1.3.0', - }) - ); + it('should fetch latest version if version not provided', async () => { + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + const response = await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'test_package', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - it('should do nothing if same version is installed', async () => { - jest.mocked(getInstallationObject).mockResolvedValueOnce({ - attributes: { - version: '1.2.0', - install_status: 'installed', - installed_es: [], - installed_kibana: [], - }, - } as any); - jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'apache-1.2.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); - - expect(response.status).toEqual('already_installed'); + expect(response.status).toEqual('installed'); + + expect(sendTelemetryEvents).toHaveBeenCalledWith( + expect.anything(), + undefined, + expect.objectContaining({ + newVersion: '1.3.0', + }) + ); + }); + + it('should do nothing if same version is installed', async () => { + jest.mocked(getInstallationObject).mockResolvedValueOnce({ + attributes: { + version: '1.2.0', + install_status: 'installed', + installed_es: [], + installed_kibana: [], + }, + } as any); + jest.spyOn(licenseService, 'hasAtLeast').mockReturnValue(true); + const response = await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'apache-1.2.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); - // failing - it('should allow to install fleet_server if internal.fleetServerStandalone is configured', async () => { - jest.mocked(appContextService.getConfig).mockReturnValueOnce({ - internal: { - fleetServerStandalone: true, - }, - } as any); + expect(response.status).toEqual('already_installed'); + }); - const response = await installPackage({ - spaceId: DEFAULT_SPACE_ID, - installSource: 'registry', - pkgkey: 'fleet_server-2.0.0', - savedObjectsClient: savedObjectsClientMock.create(), - esClient: {} as ElasticsearchClient, - }); + // failing + it('should allow to install fleet_server if internal.fleetServerStandalone is configured', async () => { + jest.mocked(appContextService.getConfig).mockReturnValueOnce({ + internal: { + fleetServerStandalone: true, + }, + } as any); - expect(response.status).toEqual('installed'); + const response = await installPackage({ + spaceId: DEFAULT_SPACE_ID, + installSource: 'registry', + pkgkey: 'fleet_server-2.0.0', + savedObjectsClient: savedObjectsClientMock.create(), + esClient: {} as ElasticsearchClient, }); + + expect(response.status).toEqual('installed'); }); }); @@ -772,6 +557,7 @@ describe('handleInstallPackageFailure', () => { beforeEach(() => { mockedLogger.error.mockClear(); jest.mocked(install._installPackage).mockClear(); + jest.mocked(installStateMachine._stateMachineInstallPackage).mockClear(); mockGetBundledPackageByPkgKey.mockReset(); jest.mocked(install._installPackage).mockResolvedValue({} as any); @@ -858,8 +644,8 @@ describe('handleInstallPackageFailure', () => { expect(mockedLogger.error).toBeCalledWith( 'rolling back to test_package-1.0.0 after error installing test_package-2.0.0' ); - expect(install._installPackage).toBeCalledTimes(1); - expect(install._installPackage).toBeCalledWith( + expect(installStateMachine._stateMachineInstallPackage).toBeCalledTimes(1); + expect(installStateMachine._stateMachineInstallPackage).toBeCalledWith( expect.objectContaining({ packageInstallContext: expect.objectContaining({ packageInfo: expect.objectContaining({ name: pkgName, version: '1.0.0' }), @@ -870,7 +656,9 @@ describe('handleInstallPackageFailure', () => { }); it('Should update the installation status to: install_failed on rollback error', async () => { - jest.mocked(install._installPackage).mockRejectedValue(new Error('test error')); + jest + .mocked(installStateMachine._stateMachineInstallPackage) + .mockRejectedValue(new Error('test error')); const installedPkg: SavedObject = { id: 'test-package', @@ -904,8 +692,8 @@ describe('handleInstallPackageFailure', () => { expect(mockedLogger.error).toBeCalledWith( expect.stringMatching(/failed to uninstall or rollback package after installation error/) ); - expect(install._installPackage).toBeCalledTimes(1); - expect(install._installPackage).toBeCalledWith( + expect(installStateMachine._stateMachineInstallPackage).toBeCalledTimes(1); + expect(installStateMachine._stateMachineInstallPackage).toBeCalledWith( expect.objectContaining({ packageInstallContext: expect.objectContaining({ packageInfo: expect.objectContaining({ name: pkgName, version: '1.0.0' }), diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install.ts b/x-pack/plugins/fleet/server/services/epm/packages/install.ts index ce406773a0635..8311cba09b8ff 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install.ts @@ -482,44 +482,23 @@ async function installPackageFromRegistry({ }` ); } - const { enablePackagesStateMachine } = appContextService.getExperimentalFeatures(); - if (enablePackagesStateMachine) { - return await installPackageWitStateMachine({ - pkgName, - pkgVersion, - installSource, - installedPkg, - installType, - savedObjectsClient, - esClient, - spaceId, - force, - packageInstallContext, - paths, - verificationResult, - authorizationHeader, - ignoreMappingUpdateErrors, - skipDataStreamRollover, - }); - } else { - return await installPackageCommon({ - pkgName, - pkgVersion, - installSource, - installedPkg, - installType, - savedObjectsClient, - esClient, - spaceId, - force, - packageInstallContext, - paths, - verificationResult, - authorizationHeader, - ignoreMappingUpdateErrors, - skipDataStreamRollover, - }); - } + return await installPackageWitStateMachine({ + pkgName, + pkgVersion, + installSource, + installedPkg, + installType, + savedObjectsClient, + esClient, + spaceId, + force, + packageInstallContext, + paths, + verificationResult, + authorizationHeader, + ignoreMappingUpdateErrors, + skipDataStreamRollover, + }); } catch (e) { sendEvent({ ...telemetryEvent, @@ -738,7 +717,7 @@ async function installPackageWitStateMachine(options: { let { telemetryEvent } = options; const logger = appContextService.getLogger(); logger.info( - `Install with enablePackagesStateMachine - Starting installation of ${pkgName}@${pkgVersion} from ${installSource} ` + `Install with state machine - Starting installation of ${pkgName}@${pkgVersion} from ${installSource} ` ); // Workaround apm issue with async spans: https://github.com/elastic/apm-agent-nodejs/issues/2611 @@ -956,6 +935,7 @@ async function installPackageByUpload({ // update the timestamp of latest installation setLastUploadInstallCache(); + // TODO: use installPackageWithStateMachine instead of installPackageCommon https://github.com/elastic/kibana/issues/189346 return await installPackageCommon({ packageInstallContext, pkgName, @@ -1139,7 +1119,7 @@ export async function installCustomPackage( paths, packageInfo, }; - + // TODO: use installPackageWithStateMachine instead of installPackageCommon https://github.com/elastic/kibana/issues/189347 return await installPackageCommon({ packageInstallContext, pkgName, diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.test.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.test.ts index f6e1f8fba5a20..795440025c7fd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.test.ts @@ -10,29 +10,40 @@ import { appContextService } from '../../..'; import { handleState } from './state_machine'; -const getTestDefinition = ( - mockOnTransition1: any, - mockOnTransition2: any, - mockOnTransition3: any, - context?: any, - onPostTransition?: any -) => { +const getTestDefinition = ({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + mockPostTransition, + mockPreTransition, +}: { + mockOnTransition1: any; + mockOnTransition2: any; + mockOnTransition3: any; + context?: any; + mockPostTransition?: any; + mockPreTransition?: any; +}) => { return { context, states: { state1: { + onPreTransition: mockPreTransition, onTransition: mockOnTransition1, - onPostTransition, + onPostTransition: mockPostTransition, nextState: 'state2', }, state2: { + onPreTransition: mockPreTransition, onTransition: mockOnTransition2, - onPostTransition, + onPostTransition: mockPostTransition, nextState: 'state3', }, state3: { + onPreTransition: mockPreTransition, onTransition: mockOnTransition3, - onPostTransition, + onPostTransition: mockPostTransition, nextState: 'end', }, }, @@ -52,19 +63,19 @@ describe('handleState', () => { }); it('should execute all the state machine transitions based on the provided data structure', async () => { - const mockOnTransitionState1 = jest.fn(); - const mockOnTransitionState2 = jest.fn(); - const mockOnTransitionState3 = jest.fn(); - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3 - ); + const mockOnTransition1 = jest.fn(); + const mockOnTransition2 = jest.fn(); + const mockOnTransition3 = jest.fn(); + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + }); await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledTimes(1); - expect(mockOnTransitionState2).toHaveBeenCalledTimes(1); - expect(mockOnTransitionState3).toHaveBeenCalledTimes(1); + expect(mockOnTransition1).toHaveBeenCalledTimes(1); + expect(mockOnTransition2).toHaveBeenCalledTimes(1); + expect(mockOnTransition3).toHaveBeenCalledTimes(1); expect(mockContract.logger?.debug).toHaveBeenCalledWith( 'Executed state: state1 with status: success - nextState: state2' ); @@ -77,22 +88,22 @@ describe('handleState', () => { }); it('should call the onTransition function with context data and the return value is saved for the next iteration', async () => { - const mockOnTransitionState1 = jest.fn().mockReturnValue({ arrayData: ['test1', 'test2'] }); - const mockOnTransitionState2 = jest + const mockOnTransition1 = jest.fn().mockReturnValue({ arrayData: ['test1', 'test2'] }); + const mockOnTransition2 = jest .fn() .mockImplementation(() => Promise.resolve({ promiseData: {} })); - const mockOnTransitionState3 = jest.fn().mockReturnValue({ lastData: ['test3'] }); - const contextData = { testData: 'test' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition3 = jest.fn().mockReturnValue({ lastData: ['test3'] }); + const context = { testData: 'test' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledWith({ testData: 'test' }); - expect(mockOnTransitionState2).toHaveBeenCalledWith( + expect(mockOnTransition1).toHaveBeenCalledWith({ testData: 'test' }); + expect(mockOnTransition2).toHaveBeenCalledWith( expect.objectContaining({ testData: 'test', arrayData: ['test1', 'test2'], @@ -102,7 +113,7 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState3).toHaveBeenCalledWith( + expect(mockOnTransition3).toHaveBeenCalledWith( expect.objectContaining({ testData: 'test', arrayData: ['test1', 'test2'], @@ -126,27 +137,27 @@ describe('handleState', () => { }); it('should save the return data from transitions also when return type is function', async () => { - const mockOnTransitionState1 = jest.fn().mockReturnValue({ arrayData: ['test1', 'test2'] }); + const mockOnTransition1 = jest.fn().mockReturnValue({ arrayData: ['test1', 'test2'] }); const state2Result = () => { return { result: 'test', }; }; - const mockOnTransitionState2 = jest.fn().mockImplementation(() => { + const mockOnTransition2 = jest.fn().mockImplementation(() => { return state2Result; }); - const mockOnTransitionState3 = jest.fn(); - const contextData = { testData: 'test' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition3 = jest.fn(); + const context = { testData: 'test' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledWith({ testData: 'test' }); - expect(mockOnTransitionState2).toHaveBeenCalledWith( + expect(mockOnTransition1).toHaveBeenCalledWith({ testData: 'test' }); + expect(mockOnTransition2).toHaveBeenCalledWith( expect.objectContaining({ testData: 'test', arrayData: ['test1', 'test2'], @@ -157,7 +168,7 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState3).toHaveBeenCalledWith( + expect(mockOnTransition3).toHaveBeenCalledWith( expect.objectContaining({ testData: 'test', arrayData: ['test1', 'test2'], @@ -181,7 +192,7 @@ describe('handleState', () => { }); it('should return updated context data', async () => { - const mockOnTransitionState1 = jest + const mockOnTransition1 = jest .fn() .mockImplementation(() => Promise.resolve({ promiseData: {} })); const state2Result = () => { @@ -189,21 +200,21 @@ describe('handleState', () => { result: 'test', }; }; - const mockOnTransitionState2 = jest.fn().mockImplementation(() => { + const mockOnTransition2 = jest.fn().mockImplementation(() => { return state2Result; }); - const mockOnTransitionState3 = jest.fn().mockReturnValue({ lastData: ['test3'] }); - const contextData = { testData: 'test' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition3 = jest.fn().mockReturnValue({ lastData: ['test3'] }); + const context = { testData: 'test' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); const updatedContext = await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledWith({ testData: 'test' }); - expect(mockOnTransitionState2).toHaveBeenCalledWith( + expect(mockOnTransition1).toHaveBeenCalledWith({ testData: 'test' }); + expect(mockOnTransition2).toHaveBeenCalledWith( expect.objectContaining({ testData: 'test', promiseData: {}, @@ -214,7 +225,7 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState3).toHaveBeenCalledWith( + expect(mockOnTransition3).toHaveBeenCalledWith( expect.objectContaining({ testData: 'test', promiseData: {}, @@ -241,22 +252,22 @@ describe('handleState', () => { }); it('should update a variable in the context at every call and return the updated value', async () => { - const mockOnTransitionState1 = jest.fn().mockReturnValue({ runningVal: 'test1' }); - const mockOnTransitionState2 = jest + const mockOnTransition1 = jest.fn().mockReturnValue({ runningVal: 'test1' }); + const mockOnTransition2 = jest .fn() .mockImplementation(() => Promise.resolve({ runningVal: 'test2' })); - const mockOnTransitionState3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); - const contextData = { runningVal: [], fixedVal: 'something' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); + const context = { runningVal: [], fixedVal: 'something' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); const updatedContext = await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledWith({ runningVal: [], fixedVal: 'something' }); - expect(mockOnTransitionState2).toHaveBeenCalledWith( + expect(mockOnTransition1).toHaveBeenCalledWith({ runningVal: [], fixedVal: 'something' }); + expect(mockOnTransition2).toHaveBeenCalledWith( expect.objectContaining({ runningVal: 'test1', fixedVal: 'something', @@ -266,7 +277,7 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState3).toHaveBeenCalledWith( + expect(mockOnTransition3).toHaveBeenCalledWith( expect.objectContaining({ runningVal: 'test2', fixedVal: 'something', @@ -289,29 +300,29 @@ describe('handleState', () => { }); it('should execute the transition starting from the provided state', async () => { - const mockOnTransitionState1 = jest.fn().mockReturnValue({ runningVal: 'test1' }); - const mockOnTransitionState2 = jest + const mockOnTransition1 = jest.fn().mockReturnValue({ runningVal: 'test1' }); + const mockOnTransition2 = jest .fn() .mockImplementation(() => Promise.resolve({ runningVal: 'test2' })); - const mockOnTransitionState3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); - const contextData = { runningVal: [], fixedVal: 'something' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); + const context = { runningVal: [], fixedVal: 'something' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); const updatedContext = await handleState('state2', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledTimes(0); - expect(mockOnTransitionState2).toHaveBeenCalledWith( + expect(mockOnTransition1).toHaveBeenCalledTimes(0); + expect(mockOnTransition2).toHaveBeenCalledWith( expect.objectContaining({ runningVal: [], fixedVal: 'something', }) ); - expect(mockOnTransitionState3).toHaveBeenCalledWith( + expect(mockOnTransition3).toHaveBeenCalledWith( expect.objectContaining({ runningVal: 'test2', fixedVal: 'something', @@ -335,46 +346,121 @@ describe('handleState', () => { it('should throw and return updated context with latest error when a state returns error', async () => { const error = new Error('Installation failed'); - const mockOnTransitionState1 = jest.fn().mockRejectedValue(error); - const mockOnTransitionState2 = jest.fn(); - const mockOnTransitionState3 = jest.fn(); - const contextData = { fixedVal: 'something' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition1 = jest.fn().mockRejectedValue(error); + const mockOnTransition2 = jest.fn(); + const mockOnTransition3 = jest.fn(); + const context = { fixedVal: 'something' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); const promise = handleState('state1', testDefinition, testDefinition.context); await expect(promise).rejects.toThrowError('Installation failed'); - expect(mockOnTransitionState1).toHaveBeenCalledTimes(1); - expect(mockOnTransitionState2).toHaveBeenCalledTimes(0); - expect(mockOnTransitionState3).toHaveBeenCalledTimes(0); + expect(mockOnTransition1).toHaveBeenCalledTimes(1); + expect(mockOnTransition2).toHaveBeenCalledTimes(0); + expect(mockOnTransition3).toHaveBeenCalledTimes(0); expect(mockContract.logger?.warn).toHaveBeenCalledWith( 'Error during execution of state "state1" with status "failed": Installation failed' ); }); + it('should execute preTransition function before the transition gets executed', async () => { + const mockOnTransition1 = jest.fn(); + const mockOnTransition2 = jest.fn(); + const mockOnTransition3 = jest.fn(); + const mockPreTransition = jest.fn(); + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + mockPreTransition, + }); + await handleState('state1', testDefinition, testDefinition.context); + + expect(mockPreTransition).toHaveBeenCalled(); + expect(mockOnTransition1).toHaveBeenCalled(); + + expect(mockContract.logger?.debug).toHaveBeenCalledWith( + 'Executing pre transition function: mockConstructor' + ); + }); + + it('should execute preTransition function before the transition gets executed passing the updated context', async () => { + const mockPreTransition = jest.fn().mockReturnValue({ runningVal: 'test1' }); + const mockOnTransition1 = jest.fn(); + const mockOnTransition2 = jest + .fn() + .mockImplementation(() => Promise.resolve({ runningVal: 'test2' })); + const mockOnTransition3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); + const context = { fixedVal: 'something' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + mockPreTransition, + context, + }); + const updatedContext = await handleState('state1', testDefinition, testDefinition.context); + + expect(updatedContext).toEqual( + expect.objectContaining({ + fixedVal: 'something', + runningVal: 'test3', + latestExecutedState: { + name: 'state3', + started_at: expect.anything(), + }, + }) + ); + }); + + it('should throw error and not execute subsequent transitions when onPreTransition throws error', async () => { + const error = new Error('Precondition failed'); + const mockPreTransition = jest.fn().mockRejectedValue(error); + const mockOnTransition1 = jest.fn(); + const mockOnTransition2 = jest.fn(); + + const mockOnTransition3 = jest.fn(); + const context = { fixedVal: 'something' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + mockPreTransition, + context, + }); + + await expect( + handleState('state1', testDefinition, testDefinition.context) + ).rejects.toThrowError('Precondition failed'); + + expect(mockPreTransition).toHaveBeenCalled(); + expect(mockOnTransition1).not.toHaveBeenCalled(); + expect(mockOnTransition2).not.toHaveBeenCalled(); + expect(mockOnTransition3).not.toHaveBeenCalled(); + }); + it('should execute postTransition function after the transition is complete', async () => { - const mockOnTransitionState1 = jest.fn(); - const mockOnTransitionState2 = jest.fn(); - const mockOnTransitionState3 = jest.fn(); + const mockOnTransition1 = jest.fn(); + const mockOnTransition2 = jest.fn(); + const mockOnTransition3 = jest.fn(); const mockPostTransition = jest.fn(); - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - undefined, - mockPostTransition - ); + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + mockPostTransition, + }); await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalled(); + expect(mockOnTransition1).toHaveBeenCalled(); expect(mockPostTransition).toHaveBeenCalled(); - expect(mockOnTransitionState2).toHaveBeenCalled(); + expect(mockOnTransition2).toHaveBeenCalled(); expect(mockPostTransition).toHaveBeenCalled(); - expect(mockOnTransitionState3).toHaveBeenCalled(); + expect(mockOnTransition3).toHaveBeenCalled(); expect(mockPostTransition).toHaveBeenCalled(); expect(mockContract.logger?.debug).toHaveBeenCalledWith( 'Executing post transition function: mockConstructor' @@ -382,27 +468,27 @@ describe('handleState', () => { }); it('should execute postTransition function after the transition passing the updated context', async () => { - const mockOnTransitionState1 = jest.fn().mockReturnValue({ runningVal: 'test1' }); - const mockOnTransitionState2 = jest + const mockOnTransition1 = jest.fn().mockReturnValue({ runningVal: 'test1' }); + const mockOnTransition2 = jest .fn() .mockImplementation(() => Promise.resolve({ runningVal: 'test2' })); - const mockOnTransitionState3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); + const mockOnTransition3 = jest.fn().mockReturnValue({ runningVal: 'test3' }); const mockPostTransition = jest.fn(); - const contextData = { fixedVal: 'something' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData, - mockPostTransition - ); + const context = { fixedVal: 'something' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + mockPostTransition, + }); const updatedContext = await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalled(); + expect(mockOnTransition1).toHaveBeenCalled(); expect(mockPostTransition).toHaveBeenCalled(); - expect(mockOnTransitionState2).toHaveBeenCalled(); + expect(mockOnTransition2).toHaveBeenCalled(); expect(mockPostTransition).toHaveBeenCalled(); - expect(mockOnTransitionState3).toHaveBeenCalled(); + expect(mockOnTransition3).toHaveBeenCalled(); expect(updatedContext).toEqual( expect.objectContaining({ fixedVal: 'something', @@ -421,22 +507,22 @@ describe('handleState', () => { it('should execute postTransition correctly also when a transition throws', async () => { const error = new Error('Installation failed'); - const mockOnTransitionState1 = jest.fn().mockReturnValue({ result1: 'test' }); - const mockOnTransitionState2 = jest.fn().mockRejectedValue(error); - const mockOnTransitionState3 = jest.fn(); + const mockOnTransition1 = jest.fn().mockReturnValue({ result1: 'test' }); + const mockOnTransition2 = jest.fn().mockRejectedValue(error); + const mockOnTransition3 = jest.fn(); const mockPostTransition = jest.fn(); - const contextData = { testData: 'test' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData, - mockPostTransition - ); + const context = { testData: 'test' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + mockPostTransition, + }); const promise = handleState('state1', testDefinition, testDefinition.context); await expect(promise).rejects.toThrowError('Installation failed'); - expect(mockOnTransitionState1).toHaveBeenCalledTimes(1); + expect(mockOnTransition1).toHaveBeenCalledTimes(1); expect(mockPostTransition).toHaveBeenCalledWith( expect.objectContaining({ result1: 'test', @@ -449,7 +535,7 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState2).toHaveBeenCalledTimes(1); + expect(mockOnTransition2).toHaveBeenCalledTimes(1); expect(mockPostTransition).toHaveBeenCalledWith( expect.objectContaining({ result1: 'test', @@ -460,26 +546,26 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState3).toHaveBeenCalledTimes(0); + expect(mockOnTransition3).toHaveBeenCalledTimes(0); }); it('should log a warning when postTransition exits with errors and continue executing the states', async () => { const error = new Error('Installation failed'); - const mockOnTransitionState1 = jest.fn().mockReturnValue({ result1: 'test' }); - const mockOnTransitionState2 = jest.fn(); - const mockOnTransitionState3 = jest.fn(); + const mockOnTransition1 = jest.fn().mockReturnValue({ result1: 'test' }); + const mockOnTransition2 = jest.fn(); + const mockOnTransition3 = jest.fn(); const mockPostTransition = jest.fn().mockRejectedValue(error); - const contextData = { testData: 'test' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData, - mockPostTransition - ); + const context = { testData: 'test' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + mockPostTransition, + }); const updatedContext = await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledTimes(1); + expect(mockOnTransition1).toHaveBeenCalledTimes(1); expect(mockPostTransition).toHaveBeenCalledWith( expect.objectContaining({ result1: 'test', @@ -490,8 +576,8 @@ describe('handleState', () => { }, }) ); - expect(mockOnTransitionState2).toHaveBeenCalledTimes(1); - expect(mockOnTransitionState3).toHaveBeenCalledTimes(1); + expect(mockOnTransition2).toHaveBeenCalledTimes(1); + expect(mockOnTransition3).toHaveBeenCalledTimes(1); expect(mockContract.logger?.warn).toHaveBeenCalledWith( 'Error during execution of post transition function: Installation failed' ); @@ -509,21 +595,21 @@ describe('handleState', () => { }); it('should exit and log a warning when the provided OnTransition is not a function', async () => { - const mockOnTransitionState1 = jest.fn().mockReturnValue({ result1: 'test' }); - const mockOnTransitionState2 = undefined; - const mockOnTransitionState3 = jest.fn(); - - const contextData = { testData: 'test' }; - const testDefinition = getTestDefinition( - mockOnTransitionState1, - mockOnTransitionState2, - mockOnTransitionState3, - contextData - ); + const mockOnTransition1 = jest.fn().mockReturnValue({ result1: 'test' }); + const mockOnTransition2 = undefined; + const mockOnTransition3 = jest.fn(); + + const context = { testData: 'test' }; + const testDefinition = getTestDefinition({ + mockOnTransition1, + mockOnTransition2, + mockOnTransition3, + context, + }); const updatedContext = await handleState('state1', testDefinition, testDefinition.context); - expect(mockOnTransitionState1).toHaveBeenCalledTimes(1); - expect(mockOnTransitionState3).toHaveBeenCalledTimes(0); + expect(mockOnTransition1).toHaveBeenCalledTimes(1); + expect(mockOnTransition3).toHaveBeenCalledTimes(0); expect(mockContract.logger?.warn).toHaveBeenCalledWith( 'Execution of state "state2" with status "failed": provided onTransition is not a valid function' ); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.ts b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.ts index c70a99e272361..4817dccc300a3 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/install_state_machine/state_machine.ts @@ -13,6 +13,7 @@ export interface State { onTransition: any; nextState?: string; currentStatus?: string; + onPreTransition?: any; onPostTransition?: any; } @@ -24,16 +25,19 @@ export type StateMachineStates = Record; * context: {}, * states: { * state1: { + * onPreTransition: onPreTransition, * onTransition: onState1Transition, * onPostTransition: onPostTransition, * nextState: 'state2', * }, * state2: { + * onPreTransition: onPreTransition, * onTransition: onState2Transition, * onPostTransition: onPostTransition,, * nextState: 'state3', * }, * state3: { + * onPreTransition: onPreTransition, * onTransition: onState3Transition, * onPostTransition: onPostTransition, * nextState: 'end', @@ -63,6 +67,10 @@ export async function handleState( let currentStatus = 'pending'; let stateResult; let updatedContext = { ...context }; + + // execute pre transition function, if available + await executePreTransition(logger, updatedContext, currentState); + if (typeof currentState.onTransition === 'function') { logger.debug( `Current state ${currentStateName}: running transition ${currentState.onTransition.name}` @@ -123,6 +131,9 @@ export async function handleState( } } +/* + * executePostTransition: function that gets executed after the execution of any step, when defined + */ async function executePostTransition( logger: Logger, updatedContext: StateContext, @@ -137,3 +148,24 @@ async function executePostTransition( } } } + +/* + * executePreTransition: function that gets executed before the execution of any step, when defined + */ +async function executePreTransition( + logger: Logger, + updatedContext: StateContext, + currentState: State +) { + if (typeof currentState.onPreTransition === 'function') { + try { + await currentState.onPreTransition.call(undefined, updatedContext); + logger.debug(`Executing pre transition function: ${currentState.onPreTransition.name}`); + } catch (error) { + logger.warn(`Error during execution of pre transition function: ${error.message}`); + + // bubble up the error; if something goes wrong in the precondition we want to see what happened + throw error; + } + } +} diff --git a/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts b/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts index ac97411a5b92f..5b9155a756645 100644 --- a/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts +++ b/x-pack/plugins/fleet/server/services/fleet_server/index.test.ts @@ -8,6 +8,8 @@ import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; +import type { PackagePolicy } from '../../../common'; + import { appContextService } from '..'; import type { MockedFleetAppContext } from '../../mocks'; @@ -24,7 +26,6 @@ import { } from '.'; jest.mock('../agent_policy'); -jest.mock('../package_policy'); jest.mock('../agents'); const mockedAgentPolicyService = agentPolicyService as jest.Mocked; @@ -54,7 +55,8 @@ describe('checkFleetServerVersionsForSecretsStorage', () => { it('should return true if all fleet server versions are at least the specified version and there are no managed policies', async () => { const version = '1.0.0'; - mockedPackagePolicyService.list + jest + .spyOn(mockedPackagePolicyService, 'list') .mockResolvedValueOnce({ items: [ { @@ -162,7 +164,7 @@ describe('getFleetServerPolicies', () => { policy_id: 'agent-policy-2', policy_ids: ['agent-policy-2'], }, - ]; + ] as PackagePolicy[]; const mockFleetServerPolicies = [ { id: 'fs-policy-1', @@ -185,16 +187,22 @@ describe('getFleetServerPolicies', () => { ]; it('should return no policies if there are no fleet server package policies', async () => { - (mockedPackagePolicyService.list as jest.Mock).mockResolvedValueOnce({ + jest.spyOn(mockedPackagePolicyService, 'list').mockResolvedValueOnce({ items: [], + total: 0, + page: 1, + perPage: 10, }); const result = await getFleetServerPolicies(soClient); expect(result).toEqual([]); }); it('should return agent policies with fleet server package policies', async () => { - (mockedPackagePolicyService.list as jest.Mock).mockResolvedValueOnce({ + jest.spyOn(mockedPackagePolicyService, 'list').mockResolvedValueOnce({ items: mockPackagePolicies, + total: mockPackagePolicies.length, + page: 1, + perPage: mockPackagePolicies.length, }); (mockedAgentPolicyService.getByIDs as jest.Mock).mockResolvedValueOnce(mockFleetServerPolicies); const result = await getFleetServerPolicies(soClient); diff --git a/x-pack/plugins/inference/common/chat_complete/index.ts b/x-pack/plugins/inference/common/chat_complete/index.ts index 175f86f74b5c4..abad6a4372595 100644 --- a/x-pack/plugins/inference/common/chat_complete/index.ts +++ b/x-pack/plugins/inference/common/chat_complete/index.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import type { Observable } from 'rxjs'; import type { InferenceTaskEventBase } from '../tasks'; import type { ToolCall, ToolCallsOf, ToolOptions } from './tools'; diff --git a/x-pack/plugins/inference/common/connectors.ts b/x-pack/plugins/inference/common/connectors.ts index 82baea2f83c39..f7ad616741d79 100644 --- a/x-pack/plugins/inference/common/connectors.ts +++ b/x-pack/plugins/inference/common/connectors.ts @@ -11,6 +11,8 @@ export enum InferenceConnectorType { Gemini = '.gemini', } +const allSupportedConnectorTypes = Object.values(InferenceConnectorType); + export interface InferenceConnector { type: InferenceConnectorType; name: string; @@ -18,9 +20,9 @@ export interface InferenceConnector { } export function isSupportedConnectorType(id: string): id is InferenceConnectorType { - return ( - id === InferenceConnectorType.OpenAI || - id === InferenceConnectorType.Bedrock || - id === InferenceConnectorType.Gemini - ); + return allSupportedConnectorTypes.includes(id as InferenceConnectorType); +} + +export interface GetConnectorsResponseBody { + connectors: InferenceConnector[]; } diff --git a/x-pack/plugins/inference/public/chat_complete/index.ts b/x-pack/plugins/inference/public/chat_complete/index.ts index 2509ea2dc1222..3dfe4616b7323 100644 --- a/x-pack/plugins/inference/public/chat_complete/index.ts +++ b/x-pack/plugins/inference/public/chat_complete/index.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { HttpStart } from '@kbn/core/public'; import { from } from 'rxjs'; -import { ChatCompleteAPI } from '../../common/chat_complete'; +import type { HttpStart } from '@kbn/core/public'; +import type { ChatCompleteAPI } from '../../common/chat_complete'; import type { ChatCompleteRequestBody } from '../../common/chat_complete/request'; import { httpResponseIntoObservable } from '../util/http_response_into_observable'; diff --git a/x-pack/plugins/inference/public/plugin.tsx b/x-pack/plugins/inference/public/plugin.tsx index 9785efb7a8874..13ef4a0373845 100644 --- a/x-pack/plugins/inference/public/plugin.tsx +++ b/x-pack/plugins/inference/public/plugin.tsx @@ -4,9 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; + +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import type { Logger } from '@kbn/logging'; import { createOutputApi } from '../common/output/create_output_api'; +import type { GetConnectorsResponseBody } from '../common/connectors'; import { createChatCompleteApi } from './chat_complete'; import type { ConfigSchema, @@ -39,11 +41,15 @@ export class InferencePlugin start(coreStart: CoreStart, pluginsStart: InferenceStartDependencies): InferencePublicStart { const chatComplete = createChatCompleteApi({ http: coreStart.http }); + return { chatComplete, output: createOutputApi(chatComplete), - getConnectors: () => { - return coreStart.http.get('/internal/inference/connectors'); + getConnectors: async () => { + const res = await coreStart.http.get( + '/internal/inference/connectors' + ); + return res.connectors; }, }; } diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/get_inference_adapter.test.ts b/x-pack/plugins/inference/server/chat_complete/adapters/get_inference_adapter.test.ts new file mode 100644 index 0000000000000..272ad76538898 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/adapters/get_inference_adapter.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 { InferenceConnectorType } from '../../../common/connectors'; +import { getInferenceAdapter } from './get_inference_adapter'; +import { openAIAdapter } from './openai'; + +describe('getInferenceAdapter', () => { + it('returns the openAI adapter for OpenAI type', () => { + expect(getInferenceAdapter(InferenceConnectorType.OpenAI)).toBe(openAIAdapter); + }); + + it('returns undefined for Bedrock type', () => { + expect(getInferenceAdapter(InferenceConnectorType.Bedrock)).toBe(undefined); + }); + + it('returns undefined for Gemini type', () => { + expect(getInferenceAdapter(InferenceConnectorType.Gemini)).toBe(undefined); + }); +}); diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/get_inference_adapter.ts b/x-pack/plugins/inference/server/chat_complete/adapters/get_inference_adapter.ts new file mode 100644 index 0000000000000..a62ec8b795608 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/adapters/get_inference_adapter.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 { InferenceConnectorType } from '../../../common/connectors'; +import type { InferenceConnectorAdapter } from '../types'; +import { openAIAdapter } from './openai'; + +export const getInferenceAdapter = ( + connectorType: InferenceConnectorType +): InferenceConnectorAdapter | undefined => { + switch (connectorType) { + case InferenceConnectorType.OpenAI: + return openAIAdapter; + + case InferenceConnectorType.Bedrock: + // not implemented yet + break; + + case InferenceConnectorType.Gemini: + // not implemented yet + break; + } + + return undefined; +}; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/index.ts b/x-pack/plugins/inference/server/chat_complete/adapters/index.ts new file mode 100644 index 0000000000000..bc420bdf57473 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/adapters/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getInferenceAdapter } from './get_inference_adapter'; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.test.ts b/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.test.ts index 7f55f8a8faa48..f3b7c423ea42f 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.test.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.test.ts @@ -6,14 +6,14 @@ */ import OpenAI from 'openai'; -import { openAIAdapter } from '.'; -import type { ActionsClient } from '@kbn/actions-plugin/server/actions_client'; -import { ChatCompletionEventType, MessageRole } from '../../../../common/chat_complete'; +import { v4 } from 'uuid'; import { PassThrough } from 'stream'; import { pick } from 'lodash'; import { lastValueFrom, Subject, toArray } from 'rxjs'; +import { ChatCompletionEventType, MessageRole } from '../../../../common/chat_complete'; import { observableIntoEventSourceStream } from '../../../util/observable_into_event_source_stream'; -import { v4 } from 'uuid'; +import { InferenceExecutor } from '../../utils/inference_executor'; +import { openAIAdapter } from '.'; function createOpenAIChunk({ delta, @@ -39,38 +39,27 @@ function createOpenAIChunk({ } describe('openAIAdapter', () => { - const actionsClientMock = { - execute: jest.fn(), - } as ActionsClient & { execute: jest.MockedFn }; + const executorMock = { + invoke: jest.fn(), + } as InferenceExecutor & { invoke: jest.MockedFn }; beforeEach(() => { - actionsClientMock.execute.mockReset(); + executorMock.invoke.mockReset(); }); const defaultArgs = { - connector: { - id: 'foo', - actionTypeId: '.gen-ai', - name: 'OpenAI', - isPreconfigured: false, - isDeprecated: false, - isSystemAction: false, - }, - actionsClient: actionsClientMock, + executor: executorMock, }; describe('when creating the request', () => { function getRequest() { - const params = actionsClientMock.execute.mock.calls[0][0].params.subActionParams as Record< - string, - any - >; + const params = executorMock.invoke.mock.calls[0][0].subActionParams as Record; return { stream: params.stream, body: JSON.parse(params.body) }; } beforeEach(() => { - actionsClientMock.execute.mockImplementation(async () => { + executorMock.invoke.mockImplementation(async () => { return { actionId: '', status: 'ok', @@ -262,7 +251,7 @@ describe('openAIAdapter', () => { beforeEach(() => { source$ = new Subject>(); - actionsClientMock.execute.mockImplementation(async () => { + executorMock.invoke.mockImplementation(async () => { return { actionId: '', status: 'ok', diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.ts b/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.ts index c811ed9f400ea..80fa9bfb781f5 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.ts +++ b/x-pack/plugins/inference/server/chat_complete/adapters/openai/index.ts @@ -21,60 +21,30 @@ import { Message, MessageRole, } from '../../../../common/chat_complete'; +import type { ToolOptions } from '../../../../common/chat_complete/tools'; import { createTokenLimitReachedError } from '../../../../common/chat_complete/errors'; import { createInferenceInternalError } from '../../../../common/errors'; +import { eventSourceStreamIntoObservable } from '../../../util/event_source_stream_into_observable'; import { InferenceConnectorAdapter } from '../../types'; -import { eventSourceStreamIntoObservable } from '../event_source_stream_into_observable'; export const openAIAdapter: InferenceConnectorAdapter = { - chatComplete: ({ connector, actionsClient, system, messages, toolChoice, tools }) => { - const openAIMessages = messagesToOpenAI({ system, messages }); - - const toolChoiceForOpenAI = - typeof toolChoice === 'string' - ? toolChoice - : toolChoice - ? { - function: { - name: toolChoice.function, - }, - type: 'function' as const, - } - : undefined; - + chatComplete: ({ executor, system, messages, toolChoice, tools }) => { const stream = true; const request: Omit & { model?: string } = { stream, - messages: openAIMessages, + messages: messagesToOpenAI({ system, messages }), + tool_choice: toolChoiceToOpenAI(toolChoice), + tools: toolsToOpenAI(tools), temperature: 0, - tool_choice: toolChoiceForOpenAI, - tools: tools - ? Object.entries(tools).map(([toolName, { description, schema }]) => { - return { - type: 'function', - function: { - name: toolName, - description, - parameters: (schema ?? { - type: 'object' as const, - properties: {}, - }) as unknown as Record, - }, - }; - }) - : undefined, }; return from( - actionsClient.execute({ - actionId: connector.id, - params: { - subAction: 'stream', - subActionParams: { - body: JSON.stringify(request), - stream, - }, + executor.invoke({ + subAction: 'stream', + subActionParams: { + body: JSON.stringify(request), + stream, }, }) ).pipe( @@ -125,6 +95,39 @@ export const openAIAdapter: InferenceConnectorAdapter = { }, }; +function toolsToOpenAI(tools: ToolOptions['tools']): OpenAI.ChatCompletionCreateParams['tools'] { + return tools + ? Object.entries(tools).map(([toolName, { description, schema }]) => { + return { + type: 'function', + function: { + name: toolName, + description, + parameters: (schema ?? { + type: 'object' as const, + properties: {}, + }) as unknown as Record, + }, + }; + }) + : undefined; +} + +function toolChoiceToOpenAI( + toolChoice: ToolOptions['toolChoice'] +): OpenAI.ChatCompletionCreateParams['tool_choice'] { + return typeof toolChoice === 'string' + ? toolChoice + : toolChoice + ? { + function: { + name: toolChoice.function, + }, + type: 'function' as const, + } + : undefined; +} + function messagesToOpenAI({ system, messages, diff --git a/x-pack/plugins/inference/server/chat_complete/api.ts b/x-pack/plugins/inference/server/chat_complete/api.ts new file mode 100644 index 0000000000000..17bf0e5214300 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/api.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaRequest } from '@kbn/core-http-server'; +import { defer, switchMap, throwError } from 'rxjs'; +import type { ChatCompleteAPI, ChatCompletionResponse } from '../../common/chat_complete'; +import { createInferenceRequestError } from '../../common/errors'; +import type { InferenceStartDependencies } from '../types'; +import { getConnectorById } from '../util/get_connector_by_id'; +import { getInferenceAdapter } from './adapters'; +import { createInferenceExecutor, chunksIntoMessage } from './utils'; + +export function createChatCompleteApi({ + request, + actions, +}: { + request: KibanaRequest; + actions: InferenceStartDependencies['actions']; +}) { + const chatCompleteAPI: ChatCompleteAPI = ({ + connectorId, + messages, + toolChoice, + tools, + system, + }): ChatCompletionResponse => { + return defer(async () => { + const actionsClient = await actions.getActionsClientWithRequest(request); + const connector = await getConnectorById({ connectorId, actionsClient }); + const executor = createInferenceExecutor({ actionsClient, connector }); + return { executor, connector }; + }).pipe( + switchMap(({ executor, connector }) => { + const connectorType = connector.type; + const inferenceAdapter = getInferenceAdapter(connectorType); + + if (!inferenceAdapter) { + return throwError(() => + createInferenceRequestError(`Adapter for type ${connectorType} not implemented`, 400) + ); + } + + return inferenceAdapter.chatComplete({ + system, + executor, + messages, + toolChoice, + tools, + }); + }), + chunksIntoMessage({ + toolChoice, + tools, + }) + ); + }; + + return chatCompleteAPI; +} diff --git a/x-pack/plugins/inference/server/chat_complete/index.ts b/x-pack/plugins/inference/server/chat_complete/index.ts index e30afb58ca25a..5273822aea5b2 100644 --- a/x-pack/plugins/inference/server/chat_complete/index.ts +++ b/x-pack/plugins/inference/server/chat_complete/index.ts @@ -5,69 +5,4 @@ * 2.0. */ -import type { KibanaRequest } from '@kbn/core-http-server'; -import { defer, switchMap, throwError } from 'rxjs'; -import type { ChatCompleteAPI, ChatCompletionResponse } from '../../common/chat_complete'; -import type { ToolOptions } from '../../common/chat_complete/tools'; -import { InferenceConnectorType } from '../../common/connectors'; -import { createInferenceRequestError } from '../../common/errors'; -import type { InferenceStartDependencies } from '../types'; -import { chunksIntoMessage } from './adapters/chunks_into_message'; -import { openAIAdapter } from './adapters/openai'; - -export function createChatCompleteApi({ - request, - actions, -}: { - request: KibanaRequest; - actions: InferenceStartDependencies['actions']; -}) { - const chatCompleteAPI: ChatCompleteAPI = ({ - connectorId, - messages, - toolChoice, - tools, - system, - }): ChatCompletionResponse => { - return defer(async () => { - const actionsClient = await actions.getActionsClientWithRequest(request); - - const connector = await actionsClient.get({ id: connectorId, throwIfSystemAction: true }); - - return { actionsClient, connector }; - }).pipe( - switchMap(({ actionsClient, connector }) => { - switch (connector.actionTypeId) { - case InferenceConnectorType.OpenAI: - return openAIAdapter.chatComplete({ - system, - connector, - actionsClient, - messages, - toolChoice, - tools, - }); - - case InferenceConnectorType.Bedrock: - break; - - case InferenceConnectorType.Gemini: - break; - } - - return throwError(() => - createInferenceRequestError( - `Adapter for type ${connector.actionTypeId} not implemented`, - 400 - ) - ); - }), - chunksIntoMessage({ - toolChoice, - tools, - }) - ); - }; - - return chatCompleteAPI; -} +export { createChatCompleteApi } from './api'; diff --git a/x-pack/plugins/inference/server/chat_complete/types.ts b/x-pack/plugins/inference/server/chat_complete/types.ts index 6c89df1498646..fff902f7e885e 100644 --- a/x-pack/plugins/inference/server/chat_complete/types.ts +++ b/x-pack/plugins/inference/server/chat_complete/types.ts @@ -5,21 +5,36 @@ * 2.0. */ -import type { ActionsClient } from '@kbn/actions-plugin/server'; import type { Observable } from 'rxjs'; import type { - ChatCompleteAPI, ChatCompletionChunkEvent, ChatCompletionTokenCountEvent, + Message, } from '../../common/chat_complete'; +import type { ToolOptions } from '../../common/chat_complete/tools'; +import type { InferenceExecutor } from './utils'; -type Connector = Awaited>; - +/** + * Adapter in charge of communicating with a specific inference connector + * and to convert inputs/outputs from/to the common chatComplete inference format. + * + * @internal + */ export interface InferenceConnectorAdapter { chatComplete: ( - options: Omit[0], 'connectorId'> & { - actionsClient: ActionsClient; - connector: Connector; - } - ) => Observable; + options: { + messages: Message[]; + system?: string; + executor: InferenceExecutor; + } & ToolOptions + ) => Observable; } + +/** + * Events that can be emitted by the observable returned from {@link InferenceConnectorAdapter.chatComplete} + * + * @internal + */ +export type InferenceConnectorAdapterChatCompleteEvent = + | ChatCompletionChunkEvent + | ChatCompletionTokenCountEvent; diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/chunks_into_message.test.ts b/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.test.ts similarity index 100% rename from x-pack/plugins/inference/server/chat_complete/adapters/chunks_into_message.test.ts rename to x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.test.ts diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/chunks_into_message.ts b/x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.ts similarity index 100% rename from x-pack/plugins/inference/server/chat_complete/adapters/chunks_into_message.ts rename to x-pack/plugins/inference/server/chat_complete/utils/chunks_into_message.ts diff --git a/x-pack/plugins/inference/server/chat_complete/utils/index.ts b/x-pack/plugins/inference/server/chat_complete/utils/index.ts new file mode 100644 index 0000000000000..dea2ac65f4755 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/utils/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { + createInferenceExecutor, + type InferenceInvokeOptions, + type InferenceInvokeResult, + type InferenceExecutor, +} from './inference_executor'; +export { chunksIntoMessage } from './chunks_into_message'; diff --git a/x-pack/plugins/inference/server/chat_complete/utils/inference_executor.test.ts b/x-pack/plugins/inference/server/chat_complete/utils/inference_executor.test.ts new file mode 100644 index 0000000000000..1821b553dd6a9 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/utils/inference_executor.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { actionsClientMock } from '@kbn/actions-plugin/server/mocks'; +import { InferenceConnector, InferenceConnectorType } from '../../../common/connectors'; +import { createInferenceExecutor, type InferenceExecutor } from './inference_executor'; + +describe('createInferenceExecutor', () => { + let actionsClient: ReturnType; + let executor: InferenceExecutor; + + const connector: InferenceConnector = { + connectorId: 'foo', + name: 'My Connector', + type: InferenceConnectorType.OpenAI, + }; + + beforeEach(() => { + actionsClient = actionsClientMock.create(); + executor = createInferenceExecutor({ actionsClient, connector }); + }); + + describe('#invoke()', () => { + it('calls `actionsClient.execute` with the right parameters', async () => { + await executor.invoke({ subAction: 'stream', subActionParams: { over: 9000 } }); + + expect(actionsClient.execute).toHaveBeenCalledTimes(1); + expect(actionsClient.execute).toHaveBeenCalledWith({ + actionId: connector.connectorId, + params: { subAction: 'stream', subActionParams: { over: 9000 } }, + }); + }); + + it('returns the value returned from `actionsClient.execute`', async () => { + const expectedResult = Symbol.for('call_result'); + + actionsClient.execute.mockResolvedValue(expectedResult as any); + + const result = await executor.invoke({ + subAction: 'stream', + subActionParams: { over: 9000 }, + }); + + expect(result).toBe(expectedResult); + }); + }); +}); diff --git a/x-pack/plugins/inference/server/chat_complete/utils/inference_executor.ts b/x-pack/plugins/inference/server/chat_complete/utils/inference_executor.ts new file mode 100644 index 0000000000000..736beb82aa685 --- /dev/null +++ b/x-pack/plugins/inference/server/chat_complete/utils/inference_executor.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ActionTypeExecutorResult } from '@kbn/actions-plugin/common'; +import type { ActionsClient } from '@kbn/actions-plugin/server'; +import type { InferenceConnector } from '../../../common/connectors'; + +export interface InferenceInvokeOptions { + subAction: string; + subActionParams?: Record; +} + +export type InferenceInvokeResult = ActionTypeExecutorResult; + +/** + * Represent the actual interface to communicate with the inference model. + * + * In practice, for now it's just a thin abstraction around the action client. + */ +export interface InferenceExecutor { + invoke(params: InferenceInvokeOptions): Promise; +} + +export const createInferenceExecutor = ({ + connector, + actionsClient, +}: { + connector: InferenceConnector; + actionsClient: ActionsClient; +}): InferenceExecutor => { + return { + async invoke({ subAction, subActionParams }): Promise { + return await actionsClient.execute({ + actionId: connector.connectorId, + params: { + subAction, + subActionParams, + }, + }); + }, + }; +}; diff --git a/x-pack/plugins/inference/server/inference_client/index.ts b/x-pack/plugins/inference/server/inference_client/index.ts index 3c25cf29f6280..d9d52a8e41ec1 100644 --- a/x-pack/plugins/inference/server/inference_client/index.ts +++ b/x-pack/plugins/inference/server/inference_client/index.ts @@ -6,12 +6,10 @@ */ import type { KibanaRequest } from '@kbn/core-http-server'; -import { ActionsClient } from '@kbn/actions-plugin/server'; -import { isSupportedConnectorType } from '../../common/connectors'; -import { createInferenceRequestError } from '../../common/errors'; -import { createChatCompleteApi } from '../chat_complete'; import type { InferenceClient, InferenceStartDependencies } from '../types'; +import { createChatCompleteApi } from '../chat_complete'; import { createOutputApi } from '../../common/output/create_output_api'; +import { getConnectorById } from '../util/get_connector_by_id'; export function createInferenceClient({ request, @@ -21,33 +19,9 @@ export function createInferenceClient({ return { chatComplete, output: createOutputApi(chatComplete), - getConnectorById: async (id: string) => { + getConnectorById: async (connectorId: string) => { const actionsClient = await actions.getActionsClientWithRequest(request); - let connector: Awaited>; - - try { - connector = await actionsClient.get({ - id, - throwIfSystemAction: true, - }); - } catch (error) { - throw createInferenceRequestError(`No connector found for id ${id}`, 400); - } - - const actionTypeId = connector.id; - - if (!isSupportedConnectorType(actionTypeId)) { - throw createInferenceRequestError( - `Type ${actionTypeId} not recognized as a supported connector type`, - 400 - ); - } - - return { - connectorId: connector.id, - name: connector.name, - type: actionTypeId, - }; + return await getConnectorById({ connectorId, actionsClient }); }, }; } diff --git a/x-pack/plugins/inference/server/plugin.ts b/x-pack/plugins/inference/server/plugin.ts index 26c56209df8ce..1b17eb4a66d35 100644 --- a/x-pack/plugins/inference/server/plugin.ts +++ b/x-pack/plugins/inference/server/plugin.ts @@ -8,10 +8,9 @@ import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; import { createInferenceClient } from './inference_client'; -import { registerChatCompleteRoute } from './routes/chat_complete'; -import { registerConnectorsRoute } from './routes/connectors'; +import { registerRoutes } from './routes'; +import type { InferenceConfig } from './config'; import type { - ConfigSchema, InferenceServerSetup, InferenceServerStart, InferenceSetupDependencies, @@ -29,7 +28,7 @@ export class InferencePlugin { logger: Logger; - constructor(context: PluginInitializerContext) { + constructor(context: PluginInitializerContext) { this.logger = context.logger.get(); } setup( @@ -38,15 +37,11 @@ export class InferencePlugin ): InferenceServerSetup { const router = coreSetup.http.createRouter(); - registerChatCompleteRoute({ + registerRoutes({ router, coreSetup, }); - registerConnectorsRoute({ - router, - coreSetup, - }); return {}; } diff --git a/x-pack/plugins/inference/server/routes/chat_complete.ts b/x-pack/plugins/inference/server/routes/chat_complete.ts index 6c840f80466c2..6b5aea7b71696 100644 --- a/x-pack/plugins/inference/server/routes/chat_complete.ts +++ b/x-pack/plugins/inference/server/routes/chat_complete.ts @@ -7,7 +7,6 @@ import { schema, Type } from '@kbn/config-schema'; import type { CoreSetup, IRouter, RequestHandlerContext } from '@kbn/core/server'; -import { isObservable } from 'rxjs'; import { MessageRole } from '../../common/chat_complete'; import type { ChatCompleteRequestBody } from '../../common/chat_complete/request'; import { ToolCall, ToolChoiceType } from '../../common/chat_complete/tools'; @@ -20,7 +19,7 @@ const toolCallSchema: Type = schema.arrayOf( toolCallId: schema.string(), function: schema.object({ name: schema.string(), - arguments: schema.maybe(schema.object({}, { unknowns: 'allow' })), + arguments: schema.maybe(schema.recordOf(schema.string(), schema.any())), }), }) ); @@ -57,7 +56,7 @@ const chatCompleteBodySchema: Type = schema.object({ schema.oneOf([ schema.object({ role: schema.literal(MessageRole.Assistant), - content: schema.string(), + content: schema.oneOf([schema.string(), schema.literal(null)]), toolCalls: toolCallSchema, }), schema.object({ @@ -68,7 +67,7 @@ const chatCompleteBodySchema: Type = schema.object({ schema.object({ role: schema.literal(MessageRole.Tool), toolCallId: schema.string(), - response: schema.object({}, { unknowns: 'allow' }), + response: schema.recordOf(schema.string(), schema.any()), }), ]) ), @@ -97,7 +96,7 @@ export function registerChatCompleteRoute({ const { connectorId, messages, system, toolChoice, tools } = request.body; - const chatCompleteResponse = await client.chatComplete({ + const chatCompleteResponse = client.chatComplete({ connectorId, messages, system, @@ -105,13 +104,9 @@ export function registerChatCompleteRoute({ tools, }); - if (isObservable(chatCompleteResponse)) { - return response.ok({ - body: observableIntoEventSourceStream(chatCompleteResponse), - }); - } - - return response.ok({ body: chatCompleteResponse }); + return response.ok({ + body: observableIntoEventSourceStream(chatCompleteResponse), + }); } ); } diff --git a/x-pack/plugins/inference/server/routes/connectors.ts b/x-pack/plugins/inference/server/routes/connectors.ts index 8c69b68d55f14..a03a393f133b1 100644 --- a/x-pack/plugins/inference/server/routes/connectors.ts +++ b/x-pack/plugins/inference/server/routes/connectors.ts @@ -6,7 +6,11 @@ */ import type { CoreSetup, IRouter, RequestHandlerContext } from '@kbn/core/server'; -import { InferenceConnector, InferenceConnectorType } from '../../common/connectors'; +import { + InferenceConnector, + InferenceConnectorType, + isSupportedConnectorType, +} from '../../common/connectors'; import type { InferenceServerStart, InferenceStartDependencies } from '../types'; export function registerConnectorsRoute({ @@ -32,14 +36,8 @@ export function registerConnectorsRoute({ includeSystemActions: false, }); - const connectorTypes: string[] = [ - InferenceConnectorType.OpenAI, - InferenceConnectorType.Bedrock, - InferenceConnectorType.Gemini, - ]; - const connectors: InferenceConnector[] = allConnectors - .filter((connector) => connectorTypes.includes(connector.actionTypeId)) + .filter((connector) => isSupportedConnectorType(connector.actionTypeId)) .map((connector) => { return { connectorId: connector.id, diff --git a/x-pack/plugins/inference/server/routes/index.ts b/x-pack/plugins/inference/server/routes/index.ts new file mode 100644 index 0000000000000..0f6891ace1223 --- /dev/null +++ b/x-pack/plugins/inference/server/routes/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreSetup, IRouter } from '@kbn/core/server'; +import type { InferenceServerStart, InferenceStartDependencies } from '../types'; +import { registerChatCompleteRoute } from './chat_complete'; +import { registerConnectorsRoute } from './connectors'; + +export const registerRoutes = ({ + router, + coreSetup, +}: { + router: IRouter; + coreSetup: CoreSetup; +}) => { + registerChatCompleteRoute({ router, coreSetup }); + registerConnectorsRoute({ router, coreSetup }); +}; diff --git a/x-pack/plugins/inference/server/types.ts b/x-pack/plugins/inference/server/types.ts index 609b719b15236..20679ffd4cedf 100644 --- a/x-pack/plugins/inference/server/types.ts +++ b/x-pack/plugins/inference/server/types.ts @@ -16,8 +16,6 @@ import { OutputAPI } from '../common/output'; /* eslint-disable @typescript-eslint/no-empty-interface*/ -export interface ConfigSchema {} - export interface InferenceSetupDependencies { actions: ActionsPluginSetup; } diff --git a/x-pack/plugins/inference/server/util/event_source_stream_into_observable.test.ts b/x-pack/plugins/inference/server/util/event_source_stream_into_observable.test.ts new file mode 100644 index 0000000000000..235305a9316ce --- /dev/null +++ b/x-pack/plugins/inference/server/util/event_source_stream_into_observable.test.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. + */ + +import { Readable } from 'node:stream'; +import { toArray, firstValueFrom } from 'rxjs'; +import { eventSourceStreamIntoObservable } from './event_source_stream_into_observable'; + +describe('eventSourceStreamIntoObservable', () => { + it('emits for a single-chunk event', async () => { + const someMessage = JSON.stringify({ foo: 'bar' }); + const stream = Readable.from([`data: ${someMessage}\n\n`]); + + const results = await firstValueFrom(eventSourceStreamIntoObservable(stream).pipe(toArray())); + + expect(results).toEqual([someMessage]); + }); + + it('emits for single-chunk events', async () => { + const messages = [JSON.stringify({ foo: 'bar' }), '42', JSON.stringify({ foo: 'dolly' })]; + const stream = Readable.from(messages.map((message) => `data: ${message}\n\n`)); + + const results = await firstValueFrom(eventSourceStreamIntoObservable(stream).pipe(toArray())); + + expect(results).toEqual(messages); + }); + + it('emits for a multi-chunk event', async () => { + const stream = Readable.from([`data: abc`, `de`, `fgh\n\n`]); + + const results = await firstValueFrom(eventSourceStreamIntoObservable(stream).pipe(toArray())); + + expect(results).toEqual(['abcdefgh']); + }); + + it('emits for a multi-events chunk', async () => { + const stream = Readable.from([`data: A\n\ndata: B\n\ndata: C\n\n`]); + + const results = await firstValueFrom(eventSourceStreamIntoObservable(stream).pipe(toArray())); + + expect(results).toEqual(['A', 'B', 'C']); + }); + + it('emits for split chunk events', async () => { + const stream = Readable.from([`data: 42\n\ndata: `, `9000\n\nda`, `ta: 51\n\n`]); + + const results = await firstValueFrom(eventSourceStreamIntoObservable(stream).pipe(toArray())); + + expect(results).toEqual(['42', '9000', '51']); + }); +}); diff --git a/x-pack/plugins/inference/server/chat_complete/adapters/event_source_stream_into_observable.ts b/x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts similarity index 95% rename from x-pack/plugins/inference/server/chat_complete/adapters/event_source_stream_into_observable.ts rename to x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts index ece32d76222cc..cad0a8e84d6a7 100644 --- a/x-pack/plugins/inference/server/chat_complete/adapters/event_source_stream_into_observable.ts +++ b/x-pack/plugins/inference/server/util/event_source_stream_into_observable.ts @@ -5,8 +5,8 @@ * 2.0. */ +import type { Readable } from 'node:stream'; import { createParser } from 'eventsource-parser'; -import { Readable } from 'node:stream'; import { Observable } from 'rxjs'; export function eventSourceStreamIntoObservable(readable: Readable) { diff --git a/x-pack/plugins/inference/server/util/get_connector_by_id.test.ts b/x-pack/plugins/inference/server/util/get_connector_by_id.test.ts new file mode 100644 index 0000000000000..7387944950f4a --- /dev/null +++ b/x-pack/plugins/inference/server/util/get_connector_by_id.test.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ActionResult as ActionConnector } from '@kbn/actions-plugin/server'; +import { actionsClientMock } from '@kbn/actions-plugin/server/mocks'; +import { InferenceConnectorType } from '../../common/connectors'; +import { getConnectorById } from './get_connector_by_id'; + +describe('getConnectorById', () => { + let actionsClient: ReturnType; + const connectorId = 'my-connector-id'; + + const createMockConnector = (parts: Partial = {}): ActionConnector => { + return { + id: 'mock', + name: 'Mock', + actionTypeId: 'action-type', + ...parts, + } as ActionConnector; + }; + + beforeEach(() => { + actionsClient = actionsClientMock.create(); + actionsClient.get.mockResolvedValue(createMockConnector()); + }); + + it('calls `actionsClient.get` with the right parameters', async () => { + actionsClient.get.mockResolvedValue( + createMockConnector({ + id: 'foo', + name: 'Foo', + actionTypeId: InferenceConnectorType.OpenAI, + }) + ); + + await getConnectorById({ actionsClient, connectorId }); + + expect(actionsClient.get).toHaveBeenCalledTimes(1); + expect(actionsClient.get).toHaveBeenCalledWith({ + id: connectorId, + throwIfSystemAction: true, + }); + }); + + it('throws if `actionsClient.get` throws', async () => { + actionsClient.get.mockImplementation(() => { + throw new Error('Something wrong'); + }); + + await expect(() => + getConnectorById({ actionsClient, connectorId }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"No connector found for id 'my-connector-id'"`); + }); + + it('throws the connector type is not compatible', async () => { + actionsClient.get.mockResolvedValue( + createMockConnector({ + id: 'tcp-pigeon-3-0', + name: 'Tcp Pigeon', + actionTypeId: '.tcp-pigeon', + }) + ); + + await expect(() => + getConnectorById({ actionsClient, connectorId }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Type '.tcp-pigeon' not recognized as a supported connector type"` + ); + }); + + it('returns the inference connector when successful', async () => { + actionsClient.get.mockResolvedValue( + createMockConnector({ + id: 'my-id', + name: 'My Name', + actionTypeId: InferenceConnectorType.OpenAI, + }) + ); + + const connector = await getConnectorById({ actionsClient, connectorId }); + + expect(connector).toEqual({ + connectorId: 'my-id', + name: 'My Name', + type: InferenceConnectorType.OpenAI, + }); + }); +}); diff --git a/x-pack/plugins/inference/server/util/get_connector_by_id.ts b/x-pack/plugins/inference/server/util/get_connector_by_id.ts new file mode 100644 index 0000000000000..3fd77630ad3d1 --- /dev/null +++ b/x-pack/plugins/inference/server/util/get_connector_by_id.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ActionsClient, ActionResult as ActionConnector } from '@kbn/actions-plugin/server'; +import { isSupportedConnectorType, type InferenceConnector } from '../../common/connectors'; +import { createInferenceRequestError } from '../../common/errors'; + +/** + * Retrieves a connector given the provided `connectorId` and asserts it's an inference connector + */ +export const getConnectorById = async ({ + connectorId, + actionsClient, +}: { + actionsClient: ActionsClient; + connectorId: string; +}): Promise => { + let connector: ActionConnector; + try { + connector = await actionsClient.get({ + id: connectorId, + throwIfSystemAction: true, + }); + } catch (error) { + throw createInferenceRequestError(`No connector found for id '${connectorId}'`, 400); + } + + const actionTypeId = connector.actionTypeId; + + if (!isSupportedConnectorType(actionTypeId)) { + throw createInferenceRequestError( + `Type '${actionTypeId}' not recognized as a supported connector type`, + 400 + ); + } + + return { + connectorId: connector.id, + name: connector.name, + type: actionTypeId, + }; +}; diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.test.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.test.ts index 3ad0926297bbc..cfa5517ab0f90 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(categorizationMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: CategorizationState = categorizationTestState; +const state: CategorizationState = categorizationTestState; describe('Testing categorization handler', () => { it('handleCategorization()', async () => { - const response = await handleCategorization(testState, mockLlm); + const response = await handleCategorization({ state, model }); expect(response.currentPipeline).toStrictEqual( categorizationExpectedHandlerResponse.currentPipeline ); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts index 7f6e083d7f83f..80e3bb4861d70 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/categorization.ts @@ -4,21 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; import { JsonOutputParser } from '@langchain/core/output_parsers'; import type { Pipeline } from '../../../common'; -import type { CategorizationState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; +import type { CategorizationNodeParams } from './types'; import { combineProcessors } from '../../util/processors'; import { CATEGORIZATION_MAIN_PROMPT } from './prompts'; import { CATEGORIZATION_EXAMPLE_PROCESSORS } from './constants'; -export async function handleCategorization( - state: CategorizationState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleCategorization({ + state, + model, +}: CategorizationNodeParams): Promise> { const categorizationMainPrompt = CATEGORIZATION_MAIN_PROMPT; const outputParser = new JsonOutputParser(); const categorizationMainGraph = categorizationMainPrompt.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.test.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.test.ts index 18d8c1842080a..184c6c4988ad4 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(categorizationMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: CategorizationState = categorizationTestState; +const state: CategorizationState = categorizationTestState; describe('Testing categorization handler', () => { it('handleErrors()', async () => { - const response = await handleErrors(testState, mockLlm); + const response = await handleErrors({ state, model }); expect(response.currentPipeline).toStrictEqual( categorizationExpectedHandlerResponse.currentPipeline ); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts index e875754cb823d..789673af0ff28 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/errors.ts @@ -4,20 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; import type { Pipeline } from '../../../common'; -import type { CategorizationState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { CategorizationNodeParams } from './types'; +import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; import { combineProcessors } from '../../util/processors'; import { CATEGORIZATION_ERROR_PROMPT } from './prompts'; -export async function handleErrors( - state: CategorizationState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleErrors({ + state, + model, +}: CategorizationNodeParams): Promise> { const categorizationErrorPrompt = CATEGORIZATION_ERROR_PROMPT; const outputParser = new JsonOutputParser(); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.test.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.test.ts index 8fc617120be66..8db8a8019a1ed 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.test.ts @@ -31,7 +31,7 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: "I'll callback later.", }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; @@ -45,7 +45,7 @@ jest.mock('../../util/pipeline', () => ({ })); describe('runCategorizationGraph', () => { - const mockClient = { + const client = { asCurrentUser: { ingest: { simulate: jest.fn(), @@ -131,14 +131,14 @@ describe('runCategorizationGraph', () => { it('Ensures that the graph compiles', async () => { try { - await getCategorizationGraph(mockClient, mockLlm); + await getCategorizationGraph({ client, model }); } catch (error) { - // noop + throw Error(`getCategorizationGraph threw an error: ${error}`); } }); it('Runs the whole graph, with mocked outputs from the LLM.', async () => { - const categorizationGraph = await getCategorizationGraph(mockClient, mockLlm); + const categorizationGraph = await getCategorizationGraph({ client, model }); (testPipeline as jest.Mock) .mockResolvedValueOnce(testPipelineValidResult) @@ -151,8 +151,8 @@ describe('runCategorizationGraph', () => { let response; try { response = await categorizationGraph.invoke(mockedRequestWithPipeline); - } catch (e) { - // noop + } catch (error) { + throw Error(`getCategorizationGraph threw an error: ${error}`); } expect(response.results).toStrictEqual(categorizationExpectedResults); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts index ff170a23fdf7a..29e90a1f9b35d 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/graph.ts @@ -5,14 +5,10 @@ * 2.0. */ -import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import type { StateGraphArgs } from '@langchain/langgraph'; import { StateGraph, END, START } from '@langchain/langgraph'; -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; import type { CategorizationState } from '../../types'; +import type { CategorizationGraphParams, CategorizationBaseNodeParams } from './types'; import { prefixSamples, formatSamples } from '../../util/samples'; import { handleCategorization } from './categorization'; import { handleValidatePipeline } from '../../util/graph'; @@ -105,7 +101,7 @@ const graphState: StateGraphArgs['channels'] = { }, }; -function modelInput(state: CategorizationState): Partial { +function modelInput({ state }: CategorizationBaseNodeParams): Partial { const samples = prefixSamples(state); const formattedSamples = formatSamples(samples); const initialPipeline = JSON.parse(JSON.stringify(state.currentPipeline)); @@ -122,7 +118,7 @@ function modelInput(state: CategorizationState): Partial { }; } -function modelOutput(state: CategorizationState): Partial { +function modelOutput({ state }: CategorizationBaseNodeParams): Partial { return { finalized: true, lastExecutedChain: 'modelOutput', @@ -133,14 +129,14 @@ function modelOutput(state: CategorizationState): Partial { }; } -function validationRouter(state: CategorizationState): string { +function validationRouter({ state }: CategorizationBaseNodeParams): string { if (Object.keys(state.currentProcessors).length === 0) { return 'categorization'; } return 'validateCategorization'; } -function chainRouter(state: CategorizationState): string { +function chainRouter({ state }: CategorizationBaseNodeParams): string { if (Object.keys(state.errors).length > 0) { return 'errors'; } @@ -157,27 +153,26 @@ function chainRouter(state: CategorizationState): string { return END; } -export async function getCategorizationGraph( - client: IScopedClusterClient, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function getCategorizationGraph({ client, model }: CategorizationGraphParams) { const workflow = new StateGraph({ channels: graphState, }) - .addNode('modelInput', modelInput) - .addNode('modelOutput', modelOutput) + .addNode('modelInput', (state: CategorizationState) => modelInput({ state })) + .addNode('modelOutput', (state: CategorizationState) => modelOutput({ state })) .addNode('handleCategorization', (state: CategorizationState) => - handleCategorization(state, model) + handleCategorization({ state, model }) ) .addNode('handleValidatePipeline', (state: CategorizationState) => - handleValidatePipeline(state, client) + handleValidatePipeline({ state, client }) + ) + .addNode('handleCategorizationValidation', (state: CategorizationState) => + handleCategorizationValidation({ state }) ) - .addNode('handleCategorizationValidation', handleCategorizationValidation) .addNode('handleInvalidCategorization', (state: CategorizationState) => - handleInvalidCategorization(state, model) + handleInvalidCategorization({ state, model }) ) - .addNode('handleErrors', (state: CategorizationState) => handleErrors(state, model)) - .addNode('handleReview', (state: CategorizationState) => handleReview(state, model)) + .addNode('handleErrors', (state: CategorizationState) => handleErrors({ state, model })) + .addNode('handleReview', (state: CategorizationState) => handleReview({ state, model })) .addEdge(START, 'modelInput') .addEdge('modelOutput', END) .addEdge('modelInput', 'handleValidatePipeline') @@ -185,16 +180,24 @@ export async function getCategorizationGraph( .addEdge('handleInvalidCategorization', 'handleValidatePipeline') .addEdge('handleErrors', 'handleValidatePipeline') .addEdge('handleReview', 'handleValidatePipeline') - .addConditionalEdges('handleValidatePipeline', validationRouter, { - categorization: 'handleCategorization', - validateCategorization: 'handleCategorizationValidation', - }) - .addConditionalEdges('handleCategorizationValidation', chainRouter, { - modelOutput: 'modelOutput', - errors: 'handleErrors', - invalidCategorization: 'handleInvalidCategorization', - review: 'handleReview', - }); + .addConditionalEdges( + 'handleValidatePipeline', + (state: CategorizationState) => validationRouter({ state }), + { + categorization: 'handleCategorization', + validateCategorization: 'handleCategorizationValidation', + } + ) + .addConditionalEdges( + 'handleCategorizationValidation', + (state: CategorizationState) => chainRouter({ state }), + { + modelOutput: 'modelOutput', + errors: 'handleErrors', + invalidCategorization: 'handleInvalidCategorization', + review: 'handleReview', + } + ); const compiledCategorizationGraph = workflow.compile(); return compiledCategorizationGraph; diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.test.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.test.ts index 10560137093d8..35069c64902dd 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(categorizationMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: CategorizationState = categorizationTestState; +const state: CategorizationState = categorizationTestState; describe('Testing categorization handler', () => { it('handleInvalidCategorization()', async () => { - const response = await handleInvalidCategorization(testState, mockLlm); + const response = await handleInvalidCategorization({ state, model }); expect(response.currentPipeline).toStrictEqual( categorizationExpectedHandlerResponse.currentPipeline ); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts index 2ecbd5d34eaa4..62f7f3101ba9a 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/invalid.ts @@ -4,21 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; import type { Pipeline } from '../../../common'; -import type { CategorizationState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { CategorizationNodeParams } from './types'; +import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; import { combineProcessors } from '../../util/processors'; import { ECS_EVENT_TYPES_PER_CATEGORY } from './constants'; import { CATEGORIZATION_VALIDATION_PROMPT } from './prompts'; -export async function handleInvalidCategorization( - state: CategorizationState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleInvalidCategorization({ + state, + model, +}: CategorizationNodeParams): Promise> { const categorizationInvalidPrompt = CATEGORIZATION_VALIDATION_PROMPT; const outputParser = new JsonOutputParser(); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/review.test.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/review.test.ts index 7775b69c5b6a8..4294aa6b034f4 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/review.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/review.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(categorizationMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: CategorizationState = categorizationTestState; +const state: CategorizationState = categorizationTestState; describe('Testing categorization handler', () => { it('handleReview()', async () => { - const response = await handleReview(testState, mockLlm); + const response = await handleReview({ state, model }); expect(response.currentPipeline).toStrictEqual( categorizationExpectedHandlerResponse.currentPipeline ); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts index 7986b4d6c2423..19b8180ce33e5 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/review.ts @@ -4,21 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; import { CATEGORIZATION_REVIEW_PROMPT } from './prompts'; import type { Pipeline } from '../../../common'; -import type { CategorizationState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { CategorizationNodeParams } from './types'; +import type { SimplifiedProcessors, SimplifiedProcessor, CategorizationState } from '../../types'; import { combineProcessors } from '../../util/processors'; import { ECS_EVENT_TYPES_PER_CATEGORY } from './constants'; -export async function handleReview( - state: CategorizationState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleReview({ + state, + model, +}: CategorizationNodeParams): Promise> { const categorizationReviewPrompt = CATEGORIZATION_REVIEW_PROMPT; const outputParser = new JsonOutputParser(); const categorizationReview = categorizationReviewPrompt.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/types.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/types.ts new file mode 100644 index 0000000000000..19b1c20dff755 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import type { CategorizationState, ChatModels } from '../../types'; + +export interface CategorizationBaseNodeParams { + state: CategorizationState; +} + +export interface CategorizationNodeParams extends CategorizationBaseNodeParams { + model: ChatModels; +} + +export interface CategorizationGraphParams { + model: ChatModels; + client: IScopedClusterClient; +} diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.test.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.test.ts index 95c56c777a315..0fe546c1e21b3 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.test.ts @@ -9,12 +9,12 @@ import { handleCategorizationValidation } from './validate'; import type { CategorizationState } from '../../types'; import { categorizationTestState } from '../../../__jest__/fixtures/categorization'; -const testState: CategorizationState = categorizationTestState; +const state: CategorizationState = categorizationTestState; describe('Testing categorization invalid category', () => { it('handleCategorizationValidation()', async () => { - testState.pipelineResults = [{ test: 'testresult', event: { category: ['foo'] } }]; - const response = handleCategorizationValidation(testState); + state.pipelineResults = [{ test: 'testresult', event: { category: ['foo'] } }]; + const response = handleCategorizationValidation({ state }); expect(response.invalidCategorization).toEqual([ { error: @@ -27,8 +27,8 @@ describe('Testing categorization invalid category', () => { describe('Testing categorization invalid type', () => { it('handleCategorizationValidation()', async () => { - testState.pipelineResults = [{ test: 'testresult', event: { type: ['foo'] } }]; - const response = handleCategorizationValidation(testState); + state.pipelineResults = [{ test: 'testresult', event: { type: ['foo'] } }]; + const response = handleCategorizationValidation({ state }); expect(response.invalidCategorization).toEqual([ { error: @@ -41,10 +41,10 @@ describe('Testing categorization invalid type', () => { describe('Testing categorization invalid compatibility', () => { it('handleCategorizationValidation()', async () => { - testState.pipelineResults = [ + state.pipelineResults = [ { test: 'testresult', event: { category: ['authentication'], type: ['access'] } }, ]; - const response = handleCategorizationValidation(testState); + const response = handleCategorizationValidation({ state }); expect(response.invalidCategorization).toEqual([ { error: 'event.type (access) not compatible with any of the event.category (authentication)', diff --git a/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.ts b/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.ts index af3846edbac34..6360f327521c5 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/categorization/validate.ts @@ -5,6 +5,7 @@ * 2.0. */ import type { CategorizationState } from '../../types'; +import type { CategorizationBaseNodeParams } from './types'; import { ECS_EVENT_TYPES_PER_CATEGORY, EVENT_CATEGORIES, EVENT_TYPES } from './constants'; import type { EventCategories } from './constants'; @@ -22,11 +23,9 @@ interface CategorizationError { error: string; } -export function handleCategorizationValidation(state: CategorizationState): { - previousInvalidCategorization: string; - invalidCategorization: CategorizationError[]; - lastExecutedChain: string; -} { +export function handleCategorizationValidation({ + state, +}: CategorizationBaseNodeParams): Partial { let previousInvalidCategorization = ''; const errors: CategorizationError[] = []; const pipelineResults = state.pipelineResults as PipelineResult[]; diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.test.ts index 9270b2453e261..f3a51c80a5241 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.test.ts @@ -14,15 +14,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: '{ "message": "ll callback later."}', }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: EcsMappingState = ecsTestState; +const state: EcsMappingState = ecsTestState; describe('Testing ecs handler', () => { it('handleDuplicates()', async () => { - const response = await handleDuplicates(testState, mockLlm); + const response = await handleDuplicates({ state, model }); expect(response.currentMapping).toStrictEqual({ message: 'll callback later.' }); expect(response.lastExecutedChain).toBe('duplicateFields'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts index a9508901860db..5c66168fc0bfe 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/duplicates.ts @@ -4,18 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; +import type { EcsNodeParams } from './types'; import type { EcsMappingState } from '../../types'; import { ECS_DUPLICATES_PROMPT } from './prompts'; -export async function handleDuplicates( - state: EcsMappingState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleDuplicates({ + state, + model, +}: EcsNodeParams): Promise> { const outputParser = new JsonOutputParser(); const ecsDuplicatesGraph = ECS_DUPLICATES_PROMPT.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.test.ts index 62e51e7d68c71..322d71ef4c792 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.test.ts @@ -24,7 +24,7 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: "I'll callback later.", }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; @@ -69,16 +69,22 @@ describe('EcsGraph', () => { // When getEcsGraph runs, langgraph compiles the graph it will error if the graph has any issues. // Common issues for example detecting a node has no next step, or there is a infinite loop between them. try { - await getEcsGraph(mockLlm); + await getEcsGraph({ model }); } catch (error) { - fail(`getEcsGraph threw an error: ${error}`); + throw Error(`getEcsGraph threw an error: ${error}`); } }); it('Runs the whole graph, with mocked outputs from the LLM.', async () => { // The mocked outputs are specifically crafted to trigger ALL different conditions, allowing us to test the whole graph. // This is why we have all the expects ensuring each function was called. - const ecsGraph = await getEcsGraph(mockLlm); - const response = await ecsGraph.invoke(mockedRequest); + const ecsGraph = await getEcsGraph({ model }); + let response; + try { + response = await ecsGraph.invoke(mockedRequest); + } catch (error) { + throw Error(`getEcsGraph threw an error: ${error}`); + } + expect(response.results).toStrictEqual(ecsMappingExpectedResults); // Check if the functions were called diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts index 4b1e4c4c37791..86b0561a22e44 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/graph.ts @@ -5,12 +5,9 @@ * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; import { END, START, StateGraph, Send } from '@langchain/langgraph'; import type { EcsMappingState } from '../../types'; +import type { EcsGraphParams, EcsBaseNodeParams } from './types'; import { modelInput, modelOutput, modelSubOutput } from './model'; import { handleDuplicates } from './duplicates'; import { handleInvalidEcs } from './invalid'; @@ -19,7 +16,7 @@ import { handleMissingKeys } from './missing'; import { handleValidateMappings } from './validate'; import { graphState } from './state'; -const handleCreateMappingChunks = async (state: EcsMappingState) => { +const handleCreateMappingChunks = async ({ state }: EcsBaseNodeParams) => { // Cherrypick a shallow copy of state to pass to subgraph const stateParams = { exAnswer: state.exAnswer, @@ -36,7 +33,7 @@ const handleCreateMappingChunks = async (state: EcsMappingState) => { return 'modelOutput'; }; -function chainRouter(state: EcsMappingState): string { +function chainRouter({ state }: EcsBaseNodeParams): string { if (Object.keys(state.duplicateFields).length > 0) { return 'duplicateFields'; } @@ -53,22 +50,22 @@ function chainRouter(state: EcsMappingState): string { } // This is added as a separate graph to be able to run these steps concurrently from handleCreateMappingChunks -async function getEcsSubGraph(model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel) { +async function getEcsSubGraph({ model }: EcsGraphParams) { const workflow = new StateGraph({ channels: graphState, }) - .addNode('modelSubOutput', modelSubOutput) - .addNode('handleValidation', handleValidateMappings) - .addNode('handleEcsMapping', (state: EcsMappingState) => handleEcsMapping(state, model)) - .addNode('handleDuplicates', (state: EcsMappingState) => handleDuplicates(state, model)) - .addNode('handleMissingKeys', (state: EcsMappingState) => handleMissingKeys(state, model)) - .addNode('handleInvalidEcs', (state: EcsMappingState) => handleInvalidEcs(state, model)) + .addNode('modelSubOutput', (state: EcsMappingState) => modelSubOutput({ state })) + .addNode('handleValidation', (state: EcsMappingState) => handleValidateMappings({ state })) + .addNode('handleEcsMapping', (state: EcsMappingState) => handleEcsMapping({ state, model })) + .addNode('handleDuplicates', (state: EcsMappingState) => handleDuplicates({ state, model })) + .addNode('handleMissingKeys', (state: EcsMappingState) => handleMissingKeys({ state, model })) + .addNode('handleInvalidEcs', (state: EcsMappingState) => handleInvalidEcs({ state, model })) .addEdge(START, 'handleEcsMapping') .addEdge('handleEcsMapping', 'handleValidation') .addEdge('handleDuplicates', 'handleValidation') .addEdge('handleMissingKeys', 'handleValidation') .addEdge('handleInvalidEcs', 'handleValidation') - .addConditionalEdges('handleValidation', chainRouter, { + .addConditionalEdges('handleValidation', (state: EcsMappingState) => chainRouter({ state }), { duplicateFields: 'handleDuplicates', missingKeys: 'handleMissingKeys', invalidEcsFields: 'handleInvalidEcs', @@ -81,17 +78,19 @@ async function getEcsSubGraph(model: ActionsClientChatOpenAI | ActionsClientSimp return compiledEcsSubGraph; } -export async function getEcsGraph(model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel) { - const subGraph = await getEcsSubGraph(model); +export async function getEcsGraph({ model }: EcsGraphParams) { + const subGraph = await getEcsSubGraph({ model }); const workflow = new StateGraph({ channels: graphState, }) - .addNode('modelInput', modelInput) - .addNode('modelOutput', modelOutput) + .addNode('modelInput', (state: EcsMappingState) => modelInput({ state })) + .addNode('modelOutput', (state: EcsMappingState) => modelOutput({ state })) .addNode('subGraph', subGraph) .addEdge(START, 'modelInput') .addEdge('subGraph', 'modelOutput') - .addConditionalEdges('modelInput', handleCreateMappingChunks) + .addConditionalEdges('modelInput', (state: EcsMappingState) => + handleCreateMappingChunks({ state }) + ) .addEdge('modelOutput', END); const compiledEcsGraph = workflow.compile(); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/index.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/index.ts index 91ea9fed3b3d3..4207727a315e5 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/index.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/index.ts @@ -4,4 +4,5 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + export { getEcsGraph } from './graph'; diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.test.ts index ce1f76ce7a721..ad10aa5b030df 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.test.ts @@ -14,15 +14,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: '{ "message": "ll callback later."}', }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: EcsMappingState = ecsTestState; +const state: EcsMappingState = ecsTestState; describe('Testing ecs handlers', () => { it('handleInvalidEcs()', async () => { - const response = await handleInvalidEcs(testState, mockLlm); + const response = await handleInvalidEcs({ state, model }); expect(response.currentMapping).toStrictEqual({ message: 'll callback later.' }); expect(response.lastExecutedChain).toBe('invalidEcs'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts index 8e2d1baf4c423..4b050fac3ccf4 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/invalid.ts @@ -4,18 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; import { JsonOutputParser } from '@langchain/core/output_parsers'; +import type { EcsNodeParams } from './types'; import type { EcsMappingState } from '../../types'; import { ECS_INVALID_PROMPT } from './prompts'; -export async function handleInvalidEcs( - state: EcsMappingState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleInvalidEcs({ + state, + model, +}: EcsNodeParams): Promise> { const outputParser = new JsonOutputParser(); const ecsInvalidEcsGraph = ECS_INVALID_PROMPT.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.test.ts index dbbfc0608d010..92954b83863bf 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.test.ts @@ -14,15 +14,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: '{ "message": "ll callback later."}', }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: EcsMappingState = ecsTestState; +const state: EcsMappingState = ecsTestState; describe('Testing ecs handler', () => { it('handleEcsMapping()', async () => { - const response = await handleEcsMapping(testState, mockLlm); + const response = await handleEcsMapping({ state, model }); expect(response.currentMapping).toStrictEqual({ message: 'll callback later.' }); expect(response.lastExecutedChain).toBe('ecsMapping'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts index 30c51dcc01dd9..7e8d964323743 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/mapping.ts @@ -4,18 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; +import type { EcsNodeParams } from './types'; import type { EcsMappingState } from '../../types'; import { ECS_MAIN_PROMPT } from './prompts'; -export async function handleEcsMapping( - state: EcsMappingState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleEcsMapping({ + state, + model, +}: EcsNodeParams): Promise> { const outputParser = new JsonOutputParser(); const ecsMainGraph = ECS_MAIN_PROMPT.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.test.ts index b369d28b1e177..35fbc51bbb2e7 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.test.ts @@ -14,15 +14,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: '{ "message": "ll callback later."}', }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: EcsMappingState = ecsTestState; +const state: EcsMappingState = ecsTestState; describe('Testing ecs handler', () => { it('handleMissingKeys()', async () => { - const response = await handleMissingKeys(testState, mockLlm); + const response = await handleMissingKeys({ state, model }); expect(response.currentMapping).toStrictEqual({ message: 'll callback later.' }); expect(response.lastExecutedChain).toBe('missingKeys'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts index 0a23b35bd3b72..649c9a5d1facf 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/missing.ts @@ -4,18 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; -import type { EcsMappingState } from '../../types'; +import { EcsNodeParams } from './types'; +import { EcsMappingState } from '../../types'; import { ECS_MISSING_KEYS_PROMPT } from './prompts'; -export async function handleMissingKeys( - state: EcsMappingState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleMissingKeys({ + state, + model, +}: EcsNodeParams): Promise> { const outputParser = new JsonOutputParser(); const ecsMissingGraph = ECS_MISSING_KEYS_PROMPT.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/model.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/model.ts index 9bc2909ab7942..44508bca4ff1a 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/model.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/model.ts @@ -9,15 +9,16 @@ import { ECS_EXAMPLE_ANSWER, ECS_FIELDS } from './constants'; import { createPipeline } from './pipeline'; import { mergeAndChunkSamples } from './chunk'; import type { EcsMappingState } from '../../types'; +import type { EcsBaseNodeParams } from './types'; -export function modelSubOutput(state: EcsMappingState): Partial { +export function modelSubOutput({ state }: EcsBaseNodeParams): Partial { return { lastExecutedChain: 'ModelSubOutput', finalMapping: state.currentMapping, }; } -export function modelInput(state: EcsMappingState): Partial { +export function modelInput({ state }: EcsBaseNodeParams): Partial { const prefixedSamples = prefixSamples(state); const sampleChunks = mergeAndChunkSamples(prefixedSamples, state.chunkSize); return { @@ -30,7 +31,7 @@ export function modelInput(state: EcsMappingState): Partial { }; } -export function modelOutput(state: EcsMappingState): Partial { +export function modelOutput({ state }: EcsBaseNodeParams): Partial { const currentPipeline = createPipeline(state); return { finalized: true, diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/types.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/types.ts new file mode 100644 index 0000000000000..a9188d3985ac7 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/types.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 { EcsMappingState, ChatModels } from '../../types'; + +export interface EcsBaseNodeParams { + state: EcsMappingState; +} + +export interface EcsNodeParams extends EcsBaseNodeParams { + model: ChatModels; +} + +export interface EcsGraphParams { + model: ChatModels; +} diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts index f347247df4246..6c3fe06699aa3 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/validate.ts @@ -6,7 +6,7 @@ */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { ECS_FULL } from '../../../common/ecs'; -import type { EcsMappingState } from '../../types'; +import type { EcsBaseNodeParams } from './types'; import { ECS_RESERVED } from './constants'; const valueFieldKeys = new Set(['target', 'confidence', 'date_formats', 'type']); @@ -152,7 +152,7 @@ export function findInvalidEcsFields(currentMapping: AnyObject): string[] { return results; } -export function handleValidateMappings(state: EcsMappingState): AnyObject { +export function handleValidateMappings({ state }: EcsBaseNodeParams): AnyObject { const missingKeys = findMissingFields(state?.combinedSamples, state?.currentMapping); const duplicateFields = findDuplicateFields(state?.prefixedSamples, state?.currentMapping); const invalidEcsFields = findInvalidEcsFields(state?.currentMapping); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/errors.test.ts b/x-pack/plugins/integration_assistant/server/graphs/related/errors.test.ts index 24dc4365dcbff..719c3f6abfc22 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/errors.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/errors.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(relatedMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: RelatedState = relatedTestState; +const state: RelatedState = relatedTestState; describe('Testing related handler', () => { it('handleErrors()', async () => { - const response = await handleErrors(testState, mockLlm); + const response = await handleErrors({ state, model }); expect(response.currentPipeline).toStrictEqual(relatedExpectedHandlerResponse.currentPipeline); expect(response.lastExecutedChain).toBe('error'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts b/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts index b40e638751ee0..5601c4b5f5e33 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/errors.ts @@ -4,21 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; import type { Pipeline } from '../../../common'; import type { RelatedState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { RelatedNodeParams } from './types'; import { combineProcessors } from '../../util/processors'; import { RELATED_ERROR_PROMPT } from './prompts'; import { COMMON_ERRORS } from './constants'; -export async function handleErrors( - state: RelatedState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleErrors({ + state, + model, +}: RelatedNodeParams): Promise> { const relatedErrorPrompt = RELATED_ERROR_PROMPT; const outputParser = new JsonOutputParser(); const relatedErrorGraph = relatedErrorPrompt.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/graph.test.ts b/x-pack/plugins/integration_assistant/server/graphs/related/graph.test.ts index a07a715a179e1..9583a3050a38a 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/graph.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/graph.test.ts @@ -28,7 +28,7 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: "I'll callback later.", }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; @@ -41,7 +41,7 @@ jest.mock('../../util/pipeline', () => ({ })); describe('runRelatedGraph', () => { - const mockClient = { + const client = { asCurrentUser: { indices: { getMapping: jest.fn(), @@ -106,14 +106,14 @@ describe('runRelatedGraph', () => { it('Ensures that the graph compiles', async () => { try { - await getRelatedGraph(mockClient, mockLlm); + await getRelatedGraph({ client, model }); } catch (error) { - // noop + throw Error(`getRelatedGraph threw an error: ${error}`); } }); it('Runs the whole graph, with mocked outputs from the LLM.', async () => { - const relatedGraph = await getRelatedGraph(mockClient, mockLlm); + const relatedGraph = await getRelatedGraph({ client, model }); (testPipeline as jest.Mock) .mockResolvedValueOnce(testPipelineValidResult) @@ -125,8 +125,8 @@ describe('runRelatedGraph', () => { let response; try { response = await relatedGraph.invoke(mockedRequestWithPipeline); - } catch (e) { - // noop + } catch (error) { + throw Error(`getRelatedGraph threw an error: ${error}`); } expect(response.results).toStrictEqual(relatedExpectedResults); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts b/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts index 22eb69f7d2a2d..eb7196b7b4ecb 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/graph.ts @@ -5,14 +5,10 @@ * 2.0. */ -import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import type { StateGraphArgs } from '@langchain/langgraph'; import { StateGraph, END, START } from '@langchain/langgraph'; -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; import type { RelatedState } from '../../types'; +import type { RelatedGraphParams, RelatedBaseNodeParams } from './types'; import { prefixSamples, formatSamples } from '../../util/samples'; import { handleValidatePipeline } from '../../util/graph'; import { handleRelated } from './related'; @@ -91,7 +87,7 @@ const graphState: StateGraphArgs['channels'] = { }, }; -function modelInput(state: RelatedState): Partial { +function modelInput({ state }: RelatedBaseNodeParams): Partial { const samples = prefixSamples(state); const formattedSamples = formatSamples(samples); const initialPipeline = JSON.parse(JSON.stringify(state.currentPipeline)); @@ -107,7 +103,7 @@ function modelInput(state: RelatedState): Partial { }; } -function modelOutput(state: RelatedState): Partial { +function modelOutput({ state }: RelatedBaseNodeParams): Partial { return { finalized: true, lastExecutedChain: 'modelOutput', @@ -118,14 +114,14 @@ function modelOutput(state: RelatedState): Partial { }; } -function inputRouter(state: RelatedState): string { +function inputRouter({ state }: RelatedBaseNodeParams): string { if (Object.keys(state.pipelineResults).length === 0) { return 'validatePipeline'; } return 'related'; } -function chainRouter(state: RelatedState): string { +function chainRouter({ state }: RelatedBaseNodeParams): string { if (Object.keys(state.currentProcessors).length === 0) { return 'related'; } @@ -141,34 +137,35 @@ function chainRouter(state: RelatedState): string { return END; } -export async function getRelatedGraph( - client: IScopedClusterClient, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function getRelatedGraph({ client, model }: RelatedGraphParams) { const workflow = new StateGraph({ channels: graphState }) - .addNode('modelInput', modelInput) - .addNode('modelOutput', modelOutput) - .addNode('handleRelated', (state: RelatedState) => handleRelated(state, model)) + .addNode('modelInput', (state: RelatedState) => modelInput({ state })) + .addNode('modelOutput', (state: RelatedState) => modelOutput({ state })) + .addNode('handleRelated', (state: RelatedState) => handleRelated({ state, model })) .addNode('handleValidatePipeline', (state: RelatedState) => - handleValidatePipeline(state, client) + handleValidatePipeline({ state, client }) ) - .addNode('handleErrors', (state: RelatedState) => handleErrors(state, model)) - .addNode('handleReview', (state: RelatedState) => handleReview(state, model)) + .addNode('handleErrors', (state: RelatedState) => handleErrors({ state, model })) + .addNode('handleReview', (state: RelatedState) => handleReview({ state, model })) .addEdge(START, 'modelInput') .addEdge('modelOutput', END) .addEdge('handleRelated', 'handleValidatePipeline') .addEdge('handleErrors', 'handleValidatePipeline') .addEdge('handleReview', 'handleValidatePipeline') - .addConditionalEdges('modelInput', inputRouter, { + .addConditionalEdges('modelInput', (state: RelatedState) => inputRouter({ state }), { related: 'handleRelated', validatePipeline: 'handleValidatePipeline', }) - .addConditionalEdges('handleValidatePipeline', chainRouter, { - related: 'handleRelated', - errors: 'handleErrors', - review: 'handleReview', - modelOutput: 'modelOutput', - }); + .addConditionalEdges( + 'handleValidatePipeline', + (state: RelatedState) => chainRouter({ state }), + { + related: 'handleRelated', + errors: 'handleErrors', + review: 'handleReview', + modelOutput: 'modelOutput', + } + ); const compiledRelatedGraph = workflow.compile(); return compiledRelatedGraph; diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/related.test.ts b/x-pack/plugins/integration_assistant/server/graphs/related/related.test.ts index 3a741020fb530..62a09cfa64ac1 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/related.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/related.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(relatedMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: RelatedState = relatedTestState; +const state: RelatedState = relatedTestState; describe('Testing related handler', () => { it('handleRelated()', async () => { - const response = await handleRelated(testState, mockLlm); + const response = await handleRelated({ state, model }); expect(response.currentPipeline).toStrictEqual(relatedExpectedHandlerResponse.currentPipeline); expect(response.lastExecutedChain).toBe('related'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/related.ts b/x-pack/plugins/integration_assistant/server/graphs/related/related.ts index af3b27790da97..172270e7f87da 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/related.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/related.ts @@ -4,20 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; import type { Pipeline } from '../../../common'; import type { RelatedState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { RelatedNodeParams } from './types'; import { combineProcessors } from '../../util/processors'; import { RELATED_MAIN_PROMPT } from './prompts'; -export async function handleRelated( - state: RelatedState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleRelated({ + state, + model, +}: RelatedNodeParams): Promise> { const relatedMainPrompt = RELATED_MAIN_PROMPT; const outputParser = new JsonOutputParser(); const relatedMainGraph = relatedMainPrompt.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/review.test.ts b/x-pack/plugins/integration_assistant/server/graphs/related/review.test.ts index 475f0d72b988d..2b6085c6f4f86 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/review.test.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/review.test.ts @@ -18,15 +18,15 @@ import { ActionsClientSimpleChatModel, } from '@kbn/langchain/server/language_models'; -const mockLlm = new FakeLLM({ +const model = new FakeLLM({ response: JSON.stringify(relatedMockProcessors, null, 2), }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; -const testState: RelatedState = relatedTestState; +const state: RelatedState = relatedTestState; describe('Testing related handler', () => { it('handleReview()', async () => { - const response = await handleReview(testState, mockLlm); + const response = await handleReview({ state, model }); expect(response.currentPipeline).toStrictEqual(relatedExpectedHandlerResponse.currentPipeline); expect(response.lastExecutedChain).toBe('review'); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/review.ts b/x-pack/plugins/integration_assistant/server/graphs/related/review.ts index 31abb6ca5a60c..300f33144b52a 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/related/review.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/related/review.ts @@ -4,20 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { - ActionsClientChatOpenAI, - ActionsClientSimpleChatModel, -} from '@kbn/langchain/server/language_models'; + import { JsonOutputParser } from '@langchain/core/output_parsers'; import type { Pipeline } from '../../../common'; import type { RelatedState, SimplifiedProcessors, SimplifiedProcessor } from '../../types'; +import type { RelatedNodeParams } from './types'; import { combineProcessors } from '../../util/processors'; import { RELATED_REVIEW_PROMPT } from './prompts'; -export async function handleReview( - state: RelatedState, - model: ActionsClientChatOpenAI | ActionsClientSimpleChatModel -) { +export async function handleReview({ + state, + model, +}: RelatedNodeParams): Promise> { const relatedReviewPrompt = RELATED_REVIEW_PROMPT; const outputParser = new JsonOutputParser(); const relatedReviewGraph = relatedReviewPrompt.pipe(model).pipe(outputParser); diff --git a/x-pack/plugins/integration_assistant/server/graphs/related/types.ts b/x-pack/plugins/integration_assistant/server/graphs/related/types.ts new file mode 100644 index 0000000000000..77f77fbacf605 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/graphs/related/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import { RelatedState, ChatModels } from '../../types'; + +export interface RelatedBaseNodeParams { + state: RelatedState; +} + +export interface RelatedNodeParams extends RelatedBaseNodeParams { + model: ChatModels; +} + +export interface RelatedGraphParams { + client: IScopedClusterClient; + model: ChatModels; +} diff --git a/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts b/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts index 80ebe9eb65258..439ebe91db2b6 100644 --- a/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/categorization_routes.ts @@ -92,7 +92,7 @@ export function registerCategorizationRoutes( ], }; - const graph = await getCategorizationGraph(client, model); + const graph = await getCategorizationGraph({ client, model }); const results = await graph.invoke(parameters, options); return res.ok({ body: CategorizationResponse.parse(results) }); diff --git a/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts b/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts index 69b13a004e98e..78ecf2023858b 100644 --- a/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/ecs_routes.ts @@ -84,7 +84,7 @@ export function registerEcsRoutes(router: IRouter void; @@ -97,3 +103,9 @@ export interface RelatedState { results: object; lastExecutedChain: string; } + +export type ChatModels = + | ActionsClientChatOpenAI + | ActionsClientBedrockChatModel + | ActionsClientSimpleChatModel + | ActionsClientGeminiChatModel; diff --git a/x-pack/plugins/integration_assistant/server/util/graph.ts b/x-pack/plugins/integration_assistant/server/util/graph.ts index a4e8141eae408..53a7787263ce1 100644 --- a/x-pack/plugins/integration_assistant/server/util/graph.ts +++ b/x-pack/plugins/integration_assistant/server/util/graph.ts @@ -8,10 +8,15 @@ import type { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import type { CategorizationState, RelatedState } from '../types'; import { testPipeline } from './pipeline'; -export async function handleValidatePipeline( - state: CategorizationState | RelatedState, - client: IScopedClusterClient -): Promise | Partial> { +interface HandleValidateNodeParams { + state: CategorizationState | RelatedState; + client: IScopedClusterClient; +} + +export async function handleValidatePipeline({ + state, + client, +}: HandleValidateNodeParams): Promise | Partial> { const previousError = JSON.stringify(state.errors, null, 2); const results = await testPipeline(state.rawSamples, state.currentPipeline, client); return { diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/_index.scss b/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/_index.scss index 264dfe5e24843..28da88491f1cc 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/_index.scss +++ b/x-pack/plugins/maps/public/connected_components/mb_map/scale_control/_index.scss @@ -5,9 +5,10 @@ bottom: $euiSizeM; pointer-events: none; color: $euiTextColor; - border-left: 2px solid $euiTextColor; - border-bottom: 2px solid $euiTextColor; + border-left: 2px solid rgba($euiTextColor, .6); + border-bottom: 2px solid rgba($euiTextColor, .6); text-align: right; + @include mapOverlayIsTextOnly; } .mapScaleControlFullScreen { diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/_mixins.scss b/x-pack/plugins/maps/public/connected_components/right_side_controls/_mixins.scss index 97557f1312e86..640545c065418 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/_mixins.scss +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/_mixins.scss @@ -1,8 +1,6 @@ @mixin mapOverlayIsTextOnly { - text-shadow: - 0 0 2px $euiColorEmptyShade, - 0 0 1px $euiColorEmptyShade, - 0 0 1px $euiColorEmptyShade, - 0 0 1px $euiColorEmptyShade, - 0 0 1px $euiColorEmptyShade 0 0 1px $euiColorEmptyShade 0 0 1px $euiColorEmptyShade; + background-color: $euiPageBackgroundColor; + + padding-left: $euiSizeXS; + padding-right: $euiSizeXS; } diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/attribution_control/_attribution_control.scss b/x-pack/plugins/maps/public/connected_components/right_side_controls/attribution_control/_attribution_control.scss index e319535b4a45c..51c82fd7aa443 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/attribution_control/_attribution_control.scss +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/attribution_control/_attribution_control.scss @@ -2,7 +2,6 @@ @include mapOverlayIsTextOnly; @include euiTextBreakWord; pointer-events: all; - padding-left: $euiSizeM; } .mapAttributionControl__fullScreen { diff --git a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/nodes_list.tsx b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/nodes_list.tsx index 94a17f85aad2c..d31981decb7e9 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/nodes_list.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/nodes_list.tsx @@ -151,7 +151,7 @@ export const NodesList: FC = ({ compactView = false }) => { name: i18n.translate('xpack.ml.trainedModels.nodesList.nodeMemoryUsageHeader', { defaultMessage: 'Memory usage', }), - truncateText: true, + truncateText: false, 'data-test-subj': 'mlNodesTableColumnMemoryUsage', render: (v: NodeItem) => { return ; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/onboarding/introduction.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/onboarding/introduction.tsx index dfef9cd56050b..441d7a2f297f3 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/onboarding/introduction.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/onboarding/introduction.tsx @@ -5,9 +5,10 @@ * 2.0. */ -import { EuiBetaBadge, EuiImage, EuiMarkdownFormat, EuiPageHeader } from '@elastic/eui'; +import { EuiBetaBadge, EuiImage, EuiPageHeader, EuiLink, EuiText } from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { useKibanaUrl } from '../../../hooks/use_kibana_url'; interface IntroductionProps { @@ -38,17 +39,6 @@ export function Introduction({ isBeta, guideLink }: IntroductionProps) { />, ]; - const description = i18n.translate('xpack.apm.onboarding.specProvider.longDescription', { - defaultMessage: - 'Application Performance Monitoring (APM) collects in-depth \ -performance metrics and errors from inside your application. \ -It allows you to monitor the performance of thousands of applications in real time. \ -[Learn more]({learnMoreLink}).', - values: { - learnMoreLink: guideLink, - }, - }); - return ( <> } - description={{description}} + description={ + + + {i18n.translate('xpack.apm.onboarding.specProvider.learnMoreLabel', { + defaultMessage: 'Learn more', + })} + + ), + }} + /> + + } rightSideItems={rightSideItems} /> diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts index 9cab31e30af64..c2a5676e85c28 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/lib/helpers/create_es_client/create_apm_event_client/index.test.ts @@ -36,7 +36,9 @@ describe('APMEventClient', () => { esClient: { search: async (params: any, { signal }: { signal: AbortSignal }) => { abortSignal = signal; - await setTimeoutPromise(3_000); + await setTimeoutPromise(3_000, undefined, { + signal: abortSignal, + }); return {}; }, } as any, diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/columns.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/columns.tsx index bea56c8957fa4..b18e20f5b22c4 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/columns.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/columns.tsx @@ -14,7 +14,6 @@ import { EuiIcon, EuiLink, EuiToolTip, - EuiButtonIcon, EuiText, formatNumber, EuiSkeletonRectangle, @@ -25,27 +24,20 @@ import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; -import { css } from '@emotion/react'; +import { BrowserUrlService } from '@kbn/share-plugin/public'; import { DEGRADED_QUALITY_MINIMUM_PERCENTAGE, POOR_QUALITY_MINIMUM_PERCENTAGE, BYTE_NUMBER_FORMAT, } from '../../../../common/constants'; import { DataStreamStat } from '../../../../common/data_streams_stats/data_stream_stat'; -import { NavigationSource } from '../../../services/telemetry'; import { DatasetQualityIndicator, QualityIndicator } from '../../quality_indicator'; import { PrivilegesWarningIconWrapper, IntegrationIcon } from '../../common'; -import { useRedirectLink } from '../../../hooks'; -import { FlyoutDataset } from '../../../state_machines/dataset_quality_controller'; +import { useDatasetRedirectLinkTelemetry, useRedirectLink } from '../../../hooks'; import { DegradedDocsPercentageLink } from './degraded_docs_percentage_link'; import { TimeRangeConfig } from '../../../../common/types'; +import { DatasetQualityDetailsLink } from './dataset_quality_details_link'; -const expandDatasetAriaLabel = i18n.translate('xpack.datasetQuality.expandLabel', { - defaultMessage: 'Expand', -}); -const collapseDatasetAriaLabel = i18n.translate('xpack.datasetQuality.collapseLabel', { - defaultMessage: 'Collapse', -}); const nameColumnName = i18n.translate('xpack.datasetQuality.nameColumnName', { defaultMessage: 'Data Set Name', }); @@ -162,52 +154,26 @@ export const getDatasetQualityTableColumns = ({ fieldFormats, canUserMonitorDataset, canUserMonitorAnyDataStream, - selectedDataset, - openFlyout, loadingDataStreamStats, loadingDegradedStats, showFullDatasetNames, isSizeStatsAvailable, isActiveDataset, timeRange, + urlService, }: { fieldFormats: FieldFormatsStart; canUserMonitorDataset: boolean; canUserMonitorAnyDataStream: boolean; - selectedDataset?: FlyoutDataset; loadingDataStreamStats: boolean; loadingDegradedStats: boolean; showFullDatasetNames: boolean; isSizeStatsAvailable: boolean; - openFlyout: (selectedDataset: FlyoutDataset) => void; isActiveDataset: (lastActivity: number) => boolean; timeRange: TimeRangeConfig; + urlService: BrowserUrlService; }): Array> => { return [ - { - name: '', - render: (dataStreamStat: DataStreamStat) => { - const isExpanded = dataStreamStat.rawName === selectedDataset?.rawName; - - return ( - openFlyout(dataStreamStat as FlyoutDataset)} - iconType={isExpanded ? 'minimize' : 'expand'} - title={!isExpanded ? expandDatasetAriaLabel : collapseDatasetAriaLabel} - aria-label={!isExpanded ? expandDatasetAriaLabel : collapseDatasetAriaLabel} - /> - ); - }, - width: '40px', - css: css` - &.euiTableCellContent { - padding: 0; - } - `, - }, { name: ( {nameColumnName} @@ -215,20 +181,22 @@ export const getDatasetQualityTableColumns = ({ field: 'title', sortable: true, render: (title: string, dataStreamStat: DataStreamStat) => { - const { integration, name } = dataStreamStat; + const { integration, name, rawName } = dataStreamStat; return ( - - - - - {title} - {showFullDatasetNames && ( - - {name} - - )} - + + + + + + {title} + {showFullDatasetNames && ( + + {name} + + )} + + ); }, }, @@ -382,9 +350,10 @@ const RedirectLink = ({ title: string; timeRange: TimeRangeConfig; }) => { + const { sendTelemetry } = useDatasetRedirectLinkTelemetry({ rawName: dataStreamStat.rawName }); const redirectLinkProps = useRedirectLink({ dataStreamStat, - telemetry: { page: 'main', navigationSource: NavigationSource.Table }, + sendTelemetry, timeRangeConfig: timeRange, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/dataset_quality_details_link.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/dataset_quality_details_link.tsx new file mode 100644 index 0000000000000..ac73f269d9f5a --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/dataset_quality_details_link.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { BrowserUrlService } from '@kbn/share-plugin/public'; +import { + DATA_QUALITY_DETAILS_LOCATOR_ID, + DataQualityDetailsLocatorParams, +} from '@kbn/deeplinks-observability'; +import { getRouterLinkProps } from '@kbn/router-utils'; +import { EuiHeaderLink } from '@elastic/eui'; + +export const DatasetQualityDetailsLink = React.memo( + ({ + urlService, + dataStream, + children, + }: { + urlService: BrowserUrlService; + dataStream: string; + children: React.ReactNode; + }) => { + const locator = urlService.locators.get( + DATA_QUALITY_DETAILS_LOCATOR_ID + ); + const datasetQualityUrl = locator?.getRedirectUrl({ dataStream }); + const navigateToDatasetQuality = () => { + locator?.navigate({ dataStream }); + }; + + const datasetQualityLinkDetailsProps = getRouterLinkProps({ + href: datasetQualityUrl, + onClick: navigateToDatasetQuality, + }); + + return ( + + {children} + + ); + } +); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/degraded_docs_percentage_link.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/degraded_docs_percentage_link.tsx index 54c393323ccfd..9d32c84891a34 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/degraded_docs_percentage_link.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/degraded_docs_percentage_link.tsx @@ -8,8 +8,7 @@ import { EuiSkeletonRectangle, EuiFlexGroup, EuiLink } from '@elastic/eui'; import React from 'react'; import { _IGNORED } from '../../../../common/es_fields'; -import { NavigationSource } from '../../../services/telemetry'; -import { useRedirectLink } from '../../../hooks'; +import { useDatasetRedirectLinkTelemetry, useRedirectLink } from '../../../hooks'; import { QualityPercentageIndicator } from '../../quality_indicator'; import { DataStreamStat } from '../../../../common/data_streams_stats/data_stream_stat'; import { TimeRangeConfig } from '../../../../common/types'; @@ -27,13 +26,15 @@ export const DegradedDocsPercentageLink = ({ degradedDocs: { percentage, count }, } = dataStreamStat; + const { sendTelemetry } = useDatasetRedirectLinkTelemetry({ + rawName: dataStreamStat.rawName, + query: { language: 'kuery', query: `${_IGNORED}: *` }, + }); + const redirectLinkProps = useRedirectLink({ dataStreamStat, query: { language: 'kuery', query: `${_IGNORED}: *` }, - telemetry: { - page: 'main', - navigationSource: NavigationSource.Table, - }, + sendTelemetry, timeRangeConfig: timeRange, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/table.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/table.tsx index 5bd8783fd0684..a7524198aa24a 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/table.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality/table/table.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React from 'react'; import { EuiBasicTable, EuiEmptyPrompt, @@ -14,8 +15,6 @@ import { EuiText, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { dynamic } from '@kbn/shared-ux-utility'; -import React from 'react'; import { fullDatasetNameDescription, fullDatasetNameLabel, @@ -27,8 +26,6 @@ import { import { useDatasetQualityTable } from '../../../hooks'; import { DescriptiveSwitch } from '../../common/descriptive_switch'; -const Flyout = dynamic(() => import('../../flyout/flyout')); - export const Table = () => { const { sort, @@ -38,8 +35,6 @@ export const Table = () => { columns, loading, resultsCount, - selectedDataset, - closeFlyout, showInactiveDatasets, showFullDatasetNames, canUserMonitorDataset, @@ -107,7 +102,6 @@ export const Table = () => { ) } /> - {selectedDataset && } ); }; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/dataset_quality_details.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/dataset_quality_details.tsx index 522ad22fae429..56632cdad8cfa 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/dataset_quality_details.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/dataset_quality_details.tsx @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule } from '@elastic/eui'; -import { useDatasetQualityDetailsState } from '../../hooks'; +import { useDatasetDetailsTelemetry, useDatasetQualityDetailsState } from '../../hooks'; import { DataStreamNotFoundPrompt } from './index_not_found_prompt'; import { Header } from './header'; import { Overview } from './overview'; @@ -16,10 +16,15 @@ import { Details } from './details'; // eslint-disable-next-line import/no-default-export export default function DatasetQualityDetails() { const { isIndexNotFoundError, dataStream } = useDatasetQualityDetailsState(); + const { startTracking } = useDatasetDetailsTelemetry(); + + useEffect(() => { + startTracking(); + }, [startTracking]); return isIndexNotFoundError ? ( ) : ( - +

diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/fields_list.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/fields_list.tsx index f48ad1d932357..f02b1720d9dfc 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/fields_list.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/fields_list.tsx @@ -32,7 +32,12 @@ export function FieldsList({ {fields.map(({ fieldTitle, fieldValue, isLoading: isFieldLoading, actionsMenu }, index) => ( - + {fieldTitle} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx index 2a0e3e93e32ac..e45253b6405c8 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx @@ -18,19 +18,30 @@ import { import { css } from '@emotion/react'; import React from 'react'; import { openInDiscoverText, openInLogsExplorerText } from '../../../common/translations'; -import { useDatasetQualityDetailsRedirectLink, useDatasetQualityDetailsState } from '../../hooks'; +import { + useDatasetDetailsRedirectLinkTelemetry, + useDatasetDetailsTelemetry, + useDatasetQualityDetailsState, + useRedirectLink, +} from '../../hooks'; import { IntegrationIcon } from '../common'; export function Header() { const { datasetDetails, timeRange, integrationDetails, loadingState } = useDatasetQualityDetailsState(); + const { navigationSources } = useDatasetDetailsTelemetry(); + const { rawName, name: title } = datasetDetails; const euiShadow = useEuiShadow('s'); const { euiTheme } = useEuiTheme(); - const redirectLinkProps = useDatasetQualityDetailsRedirectLink({ + const { sendTelemetry } = useDatasetDetailsRedirectLinkTelemetry({ + navigationSource: navigationSources.Header, + }); + const redirectLinkProps = useRedirectLink({ dataStreamStat: datasetDetails, timeRangeConfig: timeRange, + sendTelemetry, }); const pageTitle = integrationDetails?.integration?.datasets?.[datasetDetails.name] ?? title; @@ -38,15 +49,15 @@ export function Header() { return !loadingState.integrationDetailsLoaded ? ( ) : ( - +

{pageTitle}

export function DataStreamNotFoundPrompt({ dataStream }: { dataStream: string }) { const promptTitle =

{emptyPromptTitle}

; - const promptBody =

{emptyPromptBody(dataStream)}

; + const promptBody = ( + +

{emptyPromptBody(dataStream)}

+
+ ); - return ; + return ( + + ); } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx index ff311032fe69f..3040e81f0e587 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx @@ -14,7 +14,7 @@ import { KibanaErrorBoundary } from '@kbn/shared-ux-error-boundary'; import { flyoutDegradedDocsTrendText } from '../../../../../../common/translations'; import { useKibanaContextForPlugin } from '../../../../../utils'; import { TimeRangeConfig } from '../../../../../../common/types'; -import { useDegradedDocs } from '../../../../../hooks/use_degraded_docs'; +import { useDegradedDocsChart } from '../../../../../hooks'; const CHART_HEIGHT = 180; const DISABLED_ACTIONS = [ @@ -26,7 +26,7 @@ const DISABLED_ACTIONS = [ interface DegradedDocsChartProps extends Pick< - ReturnType, + ReturnType, 'attributes' | 'isChartLoading' | 'onChartLoading' | 'extraActions' > { timeRange: TimeRangeConfig; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx index 985a748e792b1..7c3aea15a6cf1 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx @@ -29,13 +29,15 @@ import { openInLogsExplorerText, overviewDegradedDocsText, } from '../../../../../../common/translations'; -import { useDegradedDocs } from '../../../../../hooks/use_degraded_docs'; import { DegradedDocsChart } from './degraded_docs_chart'; import { - useDatasetQualityDetailsRedirectLink, + useDatasetDetailsRedirectLinkTelemetry, useDatasetQualityDetailsState, + useDegradedDocsChart, + useRedirectLink, } from '../../../../../hooks'; import { _IGNORED } from '../../../../../../common/es_fields'; +import { NavigationSource } from '../../../../../services/telemetry'; const degradedDocsTooltip = ( { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx index b40f563a4dff4..e03e0957b5a52 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx @@ -10,6 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSkeletonTitle, EuiText } from ' import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; import { PrivilegesWarningIconWrapper } from '../../../common'; +import { notAvailableLabel } from '../../../../../common/translations'; const verticalRule = css` width: 1px; @@ -95,8 +96,8 @@ export function PanelIndicator({ <> {userHasPrivilege && ( - -

{value}

+ +

{userHasPrivilege ? value : notAvailableLabel}

)} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/dataset_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/dataset_summary.tsx deleted file mode 100644 index cb35e9c74d334..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/dataset_summary.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; -import { DataStreamDetails, DataStreamSettings } from '../../../common/data_streams_stats'; -import { - datasetCreatedOnText, - flyoutDatasetDetailsText, - datasetLastActivityText, -} from '../../../common/translations'; -import { FieldsList, FieldsListLoading } from './fields_list'; - -interface DatasetSummaryProps { - fieldFormats: FieldFormatsStart; - dataStreamSettings?: DataStreamSettings; - dataStreamSettingsLoading: boolean; - dataStreamDetails?: DataStreamDetails; - dataStreamDetailsLoading: boolean; -} - -export function DatasetSummary({ - dataStreamSettings, - dataStreamSettingsLoading, - dataStreamDetails, - dataStreamDetailsLoading, - fieldFormats, -}: DatasetSummaryProps) { - const dataFormatter = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE, [ - ES_FIELD_TYPES.DATE, - ]); - const formattedLastActivity = dataStreamDetails?.lastActivity - ? dataFormatter.convert(dataStreamDetails?.lastActivity) - : '-'; - const formattedCreatedOn = dataStreamSettings?.createdOn - ? dataFormatter.convert(dataStreamSettings.createdOn) - : '-'; - - return ( - - ); -} - -export function DatasetSummaryLoading() { - return ; -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx deleted file mode 100644 index 5335d5de8692d..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect, useState } from 'react'; -import { css } from '@emotion/react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiSpacer, - EuiTitle, - EuiToolTip, - EuiIcon, - EuiCode, - OnTimeChangeProps, - EuiSkeletonRectangle, -} from '@elastic/eui'; -import { UnifiedBreakdownFieldSelector } from '@kbn/unified-histogram-plugin/public'; -import type { DataViewField } from '@kbn/data-views-plugin/common'; -import { useDegradedDocsChart } from '../../../hooks'; - -import { DEFAULT_TIME_RANGE, DEFAULT_DATEPICKER_REFRESH } from '../../../../common/constants'; -import { overviewDegradedDocsText } from '../../../../common/translations'; -import { DegradedDocsChart } from '../../dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart'; -import { TimeRangeConfig } from '../../../../common/types'; - -export function DegradedDocs({ - dataStream, - timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_DATEPICKER_REFRESH }, - lastReloadTime, - onTimeRangeChange, -}: { - dataStream?: string; - timeRange?: TimeRangeConfig; - lastReloadTime: number; - onTimeRangeChange: (props: Pick) => void; -}) { - const { dataView, breakdown, ...chartProps } = useDegradedDocsChart({ dataStream }); - - const [breakdownDataViewField, setBreakdownDataViewField] = useState( - undefined - ); - - useEffect(() => { - if (breakdown.dataViewField && breakdown.fieldSupportsBreakdown) { - setBreakdownDataViewField(breakdown.dataViewField); - } else { - setBreakdownDataViewField(undefined); - } - - if (breakdown.dataViewField && !breakdown.fieldSupportsBreakdown) { - // TODO: If needed, notify user that the field is not breakable - } - }, [setBreakdownDataViewField, breakdown]); - - return ( - - - - -
{overviewDegradedDocsText}
-
- - - -
- - - - -
- - - - -
- ); -} - -const degradedDocsTooltip = ( - - _ignored - - ), - }} - /> -); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/columns.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/columns.tsx deleted file mode 100644 index 1d7e79b3c0b36..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/columns.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiBasicTableColumn } from '@elastic/eui'; -import { FieldFormat } from '@kbn/field-formats-plugin/common'; -import { formatNumber } from '@elastic/eui'; - -import { DegradedField } from '../../../../common/api_types'; -import { SparkPlot } from './spark_plot'; -import { NUMBER_FORMAT } from '../../../../common/constants'; - -const fieldColumnName = i18n.translate('xpack.datasetQuality.flyout.degradedField.field', { - defaultMessage: 'Field', -}); - -const countColumnName = i18n.translate('xpack.datasetQuality.flyout.degradedField.count', { - defaultMessage: 'Docs count', -}); - -const lastOccurrenceColumnName = i18n.translate( - 'xpack.datasetQuality.flyout.degradedField.lastOccurrence', - { - defaultMessage: 'Last occurrence', - } -); - -export const getDegradedFieldsColumns = ({ - dateFormatter, - isLoading, -}: { - dateFormatter: FieldFormat; - isLoading: boolean; -}): Array> => [ - { - name: fieldColumnName, - field: 'name', - }, - { - name: countColumnName, - sortable: true, - field: 'count', - render: (_, { count, timeSeries }) => { - const countValue = formatNumber(count, NUMBER_FORMAT); - return ; - }, - }, - { - name: lastOccurrenceColumnName, - sortable: true, - field: 'lastOccurrence', - render: (lastOccurrence: number) => { - return dateFormatter.convert(lastOccurrence); - }, - }, -]; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/degraded_fields.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/degraded_fields.tsx deleted file mode 100644 index bd2c20b24171a..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/degraded_fields.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiFlexGroup, EuiPanel, EuiTitle, EuiIconTip } from '@elastic/eui'; -import { flyoutImprovementText, flyoutImprovementTooltip } from '../../../../common/translations'; -import { DegradedFieldTable } from './table'; - -export function DegradedFields() { - return ( - - - -
{flyoutImprovementText}
-
- -
- -
- ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/spark_plot.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/spark_plot.tsx deleted file mode 100644 index 964c3ee434f45..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/spark_plot.tsx +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLoadingChart, - euiPaletteColorBlind, - useEuiTheme, -} from '@elastic/eui'; -import React from 'react'; -import { ScaleType, Settings, Tooltip, Chart, BarSeries } from '@elastic/charts'; -import { i18n } from '@kbn/i18n'; -import { Coordinate } from '../../../../common/types'; - -export function SparkPlot({ - valueLabel, - isLoading, - series, -}: { - valueLabel: React.ReactNode; - isLoading: boolean; - series?: Coordinate[] | null; -}) { - return ( - - - - - {valueLabel} - - ); -} - -function SparkPlotItem({ - isLoading, - series, -}: { - isLoading: boolean; - series?: Coordinate[] | null; -}) { - const { euiTheme } = useEuiTheme(); - const chartSize = { - height: euiTheme.size.l, - width: '80px', - }; - - const commonStyle = { - ...chartSize, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }; - const palette = euiPaletteColorBlind({ rotations: 2 }); - - if (isLoading) { - return ( -
- -
- ); - } - - if (hasValidTimeSeries(series)) { - return ( -
- - - - - -
- ); - } - - return ( -
- -
- ); -} - -function hasValidTimeSeries(series?: Coordinate[] | null): series is Coordinate[] { - return !!series?.some((point) => point.y !== 0); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/table.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/table.tsx deleted file mode 100644 index 1a1baa8aae7cd..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/table.tsx +++ /dev/null @@ -1,54 +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 { EuiBasicTable, EuiEmptyPrompt } from '@elastic/eui'; -import React from 'react'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; -import { useDatasetQualityDegradedField } from '../../../hooks'; -import { getDegradedFieldsColumns } from './columns'; -import { - overviewDegradedFieldsTableLoadingText, - overviewDegradedFieldsTableNoData, -} from '../../../../common/translations'; - -export const DegradedFieldTable = () => { - const { isLoading, pagination, renderedItems, onTableChange, sort, fieldFormats } = - useDatasetQualityDegradedField(); - const dateFormatter = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE, [ - ES_FIELD_TYPES.DATE, - ]); - const columns = getDegradedFieldsColumns({ dateFormatter, isLoading }); - - return ( - {overviewDegradedFieldsTableNoData}

} - hasBorder={false} - titleSize="m" - /> - ) - } - /> - ); -}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx deleted file mode 100644 index 1861d23b69a45..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { ReactNode, Fragment } from 'react'; -import { - EuiFlexGroup, - EuiPanel, - EuiFlexItem, - EuiSpacer, - EuiTitle, - EuiHorizontalRule, - EuiSkeletonTitle, - EuiSkeletonText, - EuiSkeletonRectangle, -} from '@elastic/eui'; - -export function FieldsList({ - title, - fields, - actionsMenu: ActionsMenu, - dataTestSubj = `datasetQualityFlyoutFieldsList-${title.toLowerCase().split(' ').join('_')}`, -}: { - title: string; - fields: Array<{ fieldTitle: string; fieldValue: ReactNode; isLoading: boolean }>; - actionsMenu?: ReactNode; - dataTestSubj?: string; -}) { - return ( - - - - {title} - - {ActionsMenu} - - - - {fields.map(({ fieldTitle, fieldValue, isLoading: isFieldLoading }, index) => ( - - - - - {fieldTitle} - - - - - {fieldValue} - - - - - {index < fields.length - 1 ? : null} - - ))} - - - ); -} - -export function FieldsListLoading() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout.tsx deleted file mode 100644 index cb6944057a2d6..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout.tsx +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { Fragment, useEffect } from 'react'; -import { css } from '@emotion/react'; -import { - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiSpacer, - EuiHorizontalRule, - EuiPanel, - EuiSkeletonRectangle, -} from '@elastic/eui'; -import { dynamic } from '@kbn/shared-ux-utility'; -import { flyoutCancelText } from '../../../common/translations'; -import { useDatasetQualityFlyout, useDatasetDetailsTelemetry } from '../../hooks'; -import { DatasetSummary, DatasetSummaryLoading } from './dataset_summary'; -import { Header } from './header'; -import { FlyoutProps } from './types'; -import { BasicDataStream } from '../../../common/types'; - -const FlyoutSummary = dynamic(() => import('./flyout_summary/flyout_summary')); -const IntegrationSummary = dynamic(() => import('./integration_summary')); - -// Allow for lazy loading -// eslint-disable-next-line import/no-default-export -export default function Flyout({ dataset, closeFlyout }: FlyoutProps) { - const { - dataStreamStat, - dataStreamSettings, - dataStreamDetails, - isNonAggregatable, - fieldFormats, - timeRange, - loadingState, - flyoutLoading, - integration, - } = useDatasetQualityFlyout(); - - const linkDetails: BasicDataStream = { - name: dataset.name, - rawName: dataset.rawName, - integration: integration?.integrationDetails, - type: dataset.type, - namespace: dataset.namespace, - }; - - const title = integration?.integrationDetails?.datasets?.[dataset.name] ?? dataset.name; - - const { startTracking } = useDatasetDetailsTelemetry(); - - useEffect(() => { - startTracking(); - }, [startTracking]); - - return ( - - {flyoutLoading ? ( - - ) : ( - <> -
- - - - - - - - - {loadingState.dataStreamDetailsLoading && loadingState.dataStreamSettingsLoading ? ( - - ) : dataStreamStat ? ( - - - - {integration?.integrationDetails && ( - <> - - - - )} - - ) : null} - - - - - - - - {flyoutCancelText} - - - - - - )} - - ); -} - -const flyoutBodyStyles = css` - .euiFlyoutBody__overflowContent { - padding: 0; - } -`; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary.tsx deleted file mode 100644 index 5b89c43ad92d1..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary.tsx +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useCallback, useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - OnRefreshProps, - OnTimeChangeProps, - EuiSpacer, - EuiFlexGroup, - EuiFlexItem, - EuiCallOut, - EuiLink, - EuiCode, -} from '@elastic/eui'; - -import { FormattedMessage } from '@kbn/i18n-react'; -import { DegradedDocs } from '../degraded_docs_trend/degraded_docs'; -import { DataStreamDetails } from '../../../../common/api_types'; -import { DEFAULT_TIME_RANGE, DEFAULT_DATEPICKER_REFRESH } from '../../../../common/constants'; -import { useDatasetQualityContext } from '../../dataset_quality/context'; -import { FlyoutSummaryHeader } from './flyout_summary_header'; -import { FlyoutSummaryKpis, FlyoutSummaryKpisLoading } from './flyout_summary_kpis'; -import { DegradedFields } from '../degraded_fields/degraded_fields'; -import { TimeRangeConfig } from '../../../../common/types'; -import { FlyoutDataset } from '../../../state_machines/dataset_quality_controller'; - -const nonAggregatableWarningTitle = i18n.translate('xpack.datasetQuality.nonAggregatable.title', { - defaultMessage: 'Your request may take longer to complete', -}); - -const nonAggregatableWarningDescription = (dataset: string) => ( - - {dataset} - - ), - howToFixIt: ( - - {i18n.translate( - 'xpack.datasetQuality.flyout.nonAggregatableDatasets.link.title', - { - defaultMessage: 'rollover', - } - )} - - ), - }} - /> - ), - }} - /> - ), - }} - /> -); - -// Allow for lazy loading -// eslint-disable-next-line import/no-default-export -export default function FlyoutSummary({ - dataStream, - dataStreamStat, - dataStreamDetails, - isNonAggregatable, - dataStreamDetailsLoading, - timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_DATEPICKER_REFRESH }, -}: { - dataStream: string; - dataStreamStat?: FlyoutDataset; - dataStreamDetails?: DataStreamDetails; - dataStreamDetailsLoading: boolean; - timeRange?: TimeRangeConfig; - isNonAggregatable?: boolean; -}) { - const { service } = useDatasetQualityContext(); - const [lastReloadTime, setLastReloadTime] = useState(Date.now()); - - const updateTimeRange = useCallback( - ({ start, end, refreshInterval }: OnRefreshProps) => { - service.send({ - type: 'UPDATE_INSIGHTS_TIME_RANGE', - timeRange: { - from: start, - to: end, - refresh: { ...DEFAULT_DATEPICKER_REFRESH, value: refreshInterval }, - }, - }); - }, - [service] - ); - - const handleTimeChange = useCallback( - ({ isInvalid, ...timeRangeProps }: OnTimeChangeProps) => { - if (!isInvalid) { - updateTimeRange({ refreshInterval: timeRange.refresh.value, ...timeRangeProps }); - } - }, - [updateTimeRange, timeRange.refresh] - ); - - const handleTimeRangeChange = useCallback( - ({ start, end }: Pick) => { - updateTimeRange({ start, end, refreshInterval: timeRange.refresh.value }); - }, - [updateTimeRange, timeRange.refresh] - ); - - const handleRefresh = useCallback( - (refreshProps: OnRefreshProps) => { - updateTimeRange(refreshProps); - setLastReloadTime(Date.now()); - }, - [updateTimeRange] - ); - - return ( - <> - {isNonAggregatable && ( - - - -

{nonAggregatableWarningDescription(dataStream)}

-
-
-
- )} - - - - - {dataStreamStat ? ( - - ) : ( - - )} - - - - - - - - - - ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_header.tsx deleted file mode 100644 index c0ee7303b51a5..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_header.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { css } from '@emotion/react'; -import { - EuiFlexGroup, - EuiIcon, - EuiSuperDatePicker, - EuiTitle, - EuiToolTip, - OnRefreshProps, - OnTimeChangeProps, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; - -import { flyoutSummaryText } from '../../../../common/translations'; -import { TimeRangeConfig } from '../../../../common/types'; - -export function FlyoutSummaryHeader({ - timeRange, - onTimeChange, - onRefresh, -}: { - timeRange: TimeRangeConfig; - onTimeChange: (timeChangeProps: OnTimeChangeProps) => void; - onRefresh: (refreshProps: OnRefreshProps) => void; -}) { - return ( - - - - {flyoutSummaryText} - - - - - - - - - - - ); -} - -const flyoutSummaryTooltip = ( - -); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpi_item.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpi_item.tsx deleted file mode 100644 index 767cd8ec41f4f..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpi_item.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiTitle, - EuiText, - EuiLink, - useEuiTheme, - EuiSkeletonTitle, - EuiSkeletonRectangle, -} from '@elastic/eui'; - -import { PrivilegesWarningIconWrapper } from '../../common'; -import { notAvailableLabel } from '../../../../common/translations'; -import type { getSummaryKpis } from './get_summary_kpis'; - -export function FlyoutSummaryKpiItem({ - title, - value, - link, - isLoading, - userHasPrivilege, -}: ReturnType[number] & { isLoading: boolean }) { - const { euiTheme } = useEuiTheme(); - - return ( - - - - - -
{title}
-
- - - <> - -
- {link ? ( - - - {link.label} - - - ) : null} -
- - - -

{userHasPrivilege ? value : notAvailableLabel}

-
-
-
-
-
- ); -} - -export function FlyoutSummaryKpiItemLoading({ title }: { title: string }) { - return ( - - ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpis.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpis.tsx deleted file mode 100644 index 47b41712dc7f5..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpis.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; - -import { _IGNORED } from '../../../../common/es_fields'; - -import { DataStreamDetails } from '../../../../common/api_types'; -import { useKibanaContextForPlugin } from '../../../utils'; -import { NavigationSource } from '../../../services/telemetry'; -import { useDatasetDetailsTelemetry, useRedirectLink } from '../../../hooks'; -import { FlyoutDataset } from '../../../state_machines/dataset_quality_controller'; -import { FlyoutSummaryKpiItem, FlyoutSummaryKpiItemLoading } from './flyout_summary_kpi_item'; -import { getSummaryKpis } from './get_summary_kpis'; -import { TimeRangeConfig } from '../../../../common/types'; - -export function FlyoutSummaryKpis({ - dataStreamStat, - dataStreamDetails, - isLoading, - timeRange, -}: { - dataStreamStat: FlyoutDataset; - dataStreamDetails?: DataStreamDetails; - isLoading: boolean; - timeRange: TimeRangeConfig; -}) { - const { - services: { observabilityShared }, - } = useKibanaContextForPlugin(); - const telemetry = useDatasetDetailsTelemetry(); - const hostsLocator = observabilityShared.locators.infra.hostsLocator; - - const degradedDocsLinkProps = useRedirectLink({ - dataStreamStat, - query: { language: 'kuery', query: `${_IGNORED}: *` }, - timeRangeConfig: timeRange, - telemetry: { - page: 'details', - navigationSource: NavigationSource.Summary, - }, - }); - - const kpis = useMemo( - () => - getSummaryKpis({ - dataStreamDetails, - timeRange, - degradedDocsLinkProps, - hostsLocator, - telemetry, - }), - [dataStreamDetails, degradedDocsLinkProps, hostsLocator, telemetry, timeRange] - ); - - return ( - - - {kpis.map((kpi) => ( - - - - ))} - - - ); -} - -export function FlyoutSummaryKpisLoading() { - const telemetry = useDatasetDetailsTelemetry(); - - return ( - - - {getSummaryKpis({ telemetry }).map(({ title }) => ( - - - - ))} - - - ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.test.ts b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.test.ts deleted file mode 100644 index 28f5334e2f199..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.test.ts +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { formatNumber } from '@elastic/eui'; -import type { useKibanaContextForPlugin } from '../../../utils'; -import type { useDatasetDetailsTelemetry } from '../../../hooks'; - -import { - BYTE_NUMBER_FORMAT, - DEFAULT_DATEPICKER_REFRESH, - DEFAULT_TIME_RANGE, - MAX_HOSTS_METRIC_VALUE, -} from '../../../../common/constants'; -import { - overviewDegradedDocsText, - flyoutDocsCountTotalText, - flyoutHostsText, - flyoutServicesText, - flyoutShowAllText, - flyoutSizeText, -} from '../../../../common/translations'; -import { getSummaryKpis } from './get_summary_kpis'; -import { TimeRangeConfig } from '../../../../common/types'; - -const dataStreamDetails = { - services: { - service1: ['service1Instance1', 'service1Instance2'], - service2: ['service2Instance1'], - }, - docsCount: 1000, - sizeBytes: 5000, - hosts: { - host1: ['host1Instance1', 'host1Instance2'], - host2: ['host2Instance1'], - }, - degradedDocsCount: 200, -}; - -const timeRange: TimeRangeConfig = { - ...DEFAULT_TIME_RANGE, - refresh: DEFAULT_DATEPICKER_REFRESH, - from: 'now-15m', - to: 'now', -}; - -const degradedDocsLinkProps = { - linkProps: { href: 'http://exploratory-view/degraded-docs', onClick: () => {} }, - navigate: () => {}, - isLogsExplorerAvailable: true, -}; -const hostsRedirectUrl = 'http://hosts/metric/'; - -const hostsLocator = { - getRedirectUrl: () => hostsRedirectUrl, -} as unknown as ReturnType< - typeof useKibanaContextForPlugin ->['services']['observabilityShared']['locators']['infra']['hostsLocator']; - -const telemetry = { - trackDetailsNavigated: () => {}, -} as unknown as ReturnType; - -describe('getSummaryKpis', () => { - it('should return the correct KPIs', () => { - const result = getSummaryKpis({ - dataStreamDetails, - timeRange, - degradedDocsLinkProps, - hostsLocator, - telemetry, - }); - - expect(result).toEqual([ - { - title: flyoutDocsCountTotalText, - value: '1,000', - userHasPrivilege: true, - }, - { - title: flyoutSizeText, - value: formatNumber(dataStreamDetails.sizeBytes ?? 0, BYTE_NUMBER_FORMAT), - userHasPrivilege: false, - }, - { - title: flyoutServicesText, - value: '3', - link: undefined, - userHasPrivilege: true, - }, - { - title: flyoutHostsText, - value: '3', - link: undefined, - userHasPrivilege: true, - }, - { - title: overviewDegradedDocsText, - value: '200', - link: { - label: flyoutShowAllText, - props: degradedDocsLinkProps.linkProps, - }, - userHasPrivilege: true, - }, - ]); - }); - - it('show X+ if number of hosts or services exceed MAX_HOSTS_METRIC_VALUE', () => { - const services = { - service1: new Array(MAX_HOSTS_METRIC_VALUE + 1) - .fill('service1Instance') - .map((_, i) => `service1Instance${i}`), - }; - - const host3 = new Array(MAX_HOSTS_METRIC_VALUE + 1) - .fill('host3Instance') - .map((_, i) => `host3Instance${i}`); - - const detailsWithMaxPlusHosts = { - ...dataStreamDetails, - services, - hosts: { ...dataStreamDetails.hosts, host3 }, - }; - - const result = getSummaryKpis({ - dataStreamDetails: detailsWithMaxPlusHosts, - timeRange, - degradedDocsLinkProps, - hostsLocator, - telemetry, - }); - - expect(result).toEqual([ - { - title: flyoutDocsCountTotalText, - value: '1,000', - userHasPrivilege: true, - }, - { - title: flyoutSizeText, - value: formatNumber(dataStreamDetails.sizeBytes ?? 0, BYTE_NUMBER_FORMAT), - userHasPrivilege: false, - }, - { - title: flyoutServicesText, - value: '50+', - link: undefined, - userHasPrivilege: true, - }, - { - title: flyoutHostsText, - value: '54+', - link: undefined, - userHasPrivilege: true, - }, - { - title: overviewDegradedDocsText, - value: '200', - link: { - label: flyoutShowAllText, - props: degradedDocsLinkProps.linkProps, - }, - userHasPrivilege: true, - }, - ]); - }); -}); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.ts b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.ts deleted file mode 100644 index b574e1e8a8160..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.ts +++ /dev/null @@ -1,167 +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 { formatNumber } from '@elastic/eui'; -import { getRouterLinkProps, RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props'; -import { - BYTE_NUMBER_FORMAT, - DEFAULT_DATEPICKER_REFRESH, - DEFAULT_TIME_RANGE, - MAX_HOSTS_METRIC_VALUE, - NUMBER_FORMAT, -} from '../../../../common/constants'; -import { - overviewDegradedDocsText, - flyoutDocsCountTotalText, - flyoutHostsText, - flyoutServicesText, - flyoutShowAllText, - flyoutSizeText, -} from '../../../../common/translations'; -import { DataStreamDetails } from '../../../../common/api_types'; -import { NavigationTarget, NavigationSource } from '../../../services/telemetry'; -import { useKibanaContextForPlugin } from '../../../utils'; -import type { useRedirectLink, useDatasetDetailsTelemetry } from '../../../hooks'; -import { TimeRangeConfig } from '../../../../common/types'; - -export function getSummaryKpis({ - dataStreamDetails, - timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_DATEPICKER_REFRESH }, - degradedDocsLinkProps, - hostsLocator, - telemetry, -}: { - dataStreamDetails?: DataStreamDetails; - timeRange?: TimeRangeConfig; - degradedDocsLinkProps?: ReturnType; - hostsLocator?: ReturnType< - typeof useKibanaContextForPlugin - >['services']['observabilityShared']['locators']['infra']['hostsLocator']; - telemetry: ReturnType; -}): Array<{ - title: string; - value: string; - link?: { label: string; props: RouterLinkProps }; - userHasPrivilege: boolean; -}> { - const services = dataStreamDetails?.services ?? {}; - const serviceKeys = Object.keys(services); - const countOfServices = serviceKeys - .map((key: string) => services[key].length) - .reduce((a, b) => a + b, 0); - - // @ts-ignore // TODO: Add link to APM services page when possible - https://github.com/elastic/kibana/issues/179904 - const servicesLink = { - label: flyoutShowAllText, - props: getRouterLinkProps({ - href: undefined, - onClick: () => { - telemetry.trackDetailsNavigated(NavigationTarget.Services, NavigationSource.Summary); - }, - }), - }; - - return [ - { - title: flyoutDocsCountTotalText, - value: formatNumber(dataStreamDetails?.docsCount ?? 0, NUMBER_FORMAT), - userHasPrivilege: true, - }, - // dataStreamDetails.sizeBytes = null indicates it's Serverless where `_stats` API isn't available - ...(dataStreamDetails?.sizeBytes !== null // Only show when not in Serverless - ? [ - { - title: flyoutSizeText, - value: formatNumber(dataStreamDetails?.sizeBytes ?? 0, BYTE_NUMBER_FORMAT), - userHasPrivilege: Boolean(dataStreamDetails?.userPrivileges?.canMonitor), - }, - ] - : []), - { - title: flyoutServicesText, - value: formatMetricValueForMax(countOfServices, MAX_HOSTS_METRIC_VALUE, NUMBER_FORMAT), - link: undefined, - userHasPrivilege: true, - }, - getHostsKpi(dataStreamDetails?.hosts, timeRange, telemetry, hostsLocator), - { - title: overviewDegradedDocsText, - value: formatNumber(dataStreamDetails?.degradedDocsCount ?? 0, NUMBER_FORMAT), - link: - degradedDocsLinkProps && degradedDocsLinkProps.linkProps.href - ? { - label: flyoutShowAllText, - props: degradedDocsLinkProps.linkProps, - } - : undefined, - userHasPrivilege: true, - }, - ]; -} - -function getHostsKpi( - dataStreamHosts: DataStreamDetails['hosts'], - timeRange: TimeRangeConfig, - telemetry: ReturnType, - hostsLocator?: ReturnType< - typeof useKibanaContextForPlugin - >['services']['observabilityShared']['locators']['infra']['hostsLocator'] -) { - const hosts = dataStreamHosts ?? {}; - const hostKeys = Object.keys(hosts); - const countOfHosts = hostKeys - .map((key: string) => hosts[key].length) - .reduce( - ({ count, anyHostExceedsMax }, hostCount) => ({ - count: count + hostCount, - anyHostExceedsMax: anyHostExceedsMax || hostCount > MAX_HOSTS_METRIC_VALUE, - }), - { count: 0, anyHostExceedsMax: false } - ); - - // Create a query so from hostKeys so that (key: value OR key: value2) - const hostsKuery = hostKeys - .filter((key) => hosts[key].length > 0) - .map((key) => hosts[key].map((value) => `${key}: "${value}"`).join(' OR ')) - .join(' OR '); - const hostsUrl = hostsLocator?.getRedirectUrl({ - query: { language: 'kuery', query: hostsKuery }, - dateRange: { from: timeRange.from, to: timeRange.to }, - limit: countOfHosts.count, - }); - - // @ts-ignore // TODO: Add link to Infra Hosts page when possible - const hostsLink = { - label: flyoutShowAllText, - props: getRouterLinkProps({ - href: hostsUrl, - onClick: () => { - telemetry.trackDetailsNavigated(NavigationTarget.Hosts, NavigationSource.Summary); - }, - }), - }; - - return { - title: flyoutHostsText, - value: formatMetricValueForMax( - countOfHosts.anyHostExceedsMax ? countOfHosts.count + 1 : countOfHosts.count, - countOfHosts.count, - NUMBER_FORMAT - ), - link: undefined, - userHasPrivilege: true, - }; -} - -/** - * Formats a metric value to show a '+' sign if it's above a max value e.g. 50+ - */ -function formatMetricValueForMax(value: number, max: number, numberFormat: string): string { - const exceedsMax = value > max; - const valueToShow = exceedsMax ? max : value; - return `${formatNumber(valueToShow, numberFormat)}${exceedsMax ? '+' : ''}`; -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/header.tsx deleted file mode 100644 index 1117c7da12a1b..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/header.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiFlyoutHeader, - EuiSkeletonTitle, - EuiTitle, - useEuiShadow, - useEuiTheme, -} from '@elastic/eui'; -import { css } from '@emotion/react'; -import React from 'react'; -import { openInDiscoverText, openInLogsExplorerText } from '../../../common/translations'; -import { NavigationSource } from '../../services/telemetry'; -import { useRedirectLink } from '../../hooks'; -import { IntegrationIcon } from '../common'; -import { BasicDataStream, TimeRangeConfig } from '../../../common/types'; - -export function Header({ - linkDetails, - loading, - title, - timeRange, -}: { - linkDetails: BasicDataStream; - loading: boolean; - title: string; - timeRange: TimeRangeConfig; -}) { - const { integration } = linkDetails; - const euiShadow = useEuiShadow('s'); - const { euiTheme } = useEuiTheme(); - const redirectLinkProps = useRedirectLink({ - dataStreamStat: linkDetails, - telemetry: { - page: 'details', - navigationSource: NavigationSource.Header, - }, - timeRangeConfig: timeRange, - }); - - return ( - - {loading ? ( - - ) : ( - - - - -

{title}

-
-
- -
-
-
- - - - {redirectLinkProps.isLogsExplorerAvailable - ? openInLogsExplorerText - : openInDiscoverText} - - - -
- )} -
- ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_actions_menu.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_actions_menu.tsx deleted file mode 100644 index 99afb7f269df5..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_actions_menu.tsx +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - EuiButtonEmpty, - EuiButtonIcon, - EuiContextMenu, - EuiContextMenuPanelDescriptor, - EuiContextMenuPanelItemDescriptor, - EuiPopover, - EuiSkeletonRectangle, -} from '@elastic/eui'; -import { css } from '@emotion/react'; -import { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props'; -import { useDatasetQualityFlyout } from '../../hooks'; -import { useFlyoutIntegrationActions } from '../../hooks/use_flyout_integration_actions'; -import { Integration } from '../../../common/data_streams_stats/integration'; -import { Dashboard } from '../../../common/api_types'; - -const integrationActionsText = i18n.translate('xpack.datasetQuality.flyoutIntegrationActionsText', { - defaultMessage: 'Integration actions', -}); - -const seeIntegrationText = i18n.translate('xpack.datasetQuality.flyoutSeeIntegrationActionText', { - defaultMessage: 'See integration', -}); - -const indexTemplateText = i18n.translate('xpack.datasetQuality.flyoutIndexTemplateActionText', { - defaultMessage: 'Index template', -}); - -const viewDashboardsText = i18n.translate('xpack.datasetQuality.flyoutViewDashboardsActionText', { - defaultMessage: 'View dashboards', -}); - -export function IntegrationActionsMenu({ - integration, - dashboards, - dashboardsLoading, -}: { - integration: Integration; - dashboards: Dashboard[]; - dashboardsLoading: boolean; -}) { - const { dataStreamStat, canUserAccessDashboards, canUserViewIntegrations } = - useDatasetQualityFlyout(); - const { version, name: integrationName } = integration; - const { type, name } = dataStreamStat!; - const { - isOpen, - handleCloseMenu, - handleToggleMenu, - getIntegrationOverviewLinkProps, - getIndexManagementLinkProps, - getDashboardLinkProps, - } = useFlyoutIntegrationActions(); - - const actionButton = ( - - ); - - const MenuActionItem = ({ - dataTestSubject, - buttonText, - routerLinkProps, - iconType, - disabled = false, - }: { - dataTestSubject: string; - buttonText: string | React.ReactNode; - routerLinkProps: RouterLinkProps; - iconType: string; - disabled?: boolean; - }) => ( - - {buttonText} - - ); - - const panelItems = useMemo(() => { - const firstLevelItems: EuiContextMenuPanelItemDescriptor[] = [ - ...(canUserViewIntegrations - ? [ - { - renderItem: () => ( - - ), - }, - ] - : []), - { - renderItem: () => ( - - ), - }, - { - isSeparator: true, - key: 'sep', - }, - ]; - - if (dashboards.length && canUserAccessDashboards) { - firstLevelItems.push({ - icon: 'dashboardApp', - panel: 1, - name: viewDashboardsText, - 'data-test-subj': 'datasetQualityFlyoutIntegrationActionViewDashboards', - disabled: false, - }); - } else if (dashboardsLoading) { - firstLevelItems.push({ - icon: 'dashboardApp', - name: , - 'data-test-subj': 'datasetQualityFlyoutIntegrationActionDashboardsLoading', - disabled: true, - }); - } - - const panel: EuiContextMenuPanelDescriptor[] = [ - { - id: 0, - items: firstLevelItems, - }, - { - id: 1, - title: viewDashboardsText, - items: dashboards.map((dashboard) => { - return { - renderItem: () => ( - - ), - }; - }), - }, - ]; - - return panel; - }, [ - dashboards, - getDashboardLinkProps, - getIndexManagementLinkProps, - getIntegrationOverviewLinkProps, - integrationName, - name, - type, - version, - dashboardsLoading, - canUserAccessDashboards, - canUserViewIntegrations, - ]); - - return ( - - - - ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_summary.tsx deleted file mode 100644 index 53262c7821ce7..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_summary.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFlexGroup, EuiBadge, EuiText } from '@elastic/eui'; -import React from 'react'; -import { css } from '@emotion/react'; -import { - flyoutIntegrationDetailsText, - flyoutIntegrationNameText, - integrationVersionText, -} from '../../../common/translations'; -import { IntegrationIcon } from '../common'; -import { FieldsList } from './fields_list'; -import { IntegrationActionsMenu } from './integration_actions_menu'; -import { Integration } from '../../../common/data_streams_stats/integration'; -import { Dashboard } from '../../../common/api_types'; - -// Allow for lazy loading -// eslint-disable-next-line import/no-default-export -export default function IntegrationSummary({ - integration, - dashboards, - dashboardsLoading, -}: { - integration: Integration; - dashboards: Dashboard[]; - dashboardsLoading: boolean; -}) { - const { name, version } = integration; - - const integrationActionsMenu = ( - - ); - return ( - - - - {name} - - - ), - isLoading: false, - }, - { - fieldTitle: integrationVersionText, - fieldValue: version, - isLoading: false, - }, - ]} - /> - ); -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts index 7424e13b0f93c..ea4443a61a8ff 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts @@ -11,12 +11,10 @@ import equal from 'fast-deep-equal'; import { distinctUntilChanged, from, map } from 'rxjs'; import { interpret } from 'xstate'; import { IDataStreamsStatsClient } from '../../services/data_streams_stats'; -import { IDataStreamDetailsClient } from '../../services/data_stream_details'; import { createDatasetQualityControllerStateMachine, DEFAULT_CONTEXT, } from '../../state_machines/dataset_quality_controller'; -import { DatasetQualityStartDeps } from '../../types'; import { getContextFromPublicState, getPublicStateFromContext } from './public_state'; import { DatasetQualityController, DatasetQualityPublicStateUpdate } from './types'; @@ -24,13 +22,11 @@ type InitialState = DatasetQualityPublicStateUpdate; interface Dependencies { core: CoreStart; - plugins: DatasetQualityStartDeps; dataStreamStatsClient: IDataStreamsStatsClient; - dataStreamDetailsClient: IDataStreamDetailsClient; } export const createDatasetQualityControllerFactory = - ({ core, plugins, dataStreamStatsClient, dataStreamDetailsClient }: Dependencies) => + ({ core, dataStreamStatsClient }: Dependencies) => async ({ initialState = DEFAULT_CONTEXT, }: { @@ -40,10 +36,8 @@ export const createDatasetQualityControllerFactory = const machine = createDatasetQualityControllerStateMachine({ initialContext, - plugins, toasts: core.notifications.toasts, dataStreamStatsClient, - dataStreamDetailsClient, }); const service = interpret(machine, { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts index 1bf0088bc7a48..ea5ae63f97073 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DatasetTableSortField, DegradedFieldSortField } from '../../hooks'; +import { DatasetTableSortField } from '../../hooks'; import { DatasetQualityControllerContext, DEFAULT_CONTEXT, @@ -17,7 +17,6 @@ export const getPublicStateFromContext = ( ): DatasetQualityPublicState => { return { table: context.table, - flyout: context.flyout, filters: context.filters, }; }; @@ -36,22 +35,6 @@ export const getContextFromPublicState = ( } : DEFAULT_CONTEXT.table.sort, }, - flyout: { - ...DEFAULT_CONTEXT.flyout, - ...publicState.flyout, - degradedFields: { - table: { - ...DEFAULT_CONTEXT.flyout.degradedFields.table, - ...publicState.flyout?.degradedFields?.table, - sort: publicState.flyout?.degradedFields?.table?.sort - ? { - ...publicState.flyout.degradedFields.table.sort, - field: publicState.flyout.degradedFields.table.sort.field as DegradedFieldSortField, - } - : DEFAULT_CONTEXT.flyout.degradedFields.table.sort, - }, - }, - }, filters: { ...DEFAULT_CONTEXT.filters, ...publicState.filters, diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts index decb7454bd193..81b2de0088a52 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts @@ -9,9 +9,7 @@ import { Observable } from 'rxjs'; import { DatasetQualityControllerStateService, WithFilters, - WithFlyoutOptions, WithTableOptions, - DegradedFields, } from '../../state_machines/dataset_quality_controller'; export interface DatasetQualityController { @@ -25,25 +23,10 @@ export type DatasetQualityTableOptions = Partial< Omit & { sort: TableSortOptions } >; -type DegradedFieldSortOptions = Omit & { field: string }; - -export type DatasetQualityDegradedFieldTableOptions = Partial< - Omit & { - sort: DegradedFieldSortOptions; - } ->; - -export type DatasetQualityFlyoutOptions = Partial< - Omit & { - degradedFields: { table?: DatasetQualityDegradedFieldTableOptions }; - } ->; - export type DatasetQualityFilterOptions = Partial; export interface DatasetQualityPublicState { table: DatasetQualityTableOptions; - flyout: DatasetQualityFlyoutOptions; filters: DatasetQualityFilterOptions; } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts index 65ca53c073d42..b5a295a897bd5 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts @@ -28,7 +28,7 @@ export type DatasetQualityDetailsPublicState = WithDefaultControllerState; // a must and everything else can be optional. The table inside the // degradedFields must accept field property as string export type DatasetQualityDetailsPublicStateUpdate = Partial< - Pick + Pick > & { dataStream: string; } & { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts index 5c746e2f1177b..ad588fd0b673f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts @@ -6,14 +6,13 @@ */ export * from './use_dataset_quality_table'; -export * from './use_dataset_quality_flyout'; export * from './use_degraded_docs_chart'; export * from './use_redirect_link'; export * from './use_summary_panel'; export * from './use_create_dataview'; -export * from './use_dataset_quality_degraded_field'; -export * from './use_telemetry'; +export * from './use_redirect_link_telemetry'; export * from './use_dataset_quality_details_state'; -export * from './use_dataset_quality_details_redirect_link'; export * from './use_degraded_fields'; export * from './use_integration_actions'; +export * from './use_dataset_telemetry'; +export * from './use_dataset_details_telemetry'; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts new file mode 100644 index 0000000000000..f613d3af7fdc4 --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts @@ -0,0 +1,200 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback, useEffect, useMemo } from 'react'; +import { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props'; +import { getDateISORange } from '@kbn/timerange'; +import { useDatasetQualityDetailsState } from './use_dataset_quality_details_state'; +import { DatasetDetailsEbtProps, NavigationSource, NavigationTarget } from '../services/telemetry'; +import { BasicDataStream, TimeRangeConfig } from '../../common/types'; +import { DataStreamDetails } from '../../common/api_types'; +import { Integration } from '../../common/data_streams_stats/integration'; +import { mapPercentageToQuality } from '../../common/utils'; +import { MASKED_FIELD_PLACEHOLDER, UNKOWN_FIELD_PLACEHOLDER } from '../../common/constants'; + +export function useDatasetDetailsTelemetry() { + const { + telemetryClient, + datasetDetails, + dataStreamDetails, + timeRange, + canUserViewIntegrations, + canUserAccessDashboards, + breakdownField, + isNonAggregatable, + isBreakdownFieldEcs, + integrationDetails, + loadingState, + } = useDatasetQualityDetailsState(); + + const ebtProps = useMemo(() => { + if (dataStreamDetails && timeRange && !loadingState.dataStreamDetailsLoading) { + return getDatasetDetailsEbtProps({ + datasetDetails, + dataStreamDetails, + timeRange, + canUserViewIntegrations, + canUserAccessDashboards, + breakdownField, + isNonAggregatable, + isBreakdownFieldEcs, + integration: integrationDetails.integration, + }); + } + + return undefined; + }, [ + dataStreamDetails, + timeRange, + loadingState.dataStreamDetailsLoading, + datasetDetails, + canUserViewIntegrations, + canUserAccessDashboards, + breakdownField, + isNonAggregatable, + isBreakdownFieldEcs, + integrationDetails.integration, + ]); + + const startTracking = useCallback(() => { + telemetryClient.startDatasetDetailsTracking(); + }, [telemetryClient]); + + // Report opening dataset details + useEffect(() => { + const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); + if (datasetDetailsTrackingState === 'started' && ebtProps) { + telemetryClient.trackDatasetDetailsOpened(ebtProps); + } + }, [ebtProps, telemetryClient]); + + const trackDetailsNavigated = useCallback( + (target: NavigationTarget, source: NavigationSource, isDegraded = false) => { + const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); + if ( + (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') && + ebtProps + ) { + telemetryClient.trackDatasetDetailsNavigated({ + ...ebtProps, + filters: { + is_degraded: isDegraded, + }, + target, + source, + }); + } else { + throw new Error( + 'Cannot report dataset details navigation telemetry without required data and state' + ); + } + }, + [ebtProps, telemetryClient] + ); + + const trackDatasetDetailsBreakdownFieldChanged = useCallback(() => { + const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); + if ( + (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') && + ebtProps + ) { + telemetryClient.trackDatasetDetailsBreakdownFieldChanged({ + ...ebtProps, + breakdown_field: ebtProps.breakdown_field, + }); + } + }, [ebtProps, telemetryClient]); + + const wrapLinkPropsForTelemetry = useCallback( + ( + props: RouterLinkProps, + target: NavigationTarget, + source: NavigationSource, + isDegraded = false + ) => { + return { + ...props, + onClick: (event: Parameters[0]) => { + trackDetailsNavigated(target, source, isDegraded); + if (props.onClick) { + props.onClick(event); + } + }, + }; + }, + [trackDetailsNavigated] + ); + + return { + startTracking, + trackDetailsNavigated, + wrapLinkPropsForTelemetry, + navigationTargets: NavigationTarget, + navigationSources: NavigationSource, + trackDatasetDetailsBreakdownFieldChanged, + }; +} + +function getDatasetDetailsEbtProps({ + datasetDetails, + dataStreamDetails, + timeRange, + canUserViewIntegrations, + canUserAccessDashboards, + breakdownField, + isNonAggregatable, + isBreakdownFieldEcs, + integration, +}: { + datasetDetails: BasicDataStream; + dataStreamDetails: DataStreamDetails; + timeRange: TimeRangeConfig; + canUserViewIntegrations: boolean; + canUserAccessDashboards: boolean; + breakdownField?: string; + isNonAggregatable: boolean; + isBreakdownFieldEcs: boolean; + integration?: Integration; +}): DatasetDetailsEbtProps { + const indexName = datasetDetails.rawName; + const dataStream = { + dataset: datasetDetails.name, + namespace: datasetDetails.namespace, + type: datasetDetails.type, + }; + const degradedDocs = dataStreamDetails?.degradedDocsCount ?? 0; + const totalDocs = dataStreamDetails?.docsCount ?? 0; + const degradedPercentage = + totalDocs > 0 ? Number(((degradedDocs / totalDocs) * 100).toFixed(2)) : 0; + const health = mapPercentageToQuality(degradedPercentage); + const { startDate: from, endDate: to } = getDateISORange(timeRange); + + return { + index_name: indexName, + data_stream: dataStream, + privileges: { + can_monitor_data_stream: true, + can_view_integrations: canUserViewIntegrations, + can_view_dashboards: canUserAccessDashboards, + }, + data_stream_aggregatable: !isNonAggregatable, + data_stream_health: health, + from, + to, + degraded_percentage: degradedPercentage, + integration: integration?.name, + breakdown_field: breakdownField + ? isBreakdownFieldEcs === null + ? UNKOWN_FIELD_PLACEHOLDER + : getMaskedBreakdownField(breakdownField, isBreakdownFieldEcs) + : breakdownField, + }; +} + +function getMaskedBreakdownField(breakdownField: string, isBreakdownFieldEcs: boolean) { + return isBreakdownFieldEcs ? breakdownField : MASKED_FIELD_PLACEHOLDER; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_degraded_field.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_degraded_field.ts deleted file mode 100644 index d92aa5be153f6..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_degraded_field.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { useSelector } from '@xstate/react'; -import { useCallback, useMemo } from 'react'; -import { orderBy } from 'lodash'; -import { useDatasetQualityContext } from '../components/dataset_quality/context'; -import { DegradedField } from '../../common/data_streams_stats'; -import { SortDirection } from '../../common/types'; -import { - DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, - DEFAULT_DEGRADED_FIELD_SORT_FIELD, -} from '../../common/constants'; -import { useKibanaContextForPlugin } from '../utils'; - -type DegradedFieldSortField = keyof DegradedField; - -// TODO: DELETE this hook in favour of new hook post migration -export function useDatasetQualityDegradedField() { - const { service } = useDatasetQualityContext(); - const { - services: { fieldFormats }, - } = useKibanaContextForPlugin(); - - const degradedFields = useSelector(service, (state) => state.context.flyout.degradedFields) ?? {}; - const { data, table } = degradedFields; - const { page, rowsPerPage, sort } = table; - - const pagination = { - pageIndex: page, - pageSize: rowsPerPage, - totalItemCount: data?.length ?? 0, - hidePerPageOptions: true, - }; - - const onTableChange = useCallback( - (options: { - page: { index: number; size: number }; - sort?: { field: DegradedFieldSortField; direction: SortDirection }; - }) => { - service.send({ - type: 'UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA', - degraded_field_criteria: { - page: options.page.index, - rowsPerPage: options.page.size, - sort: { - field: options.sort?.field || DEFAULT_DEGRADED_FIELD_SORT_FIELD, - direction: options.sort?.direction || DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, - }, - }, - }); - }, - [service] - ); - - const renderedItems = useMemo(() => { - const sortedItems = orderBy(data, sort.field, sort.direction); - return sortedItems.slice(page * rowsPerPage, (page + 1) * rowsPerPage); - }, [data, sort.field, sort.direction, page, rowsPerPage]); - - const isLoading = useSelector(service, (state) => - state.matches('flyout.initializing.dataStreamDegradedFields.fetching') - ); - - return { - isLoading, - pagination, - onTableChange, - renderedItems, - sort: { sort }, - fieldFormats, - }; -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_redirect_link.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_redirect_link.ts deleted file mode 100644 index 3000d05aa34de..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_redirect_link.ts +++ /dev/null @@ -1,188 +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 { - SINGLE_DATASET_LOCATOR_ID, - type SingleDatasetLocatorParams, -} from '@kbn/deeplinks-observability'; -import { type DiscoverAppLocatorParams, DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; -import { type Query, type AggregateQuery, buildPhraseFilter } from '@kbn/es-query'; -import { getRouterLinkProps } from '@kbn/router-utils'; -import type { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props'; -import type { LocatorPublic } from '@kbn/share-plugin/common'; -import type { LocatorClient } from '@kbn/shared-ux-prompt-no-data-views-types'; -import { useKibanaContextForPlugin } from '../utils'; -import { BasicDataStream, TimeRangeConfig } from '../../common/types'; - -export const useDatasetQualityDetailsRedirectLink = ({ - dataStreamStat, - query, - timeRangeConfig, - breakdownField, -}: { - dataStreamStat: T; - query?: Query | AggregateQuery; - timeRangeConfig: TimeRangeConfig; - breakdownField?: string; -}) => { - const { - services: { share }, - } = useKibanaContextForPlugin(); - - const { from, to } = timeRangeConfig; - - const logsExplorerLocator = - share.url.locators.get(SINGLE_DATASET_LOCATOR_ID); - - const config = logsExplorerLocator - ? buildLogsExplorerConfig({ - locator: logsExplorerLocator, - dataStreamStat, - query, - from, - to, - breakdownField, - }) - : buildDiscoverConfig({ - locatorClient: share.url.locators, - dataStreamStat, - query, - from, - to, - breakdownField, - }); - - return { - linkProps: { - ...config.routerLinkProps, - }, - navigate: config.navigate, - isLogsExplorerAvailable: !!logsExplorerLocator, - }; -}; - -const buildLogsExplorerConfig = ({ - locator, - dataStreamStat, - query, - from, - to, - breakdownField, -}: { - locator: LocatorPublic; - dataStreamStat: T; - query?: Query | AggregateQuery; - from: string; - to: string; - breakdownField?: string; -}): { - navigate: () => void; - routerLinkProps: RouterLinkProps; -} => { - const params: SingleDatasetLocatorParams = { - dataset: dataStreamStat.name, - timeRange: { - from, - to, - }, - integration: dataStreamStat.integration?.name, - query, - filterControls: { - namespace: { - mode: 'include', - values: [dataStreamStat.namespace], - }, - }, - breakdownField, - }; - - const urlToLogsExplorer = locator.getRedirectUrl(params); - - const navigateToLogsExplorer = () => { - locator.navigate(params) as Promise; - }; - - const logsExplorerLinkProps = getRouterLinkProps({ - href: urlToLogsExplorer, - onClick: navigateToLogsExplorer, - }); - - return { routerLinkProps: logsExplorerLinkProps, navigate: navigateToLogsExplorer }; -}; - -const buildDiscoverConfig = ({ - locatorClient, - dataStreamStat, - query, - from, - to, - breakdownField, -}: { - locatorClient: LocatorClient; - dataStreamStat: T; - query?: Query | AggregateQuery; - from: string; - to: string; - breakdownField?: string; -}): { - navigate: () => void; - routerLinkProps: RouterLinkProps; -} => { - const dataViewId = `${dataStreamStat.type}-${dataStreamStat.name}-*`; - const dataViewTitle = dataStreamStat.integration - ? `[${dataStreamStat.integration.title}] ${dataStreamStat.name}` - : `${dataViewId}`; - - const params: DiscoverAppLocatorParams = { - timeRange: { - from, - to, - }, - refreshInterval: { - pause: true, - value: 60000, - }, - dataViewId, - dataViewSpec: { - id: dataViewId, - title: dataViewTitle, - }, - query, - breakdownField, - columns: ['@timestamp', 'message'], - filters: [ - buildPhraseFilter( - { - name: 'data_stream.namespace', - type: 'string', - }, - dataStreamStat.namespace, - { - id: dataViewId, - title: dataViewTitle, - } - ), - ], - interval: 'auto', - sort: [['@timestamp', 'desc']], - }; - - const locator = locatorClient.get(DISCOVER_APP_LOCATOR); - - const urlToDiscover = locator?.getRedirectUrl(params); - - const navigateToDiscover = () => { - locator?.navigate(params) as Promise; - }; - - const discoverLinkProps = getRouterLinkProps({ - href: urlToDiscover, - onClick: navigateToDiscover, - }); - - return { routerLinkProps: discoverLinkProps, navigate: navigateToDiscover }; -}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts index 4b0626f951580..146ff9e5aa413 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts @@ -15,7 +15,7 @@ import { BasicDataStream } from '../../common/types'; import { useKibanaContextForPlugin } from '../utils'; export const useDatasetQualityDetailsState = () => { - const { service } = useDatasetQualityDetailsContext(); + const { service, telemetryClient } = useDatasetQualityDetailsContext(); const { services: { fieldFormats }, @@ -36,6 +36,14 @@ export const useDatasetQualityDetailsState = () => { : false ); + const isBreakdownFieldAsserted = useSelector( + service, + (state) => + state.matches('initializing.checkBreakdownFieldIsEcs.done') && + breakdownField && + isBreakdownFieldEcs + ); + const dataStreamSettings = useSelector(service, (state) => state.matches('initializing.dataStreamSettings.initializeIntegrations') ? state.context.dataStreamSettings @@ -67,7 +75,9 @@ export const useDatasetQualityDetailsState = () => { ) ); - const canUserViewIntegrations = dataStreamSettings?.datasetUserPrivileges?.canViewIntegrations; + const canUserViewIntegrations = Boolean( + dataStreamSettings?.datasetUserPrivileges?.canViewIntegrations + ); const dataStreamDetails = useSelector(service, (state) => state.matches('initializing.dataStreamDetails.done') @@ -115,6 +125,7 @@ export const useDatasetQualityDetailsState = () => { return { service, + telemetryClient, fieldFormats, isIndexNotFoundError, dataStream, @@ -123,6 +134,7 @@ export const useDatasetQualityDetailsState = () => { dataStreamDetails, breakdownField, isBreakdownFieldEcs, + isBreakdownFieldAsserted, isNonAggregatable, timeRange, loadingState, diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.ts similarity index 100% rename from x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.tsx rename to x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.ts diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_flyout.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_flyout.tsx deleted file mode 100644 index 0f9d7981e619c..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_flyout.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useSelector } from '@xstate/react'; -import { useDatasetQualityContext } from '../components/dataset_quality/context'; -import { useKibanaContextForPlugin } from '../utils'; - -export const useDatasetQualityFlyout = () => { - const { - services: { fieldFormats }, - } = useKibanaContextForPlugin(); - - const { service } = useDatasetQualityContext(); - - const { - dataset: dataStreamStat, - dataStreamSettings, - datasetDetails: dataStreamDetails, - insightsTimeRange, - breakdownField, - isNonAggregatable, - integration, - } = useSelector(service, (state) => state.context.flyout) ?? {}; - - const { timeRange } = useSelector(service, (state) => state.context.filters); - - const loadingState = useSelector(service, (state) => ({ - dataStreamDetailsLoading: state.matches('flyout.initializing.dataStreamDetails.fetching'), - dataStreamSettingsLoading: state.matches('flyout.initializing.dataStreamSettings.fetching'), - datasetIntegrationDashboardLoading: state.matches( - 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.fetching' - ), - datasetIntegrationDone: state.matches( - 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDetails.done' - ), - })); - - const canUserAccessDashboards = useSelector( - service, - (state) => - !state.matches( - 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.unauthorized' - ) - ); - - const canUserViewIntegrations = useSelector( - service, - (state) => state.context.datasetUserPrivileges.canViewIntegrations - ); - - return { - dataStreamStat, - dataStreamSettings, - dataStreamDetails, - isNonAggregatable, - integration, - fieldFormats, - timeRange: insightsTimeRange ?? timeRange, - breakdownField, - loadingState, - flyoutLoading: !dataStreamStat, - canUserAccessDashboards, - canUserViewIntegrations, - }; -}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx index b205a58dfb98f..3a3475eabeeda 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx @@ -14,7 +14,6 @@ import { DataStreamStat } from '../../common/data_streams_stats/data_stream_stat import { tableSummaryAllText, tableSummaryOfText } from '../../common/translations'; import { getDatasetQualityTableColumns } from '../components/dataset_quality/table/columns'; import { useDatasetQualityContext } from '../components/dataset_quality/context'; -import { FlyoutDataset } from '../state_machines/dataset_quality_controller'; import { useKibanaContextForPlugin } from '../utils'; import { filterInactiveDatasets, isActiveDataset } from '../utils/filter_inactive_datasets'; import { SortDirection } from '../../common/types'; @@ -30,7 +29,10 @@ const sortingOverrides: Partial<{ export const useDatasetQualityTable = () => { const { - services: { fieldFormats }, + services: { + fieldFormats, + share: { url }, + }, } = useKibanaContextForPlugin(); const { service } = useDatasetQualityContext(); @@ -61,8 +63,6 @@ export const useDatasetQualityTable = () => { } = useSelector(service, (state) => state.context.filters); const showInactiveDatasets = inactive || !canUserMonitorDataset; - const flyout = useSelector(service, (state) => state.context.flyout); - const loading = useSelector( service, (state) => @@ -89,33 +89,6 @@ export const useDatasetQualityTable = () => { [service] ); - const closeFlyout = useCallback(() => service.send({ type: 'CLOSE_FLYOUT' }), [service]); - const openFlyout = useCallback( - (selectedDataset: FlyoutDataset) => { - if (flyout?.dataset?.rawName === selectedDataset.rawName) { - service.send({ - type: 'CLOSE_FLYOUT', - }); - - return; - } - - if (!flyout?.insightsTimeRange) { - service.send({ - type: 'OPEN_FLYOUT', - dataset: selectedDataset, - }); - return; - } - - service.send({ - type: 'SELECT_NEW_DATASET', - dataset: selectedDataset, - }); - }, - [flyout?.dataset?.rawName, flyout?.insightsTimeRange, service] - ); - const isActive = useCallback( (lastActivity: number) => isActiveDataset({ lastActivity, timeRange }), [timeRange] @@ -127,27 +100,25 @@ export const useDatasetQualityTable = () => { fieldFormats, canUserMonitorDataset, canUserMonitorAnyDataStream, - selectedDataset: flyout?.dataset, - openFlyout, loadingDataStreamStats, loadingDegradedStats, showFullDatasetNames, isSizeStatsAvailable, isActiveDataset: isActive, timeRange, + urlService: url, }), [ fieldFormats, canUserMonitorDataset, canUserMonitorAnyDataStream, - flyout?.dataset, - openFlyout, loadingDataStreamStats, loadingDegradedStats, showFullDatasetNames, isSizeStatsAvailable, isActive, timeRange, + url, ] ); @@ -235,8 +206,6 @@ export const useDatasetQualityTable = () => { columns, loading, resultsCount, - closeFlyout, - selectedDataset: flyout?.dataset, showInactiveDatasets, showFullDatasetNames, canUserMonitorDataset, diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_telemetry.ts new file mode 100644 index 0000000000000..167ebd37fe81a --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_telemetry.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 { useSelector } from '@xstate/react'; +import { useCallback } from 'react'; +import { getDateISORange } from '@kbn/timerange'; +import { useDatasetQualityContext } from '../components/dataset_quality/context'; +import { useDatasetQualityFilters } from './use_dataset_quality_filters'; +import { DataStreamStat } from '../../common/data_streams_stats'; +import { DatasetEbtProps, DatasetNavigatedEbtProps } from '../services/telemetry'; + +export function useDatasetTelemetry() { + const { service, telemetryClient } = useDatasetQualityContext(); + + // eslint-disable-next-line react-hooks/exhaustive-deps + const datasets = useSelector(service, (state) => state.context.datasets) ?? {}; + const nonAggregatableDatasets = useSelector( + service, + (state) => state.context.nonAggregatableDatasets + ); + const canUserViewIntegrations = useSelector( + service, + (state) => state.context.datasetUserPrivileges.canViewIntegrations + ); + const sort = useSelector(service, (state) => state.context.table.sort); + const appliedFilters = useDatasetQualityFilters(); + + const trackDatasetNavigated = useCallback<(rawName: string, isIgnoredFilter: boolean) => void>( + (rawName: string, isIgnoredFilter: boolean) => { + const foundDataset = datasets.find((dataset) => dataset.rawName === rawName); + if (foundDataset) { + const ebtProps = getDatasetEbtProps( + foundDataset, + sort, + appliedFilters, + nonAggregatableDatasets, + isIgnoredFilter, + canUserViewIntegrations + ); + telemetryClient.trackDatasetNavigated(ebtProps); + } else { + throw new Error( + `Cannot report dataset navigation telemetry for unknown dataset ${rawName}` + ); + } + }, + [ + sort, + appliedFilters, + canUserViewIntegrations, + datasets, + nonAggregatableDatasets, + telemetryClient, + ] + ); + + return { trackDatasetNavigated }; +} + +function getDatasetEbtProps( + dataset: DataStreamStat, + sort: { field: string; direction: 'asc' | 'desc' }, + filters: ReturnType, + nonAggregatableDatasets: string[], + isIgnoredFilter: boolean, + canUserViewIntegrations: boolean +): DatasetNavigatedEbtProps { + const { startDate: from, endDate: to } = getDateISORange(filters.timeRange); + const datasetEbtProps: DatasetEbtProps = { + index_name: dataset.rawName, + data_stream: { + dataset: dataset.name, + namespace: dataset.namespace, + type: dataset.type, + }, + data_stream_health: dataset.degradedDocs.quality, + data_stream_aggregatable: nonAggregatableDatasets.some( + (indexName) => indexName === dataset.rawName + ), + from, + to, + degraded_percentage: dataset.degradedDocs.percentage, + integration: dataset.integration?.name, + privileges: { + can_monitor_data_stream: dataset.userPrivileges?.canMonitor ?? true, + can_view_integrations: canUserViewIntegrations, + }, + }; + + const ebtFilters: DatasetNavigatedEbtProps['filters'] = { + is_degraded: isIgnoredFilter, + query_length: filters.selectedQuery?.length ?? 0, + integrations: { + total: filters.integrations.filter((item) => item.name !== 'none').length, + included: filters.integrations.filter((item) => item?.checked === 'on').length, + excluded: filters.integrations.filter((item) => item?.checked === 'off').length, + }, + namespaces: { + total: filters.namespaces.length, + included: filters.namespaces.filter((item) => item?.checked === 'on').length, + excluded: filters.namespaces.filter((item) => item?.checked === 'off').length, + }, + qualities: { + total: filters.qualities.length, + included: filters.qualities.filter((item) => item?.checked === 'on').length, + excluded: filters.qualities.filter((item) => item?.checked === 'off').length, + }, + }; + + return { + ...datasetEbtProps, + sort, + filters: ebtFilters, + }; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts similarity index 80% rename from x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs.ts rename to x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts index 7842fe81966f3..795700bfc9441 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useCallback, useState, useMemo, useEffect } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import type { Action } from '@kbn/ui-actions-plugin/public'; import { fieldSupportsBreakdown } from '@kbn/unified-histogram-plugin/public'; import { i18n } from '@kbn/i18n'; @@ -16,7 +16,9 @@ import { useCreateDataView } from './use_create_dataview'; import { useKibanaContextForPlugin } from '../utils'; import { useDatasetQualityDetailsState } from './use_dataset_quality_details_state'; import { getLensAttributes } from '../components/dataset_quality_details/overview/document_trends/degraded_docs/lens_attributes'; -import { useDatasetQualityDetailsRedirectLink } from './use_dataset_quality_details_redirect_link'; +import { useRedirectLink } from './use_redirect_link'; +import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry'; +import { useDatasetDetailsRedirectLinkTelemetry } from './use_redirect_link_telemetry'; const exploreDataInLogsExplorerText = i18n.translate( 'xpack.datasetQuality.details.chartExploreDataInLogsExplorerText', @@ -39,13 +41,27 @@ const openInLensText = i18n.translate('xpack.datasetQuality.details.chartOpenInL const ACTION_EXPLORE_IN_LOGS_EXPLORER = 'ACTION_EXPLORE_IN_LOGS_EXPLORER'; const ACTION_OPEN_IN_LENS = 'ACTION_OPEN_IN_LENS'; -export const useDegradedDocs = () => { +export const useDegradedDocsChart = () => { const { euiTheme } = useEuiTheme(); const { services: { lens }, } = useKibanaContextForPlugin(); - const { service, dataStream, datasetDetails, timeRange, breakdownField, integrationDetails } = - useDatasetQualityDetailsState(); + const { + service, + dataStream, + datasetDetails, + timeRange, + breakdownField, + integrationDetails, + isBreakdownFieldAsserted, + } = useDatasetQualityDetailsState(); + + const { + trackDatasetDetailsBreakdownFieldChanged, + trackDetailsNavigated, + navigationTargets, + navigationSources, + } = useDatasetDetailsTelemetry(); const [isChartLoading, setIsChartLoading] = useState(undefined); const [attributes, setAttributes] = useState | undefined>( @@ -75,6 +91,10 @@ export const useDegradedDocs = () => { [service] ); + useEffect(() => { + if (isBreakdownFieldAsserted) trackDatasetDetailsBreakdownFieldChanged(); + }, [trackDatasetDetailsBreakdownFieldChanged, isBreakdownFieldAsserted]); + useEffect(() => { const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW; const datasetTitle = @@ -98,13 +118,21 @@ export const useDegradedDocs = () => { const openInLensCallback = useCallback(() => { if (attributes) { + trackDetailsNavigated(navigationTargets.Lens, navigationSources.Chart); lens.navigateToPrefilledEditor({ id: '', timeRange, attributes, }); } - }, [attributes, lens, timeRange]); + }, [ + attributes, + lens, + navigationSources.Chart, + navigationTargets.Lens, + timeRange, + trackDetailsNavigated, + ]); const getOpenInLensAction = useMemo(() => { return { @@ -126,11 +154,17 @@ export const useDegradedDocs = () => { }; }, [openInLensCallback]); - const redirectLinkProps = useDatasetQualityDetailsRedirectLink({ + const { sendTelemetry } = useDatasetDetailsRedirectLinkTelemetry({ + query: { language: 'kuery', query: '_ignored:*' }, + navigationSource: navigationSources.Chart, + }); + + const redirectLinkProps = useRedirectLink({ dataStreamStat: datasetDetails, query: { language: 'kuery', query: '_ignored:*' }, timeRangeConfig: timeRange, breakdownField: breakdownDataViewField?.name, + sendTelemetry, }); const getOpenInLogsExplorerAction = useMemo(() => { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx deleted file mode 100644 index 6840f2a4088a9..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useCallback, useState, useMemo, useEffect } from 'react'; -import { Action } from '@kbn/ui-actions-plugin/public'; -import { fieldSupportsBreakdown } from '@kbn/unified-histogram-plugin/public'; -import { useSelector } from '@xstate/react'; -import { i18n } from '@kbn/i18n'; -import { useEuiTheme } from '@elastic/eui'; -import { type DataView, DataViewField } from '@kbn/data-views-plugin/common'; -import { useDatasetQualityContext } from '../components/dataset_quality/context'; -import { DEFAULT_LOGS_DATA_VIEW } from '../../common/constants'; -import { useCreateDataView } from './use_create_dataview'; -import { useRedirectLink } from './use_redirect_link'; -import { useDatasetQualityFlyout } from './use_dataset_quality_flyout'; -import { useKibanaContextForPlugin } from '../utils'; -import { useDatasetDetailsTelemetry } from './use_telemetry'; -import { getLensAttributes } from '../components/dataset_quality_details/overview/document_trends/degraded_docs/lens_attributes'; - -const exploreDataInLogsExplorerText = i18n.translate( - 'xpack.datasetQuality.flyoutChartExploreDataInLogsExplorerText', - { - defaultMessage: 'Explore data in Logs Explorer', - } -); - -const exploreDataInDiscoverText = i18n.translate( - 'xpack.datasetQuality.flyoutChartExploreDataInDiscoverText', - { - defaultMessage: 'Explore data in Discover', - } -); - -const openInLensText = i18n.translate('xpack.datasetQuality.flyoutChartOpenInLensText', { - defaultMessage: 'Open in Lens', -}); - -const ACTION_EXPLORE_IN_LOGS_EXPLORER = 'ACTION_EXPLORE_IN_LOGS_EXPLORER'; -const ACTION_OPEN_IN_LENS = 'ACTION_OPEN_IN_LENS'; - -interface DegradedDocsChartDeps { - dataStream?: string; - breakdownField?: string; -} - -export const useDegradedDocsChart = ({ dataStream }: DegradedDocsChartDeps) => { - const { euiTheme } = useEuiTheme(); - const { - services: { lens }, - } = useKibanaContextForPlugin(); - const { service } = useDatasetQualityContext(); - - const { - trackDatasetDetailsBreakdownFieldChanged, - trackDetailsNavigated, - navigationTargets, - navigationSources, - } = useDatasetDetailsTelemetry(); - - const { dataStreamStat, timeRange, breakdownField } = useDatasetQualityFlyout(); - - const isBreakdownFieldEcs = useSelector( - service, - (state) => state.context.flyout.isBreakdownFieldEcs - ); - - const isBreakdownFieldEcsAsserted = useSelector(service, (state) => { - return ( - state.matches('flyout.initializing.assertBreakdownFieldIsEcs.done') && - state.history?.matches('flyout.initializing.assertBreakdownFieldIsEcs.fetching') && - isBreakdownFieldEcs !== null - ); - }); - - const [isChartLoading, setIsChartLoading] = useState(undefined); - const [attributes, setAttributes] = useState | undefined>( - undefined - ); - - const { dataView } = useCreateDataView({ - indexPatternString: getDataViewIndexPattern(dataStream), - }); - - const breakdownDataViewField = useMemo( - () => getDataViewField(dataView, breakdownField), - [breakdownField, dataView] - ); - - const handleChartLoading = (isLoading: boolean) => { - setIsChartLoading(isLoading); - }; - - const handleBreakdownFieldChange = useCallback( - (field: DataViewField | undefined) => { - service.send({ - type: 'BREAKDOWN_FIELD_CHANGE', - breakdownField: field?.name ?? null, - }); - }, - [service] - ); - - useEffect(() => { - if (isBreakdownFieldEcsAsserted) trackDatasetDetailsBreakdownFieldChanged(); - }, [trackDatasetDetailsBreakdownFieldChanged, isBreakdownFieldEcsAsserted]); - - useEffect(() => { - const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW; - - const lensAttributes = getLensAttributes({ - color: euiTheme.colors.danger, - dataStream: dataStreamName, - datasetTitle: dataStreamStat?.title ?? dataStreamName, - breakdownFieldName: breakdownDataViewField?.name, - }); - setAttributes(lensAttributes); - }, [ - breakdownDataViewField?.name, - euiTheme.colors.danger, - setAttributes, - dataStream, - dataStreamStat?.title, - ]); - - const openInLensCallback = useCallback(() => { - if (attributes) { - trackDetailsNavigated(navigationTargets.Lens, navigationSources.Chart); - lens.navigateToPrefilledEditor({ - id: '', - timeRange, - attributes, - }); - } - }, [attributes, trackDetailsNavigated, navigationTargets, navigationSources, lens, timeRange]); - - const getOpenInLensAction = useMemo(() => { - return { - id: ACTION_OPEN_IN_LENS, - type: 'link', - order: 17, - getDisplayName(): string { - return openInLensText; - }, - getIconType(): string { - return 'visArea'; - }, - async isCompatible(): Promise { - return true; - }, - async execute(): Promise { - return openInLensCallback(); - }, - }; - }, [openInLensCallback]); - - const redirectLinkProps = useRedirectLink({ - dataStreamStat: dataStreamStat!, - query: { language: 'kuery', query: '_ignored:*' }, - timeRangeConfig: timeRange, - breakdownField: breakdownDataViewField?.name, - telemetry: { - page: 'details', - navigationSource: navigationSources.Chart, - }, - }); - - const getOpenInLogsExplorerAction = useMemo(() => { - return { - id: ACTION_EXPLORE_IN_LOGS_EXPLORER, - type: 'link', - getDisplayName(): string { - return redirectLinkProps?.isLogsExplorerAvailable - ? exploreDataInLogsExplorerText - : exploreDataInDiscoverText; - }, - getHref: async () => { - return redirectLinkProps.linkProps.href; - }, - getIconType(): string | undefined { - return 'visTable'; - }, - async isCompatible(): Promise { - return true; - }, - async execute(): Promise { - return redirectLinkProps.navigate(); - }, - order: 18, - }; - }, [redirectLinkProps]); - - const extraActions: Action[] = [getOpenInLensAction, getOpenInLogsExplorerAction]; - - return { - attributes, - dataView, - breakdown: { - dataViewField: breakdownDataViewField, - fieldSupportsBreakdown: breakdownDataViewField - ? fieldSupportsBreakdown(breakdownDataViewField) - : true, - onChange: handleBreakdownFieldChange, - }, - extraActions, - isChartLoading, - onChartLoading: handleChartLoading, - setAttributes, - setIsChartLoading, - }; -}; - -function getDataViewIndexPattern(dataStream: string | undefined) { - return dataStream ?? DEFAULT_LOGS_DATA_VIEW; -} - -function getDataViewField(dataView: DataView | undefined, fieldName: string | undefined) { - return fieldName && dataView - ? dataView.fields.find((field) => field.name === fieldName) - : undefined; -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_flyout_integration_actions.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_flyout_integration_actions.tsx deleted file mode 100644 index b0f47716100b4..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_flyout_integration_actions.tsx +++ /dev/null @@ -1,104 +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 { getRouterLinkProps } from '@kbn/router-utils'; -import { useMemo, useCallback } from 'react'; -import useToggle from 'react-use/lib/useToggle'; -import { MANAGEMENT_APP_LOCATOR } from '@kbn/deeplinks-management/constants'; -import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; -import { useKibanaContextForPlugin } from '../utils'; -import { Dashboard } from '../../common/api_types'; -import { useDatasetDetailsTelemetry } from './use_telemetry'; - -export const useFlyoutIntegrationActions = () => { - const { - services: { - application: { navigateToUrl }, - http: { basePath }, - share, - }, - } = useKibanaContextForPlugin(); - const { wrapLinkPropsForTelemetry, navigationSources, navigationTargets } = - useDatasetDetailsTelemetry(); - - const [isOpen, toggleIsOpen] = useToggle(false); - - const dashboardLocator = useMemo( - () => share.url.locators.get(DASHBOARD_APP_LOCATOR), - [share.url.locators] - ); - const indexManagementLocator = useMemo( - () => share.url.locators.get(MANAGEMENT_APP_LOCATOR), - [share.url.locators] - ); - - const handleCloseMenu = useCallback(() => { - toggleIsOpen(); - }, [toggleIsOpen]); - const handleToggleMenu = useCallback(() => { - toggleIsOpen(); - }, [toggleIsOpen]); - - const getIntegrationOverviewLinkProps = useCallback( - (name: string, version: string) => { - const href = basePath.prepend(`/app/integrations/detail/${name}-${version}/overview`); - return wrapLinkPropsForTelemetry( - getRouterLinkProps({ - href, - onClick: () => { - return navigateToUrl(href); - }, - }), - navigationTargets.Integration, - navigationSources.ActionMenu - ); - }, - [basePath, navigateToUrl, navigationSources, navigationTargets, wrapLinkPropsForTelemetry] - ); - const getIndexManagementLinkProps = useCallback( - (params: { sectionId: string; appId: string }) => - wrapLinkPropsForTelemetry( - getRouterLinkProps({ - href: indexManagementLocator?.getRedirectUrl(params), - onClick: () => { - return indexManagementLocator?.navigate(params); - }, - }), - navigationTargets.IndexTemplate, - navigationSources.ActionMenu - ), - [ - indexManagementLocator, - navigationSources.ActionMenu, - navigationTargets.IndexTemplate, - wrapLinkPropsForTelemetry, - ] - ); - const getDashboardLinkProps = useCallback( - (dashboard: Dashboard) => - wrapLinkPropsForTelemetry( - getRouterLinkProps({ - href: dashboardLocator?.getRedirectUrl({ dashboardId: dashboard?.id } || ''), - onClick: () => { - return dashboardLocator?.navigate({ dashboardId: dashboard?.id } || ''); - }, - }), - navigationTargets.Dashboard, - navigationSources.ActionMenu - ), - [dashboardLocator, navigationSources, navigationTargets, wrapLinkPropsForTelemetry] - ); - - return { - isOpen, - handleCloseMenu, - handleToggleMenu, - getIntegrationOverviewLinkProps, - getIndexManagementLinkProps, - getDashboardLinkProps, - }; -}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts index 0fce743875a60..165ac2a651809 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts @@ -12,6 +12,7 @@ import { MANAGEMENT_APP_LOCATOR } from '@kbn/deeplinks-management/constants'; import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics'; import { useKibanaContextForPlugin } from '../utils'; import { Dashboard } from '../../common/api_types'; +import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry'; export const useIntegrationActions = () => { const { @@ -21,6 +22,8 @@ export const useIntegrationActions = () => { share, }, } = useKibanaContextForPlugin(); + const { wrapLinkPropsForTelemetry, navigationSources, navigationTargets } = + useDatasetDetailsTelemetry(); const [isOpen, toggleIsOpen] = useToggle(false); @@ -43,34 +46,51 @@ export const useIntegrationActions = () => { const getIntegrationOverviewLinkProps = useCallback( (name: string, version: string) => { const href = basePath.prepend(`/app/integrations/detail/${name}-${version}/overview`); - return getRouterLinkProps({ - href, - onClick: () => { - return navigateToUrl(href); - }, - }); + return wrapLinkPropsForTelemetry( + getRouterLinkProps({ + href, + onClick: () => { + return navigateToUrl(href); + }, + }), + navigationTargets.Integration, + navigationSources.ActionMenu + ); }, - [basePath, navigateToUrl] + [basePath, navigateToUrl, navigationSources, navigationTargets, wrapLinkPropsForTelemetry] ); const getIndexManagementLinkProps = useCallback( (params: { sectionId: string; appId: string }) => - getRouterLinkProps({ - href: indexManagementLocator?.getRedirectUrl(params), - onClick: () => { - return indexManagementLocator?.navigate(params); - }, - }), - [indexManagementLocator] + wrapLinkPropsForTelemetry( + getRouterLinkProps({ + href: indexManagementLocator?.getRedirectUrl(params), + onClick: () => { + return indexManagementLocator?.navigate(params); + }, + }), + navigationTargets.IndexTemplate, + navigationSources.ActionMenu + ), + [ + indexManagementLocator, + navigationSources.ActionMenu, + navigationTargets.IndexTemplate, + wrapLinkPropsForTelemetry, + ] ); const getDashboardLinkProps = useCallback( (dashboard: Dashboard) => - getRouterLinkProps({ - href: dashboardLocator?.getRedirectUrl({ dashboardId: dashboard?.id } || ''), - onClick: () => { - return dashboardLocator?.navigate({ dashboardId: dashboard?.id } || ''); - }, - }), - [dashboardLocator] + wrapLinkPropsForTelemetry( + getRouterLinkProps({ + href: dashboardLocator?.getRedirectUrl({ dashboardId: dashboard?.id } || ''), + onClick: () => { + return dashboardLocator?.navigate({ dashboardId: dashboard?.id } || ''); + }, + }), + navigationTargets.Dashboard, + navigationSources.ActionMenu + ), + [dashboardLocator, navigationSources, navigationTargets, wrapLinkPropsForTelemetry] ); return { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts index e4fbf0771ee1f..d83ad8299e263 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts @@ -18,20 +18,20 @@ import { LocatorPublic } from '@kbn/share-plugin/common'; import { LocatorClient } from '@kbn/shared-ux-prompt-no-data-views-types'; import { useKibanaContextForPlugin } from '../utils'; import { BasicDataStream, TimeRangeConfig } from '../../common/types'; -import { useRedirectLinkTelemetry } from './use_telemetry'; +import { SendTelemetryFn } from './use_redirect_link_telemetry'; export const useRedirectLink = ({ dataStreamStat, query, timeRangeConfig, breakdownField, - telemetry, + sendTelemetry, }: { dataStreamStat: T; query?: Query | AggregateQuery; timeRangeConfig: TimeRangeConfig; breakdownField?: string; - telemetry?: Parameters[0]['telemetry']; + sendTelemetry: SendTelemetryFn; }) => { const { services: { share }, @@ -42,13 +42,6 @@ export const useRedirectLink = ({ const logsExplorerLocator = share.url.locators.get(SINGLE_DATASET_LOCATOR_ID); - const { sendTelemetry } = useRedirectLinkTelemetry({ - rawName: dataStreamStat.rawName, - isLogsExplorer: !!logsExplorerLocator, - telemetry, - query, - }); - return useMemo<{ linkProps: RouterLinkProps; navigate: () => void; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link_telemetry.ts new file mode 100644 index 0000000000000..a70de0bd20295 --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link_telemetry.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { AggregateQuery, Query } from '@kbn/es-query'; +import { + SINGLE_DATASET_LOCATOR_ID, + SingleDatasetLocatorParams, +} from '@kbn/deeplinks-observability'; +import { NavigationSource } from '../services/telemetry'; +import { useDatasetTelemetry } from './use_dataset_telemetry'; +import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry'; +import { useKibanaContextForPlugin } from '../utils'; + +export type SendTelemetryFn = + | ReturnType['sendTelemetry'] + | ReturnType['sendTelemetry']; + +export const useDatasetRedirectLinkTelemetry = ({ + rawName, + query, +}: { + rawName: string; + query?: Query | AggregateQuery; +}) => { + const { trackDatasetNavigated } = useDatasetTelemetry(); + + const sendTelemetry = useCallback(() => { + const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false; + + trackDatasetNavigated(rawName, isIgnoredFilter); + }, [query, rawName, trackDatasetNavigated]); + + return { + sendTelemetry, + }; +}; + +export const useDatasetDetailsRedirectLinkTelemetry = ({ + query, + navigationSource, +}: { + navigationSource: NavigationSource; + query?: Query | AggregateQuery; +}) => { + const { + services: { share }, + } = useKibanaContextForPlugin(); + const logsExplorerLocator = + share.url.locators.get(SINGLE_DATASET_LOCATOR_ID); + const isLogsExplorer = !!logsExplorerLocator; + const { trackDetailsNavigated, navigationTargets } = useDatasetDetailsTelemetry(); + + const sendTelemetry = useCallback(() => { + const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false; + const target = isLogsExplorer ? navigationTargets.LogsExplorer : navigationTargets.Discover; + + trackDetailsNavigated(target, navigationSource, isIgnoredFilter); + }, [ + query, + isLogsExplorer, + navigationTargets.LogsExplorer, + navigationTargets.Discover, + trackDetailsNavigated, + navigationSource, + ]); + + return { + sendTelemetry, + }; +}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts similarity index 100% rename from x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.tsx rename to x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx deleted file mode 100644 index c473495c0a661..0000000000000 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx +++ /dev/null @@ -1,382 +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 { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props'; -import { useCallback, useEffect, useMemo } from 'react'; -import { useSelector } from '@xstate/react'; -import { getDateISORange } from '@kbn/timerange'; -import { AggregateQuery, Query } from '@kbn/es-query'; - -import { MASKED_FIELD_PLACEHOLDER, UNKOWN_FIELD_PLACEHOLDER } from '../../common/constants'; -import { DataStreamStat } from '../../common/data_streams_stats'; -import { DataStreamDetails } from '../../common/api_types'; -import { mapPercentageToQuality } from '../../common/utils'; -import { - NavigationTarget, - NavigationSource, - DatasetDetailsEbtProps, - DatasetNavigatedEbtProps, - DatasetEbtProps, -} from '../services/telemetry'; -import { FlyoutDataset } from '../state_machines/dataset_quality_controller'; -import { useDatasetQualityContext } from '../components/dataset_quality/context'; -import { useDatasetQualityFilters } from './use_dataset_quality_filters'; -import { TimeRangeConfig } from '../../common/types'; - -export const useRedirectLinkTelemetry = ({ - rawName, - isLogsExplorer, - telemetry, - query, -}: { - rawName: string; - isLogsExplorer: boolean; - telemetry?: { - page: 'main' | 'details'; - navigationSource: NavigationSource; - }; - query?: Query | AggregateQuery; -}) => { - const { trackDatasetNavigated } = useDatasetTelemetry(); - const { trackDetailsNavigated, navigationTargets } = useDatasetDetailsTelemetry(); - - const sendTelemetry = useCallback(() => { - if (telemetry) { - const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false; - if (telemetry.page === 'main') { - trackDatasetNavigated(rawName, isIgnoredFilter); - } else { - trackDetailsNavigated( - isLogsExplorer ? navigationTargets.LogsExplorer : navigationTargets.Discover, - telemetry.navigationSource, - isIgnoredFilter - ); - } - } - }, [ - isLogsExplorer, - trackDetailsNavigated, - navigationTargets, - query, - rawName, - telemetry, - trackDatasetNavigated, - ]); - - const wrapLinkPropsForTelemetry = useCallback( - (props: RouterLinkProps) => { - return { - ...props, - onClick: (event: Parameters[0]) => { - sendTelemetry(); - if (props.onClick) { - props.onClick(event); - } - }, - }; - }, - [sendTelemetry] - ); - - return { - wrapLinkPropsForTelemetry, - sendTelemetry, - }; -}; - -export const useDatasetTelemetry = () => { - const { service, telemetryClient } = useDatasetQualityContext(); - - // eslint-disable-next-line react-hooks/exhaustive-deps - const datasets = useSelector(service, (state) => state.context.datasets) ?? {}; - const nonAggregatableDatasets = useSelector( - service, - (state) => state.context.nonAggregatableDatasets - ); - const canUserViewIntegrations = useSelector( - service, - (state) => state.context.datasetUserPrivileges.canViewIntegrations - ); - const sort = useSelector(service, (state) => state.context.table.sort); - const appliedFilters = useDatasetQualityFilters(); - - const trackDatasetNavigated = useCallback<(rawName: string, isIgnoredFilter: boolean) => void>( - (rawName: string, isIgnoredFilter: boolean) => { - const foundDataset = datasets.find((dataset) => dataset.rawName === rawName); - if (foundDataset) { - const ebtProps = getDatasetEbtProps( - foundDataset, - sort, - appliedFilters, - nonAggregatableDatasets, - isIgnoredFilter, - canUserViewIntegrations - ); - telemetryClient.trackDatasetNavigated(ebtProps); - } else { - throw new Error( - `Cannot report dataset navigation telemetry for unknown dataset ${rawName}` - ); - } - }, - [ - sort, - appliedFilters, - canUserViewIntegrations, - datasets, - nonAggregatableDatasets, - telemetryClient, - ] - ); - - return { trackDatasetNavigated }; -}; - -export const useDatasetDetailsTelemetry = () => { - const { service, telemetryClient } = useDatasetQualityContext(); - - const { - dataset: dataStreamStat, - datasetDetails: dataStreamDetails, - insightsTimeRange, - breakdownField, - isNonAggregatable, - isBreakdownFieldEcs, - } = useSelector(service, (state) => state.context.flyout) ?? {}; - - const loadingState = useSelector(service, (state) => ({ - dataStreamDetailsLoading: - state.matches('flyout.initializing.dataStreamDetails.fetching') || - state.matches('flyout.initializing.assertBreakdownFieldIsEcs.fetching'), - })); - - const canUserAccessDashboards = useSelector( - service, - (state) => !state.matches('flyout.initializing.integrationDashboards.unauthorized') - ); - - const canUserViewIntegrations = useSelector( - service, - (state) => state.context.datasetUserPrivileges.canViewIntegrations - ); - - const ebtProps = useMemo(() => { - if ( - dataStreamDetails && - insightsTimeRange && - dataStreamStat && - !loadingState.dataStreamDetailsLoading - ) { - return getDatasetDetailsEbtProps( - insightsTimeRange, - dataStreamStat, - dataStreamDetails, - isNonAggregatable ?? false, - canUserViewIntegrations, - canUserAccessDashboards, - isBreakdownFieldEcs, - breakdownField - ); - } - - return undefined; - }, [ - insightsTimeRange, - dataStreamStat, - dataStreamDetails, - loadingState.dataStreamDetailsLoading, - isNonAggregatable, - canUserViewIntegrations, - canUserAccessDashboards, - isBreakdownFieldEcs, - breakdownField, - ]); - - const startTracking = useCallback(() => { - telemetryClient.startDatasetDetailsTracking(); - }, [telemetryClient]); - - // Report opening dataset details - useEffect(() => { - const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); - if (datasetDetailsTrackingState === 'started' && ebtProps) { - telemetryClient.trackDatasetDetailsOpened(ebtProps); - } - }, [ebtProps, telemetryClient]); - - const trackDetailsNavigated = useCallback( - (target: NavigationTarget, source: NavigationSource, isDegraded = false) => { - const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); - if ( - (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') && - ebtProps - ) { - telemetryClient.trackDatasetDetailsNavigated({ - ...ebtProps, - filters: { - is_degraded: isDegraded, - }, - target, - source, - }); - } else { - throw new Error( - 'Cannot report dataset details navigation telemetry without required data and state' - ); - } - }, - [ebtProps, telemetryClient] - ); - - const trackDatasetDetailsBreakdownFieldChanged = useCallback(() => { - const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState(); - if ( - (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') && - ebtProps - ) { - telemetryClient.trackDatasetDetailsBreakdownFieldChanged({ - ...ebtProps, - breakdown_field: ebtProps.breakdown_field, - }); - } - }, [ebtProps, telemetryClient]); - - const wrapLinkPropsForTelemetry = useCallback( - ( - props: RouterLinkProps, - target: NavigationTarget, - source: NavigationSource, - isDegraded = false - ) => { - return { - ...props, - onClick: (event: Parameters[0]) => { - trackDetailsNavigated(target, source, isDegraded); - if (props.onClick) { - props.onClick(event); - } - }, - }; - }, - [trackDetailsNavigated] - ); - - return { - startTracking, - trackDetailsNavigated, - wrapLinkPropsForTelemetry, - navigationTargets: NavigationTarget, - navigationSources: NavigationSource, - trackDatasetDetailsBreakdownFieldChanged, - }; -}; - -function getDatasetEbtProps( - dataset: DataStreamStat, - sort: { field: string; direction: 'asc' | 'desc' }, - filters: ReturnType, - nonAggregatableDatasets: string[], - isIgnoredFilter: boolean, - canUserViewIntegrations: boolean -): DatasetNavigatedEbtProps { - const { startDate: from, endDate: to } = getDateISORange(filters.timeRange); - const datasetEbtProps: DatasetEbtProps = { - index_name: dataset.rawName, - data_stream: { - dataset: dataset.name, - namespace: dataset.namespace, - type: dataset.type, - }, - data_stream_health: dataset.degradedDocs.quality, - data_stream_aggregatable: nonAggregatableDatasets.some( - (indexName) => indexName === dataset.rawName - ), - from, - to, - degraded_percentage: dataset.degradedDocs.percentage, - integration: dataset.integration?.name, - privileges: { - can_monitor_data_stream: dataset.userPrivileges?.canMonitor ?? true, - can_view_integrations: canUserViewIntegrations, - }, - }; - - const ebtFilters: DatasetNavigatedEbtProps['filters'] = { - is_degraded: isIgnoredFilter, - query_length: filters.selectedQuery?.length ?? 0, - integrations: { - total: filters.integrations.filter((item) => item.name !== 'none').length, - included: filters.integrations.filter((item) => item?.checked === 'on').length, - excluded: filters.integrations.filter((item) => item?.checked === 'off').length, - }, - namespaces: { - total: filters.namespaces.length, - included: filters.namespaces.filter((item) => item?.checked === 'on').length, - excluded: filters.namespaces.filter((item) => item?.checked === 'off').length, - }, - qualities: { - total: filters.qualities.length, - included: filters.qualities.filter((item) => item?.checked === 'on').length, - excluded: filters.qualities.filter((item) => item?.checked === 'off').length, - }, - }; - - return { - ...datasetEbtProps, - sort, - filters: ebtFilters, - }; -} - -function getDatasetDetailsEbtProps( - insightsTimeRange: TimeRangeConfig, - flyoutDataset: FlyoutDataset, - details: DataStreamDetails, - isNonAggregatable: boolean, - canUserViewIntegrations: boolean, - canUserAccessDashboards: boolean, - isBreakdownFieldEcs: boolean | null, - breakdownField?: string -): DatasetDetailsEbtProps { - const indexName = flyoutDataset.rawName; - const dataStream = { - dataset: flyoutDataset.name, - namespace: flyoutDataset.namespace, - type: flyoutDataset.type, - }; - const degradedDocs = details?.degradedDocsCount ?? 0; - const totalDocs = details?.docsCount ?? 0; - const degradedPercentage = - totalDocs > 0 ? Number(((degradedDocs / totalDocs) * 100).toFixed(2)) : 0; - const health = mapPercentageToQuality(degradedPercentage); - const { startDate: from, endDate: to } = getDateISORange(insightsTimeRange); - - return { - index_name: indexName, - data_stream: dataStream, - privileges: { - can_monitor_data_stream: true, - can_view_integrations: canUserViewIntegrations, - can_view_dashboards: canUserAccessDashboards, - }, - data_stream_aggregatable: !isNonAggregatable, - data_stream_health: health, - from, - to, - degraded_percentage: degradedPercentage, - integration: flyoutDataset.integration?.name, - breakdown_field: breakdownField - ? isBreakdownFieldEcs === null - ? UNKOWN_FIELD_PLACEHOLDER - : getMaskedBreakdownField(breakdownField, isBreakdownFieldEcs) - : breakdownField, - }; -} - -function getMaskedBreakdownField(breakdownField: string, isBreakdownFieldEcs: boolean) { - return isBreakdownFieldEcs ? breakdownField : MASKED_FIELD_PLACEHOLDER; -} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx index 6cb4c12975412..84dbabe1d2540 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx @@ -52,9 +52,7 @@ export class DatasetQualityPlugin const createDatasetQualityController = createDatasetQualityControllerLazyFactory({ core, - plugins, dataStreamStatsClient, - dataStreamDetailsClient, }); const DatasetQualityDetails = createDatasetQualityDetails({ diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts index e4b5e07c8df92..f1a41ffc666cc 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts @@ -34,6 +34,7 @@ export enum NavigationSource { Footer = 'footer', Summary = 'summary', Chart = 'chart', + Trend = 'trend', Table = 'table', ActionMenu = 'action_menu', } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts index 62ec47632c242..87a6a398df8f0 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts @@ -7,8 +7,6 @@ import { DEFAULT_DATASET_TYPE, - DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, - DEFAULT_DEGRADED_FIELD_SORT_FIELD, DEFAULT_SORT_DIRECTION, DEFAULT_SORT_FIELD, } from '../../../../common/constants'; @@ -47,19 +45,6 @@ export const DEFAULT_CONTEXT: DefaultDatasetQualityControllerState = { namespaces: [], qualities: [], }, - flyout: { - degradedFields: { - table: { - page: 0, - rowsPerPage: 10, - sort: { - field: DEFAULT_DEGRADED_FIELD_SORT_FIELD, - direction: DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, - }, - }, - }, - isBreakdownFieldEcs: null, - }, datasets: [], isSizeStatsAvailable: true, nonAggregatableDatasets: [], diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts index f10ea32da3af6..a21cc85aac449 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts @@ -17,15 +17,6 @@ export const fetchDatasetStatsFailedNotifier = (toasts: IToasts, error: Error) = }); }; -export const fetchDatasetDetailsFailedNotifier = (toasts: IToasts, error: Error) => { - toasts.addDanger({ - title: i18n.translate('xpack.datasetQuality.fetchDatasetDetailsFailed', { - defaultMessage: "We couldn't get your data set details.", - }), - text: error.message, - }); -}; - export const fetchDegradedStatsFailedNotifier = (toasts: IToasts, error: Error) => { toasts.addDanger({ title: i18n.translate('xpack.datasetQuality.fetchDegradedStatsFailed', { @@ -35,15 +26,6 @@ export const fetchDegradedStatsFailedNotifier = (toasts: IToasts, error: Error) }); }; -export const fetchNonAggregatableDatasetsFailedNotifier = (toasts: IToasts, error: Error) => { - toasts.addDanger({ - title: i18n.translate('xpack.datasetQuality.fetchNonAggregatableDatasetsFailed', { - defaultMessage: "We couldn't get non aggregatable datasets information.", - }), - text: error.message, - }); -}; - export const fetchIntegrationsFailedNotifier = (toasts: IToasts, error: Error) => { toasts.addDanger({ title: i18n.translate('xpack.datasetQuality.fetchIntegrationsFailed', { @@ -52,19 +34,3 @@ export const fetchIntegrationsFailedNotifier = (toasts: IToasts, error: Error) = text: error.message, }); }; - -export const noDatasetSelected = i18n.translate( - 'xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected', - { - defaultMessage: 'No data set have been selected', - } -); - -export const assertBreakdownFieldEcsFailedNotifier = (toasts: IToasts, error: Error) => { - toasts.addDanger({ - title: i18n.translate('xpack.datasetQuality.assertBreakdownFieldEcsFailed', { - defaultMessage: "We couldn't retrieve breakdown field metadata.", - }), - text: error.message, - }); -}; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts index fb6c03fae153a..7ce3c5b5d8f60 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts @@ -8,36 +8,22 @@ import { IToasts } from '@kbn/core/public'; import { getDateISORange } from '@kbn/timerange'; import { assign, createMachine, DoneInvokeEvent, InterpreterFrom } from 'xstate'; -import { DatasetQualityStartDeps } from '../../../types'; -import { - Dashboard, - DataStreamStat, - DegradedFieldResponse, - NonAggregatableDatasets, -} from '../../../../common/api_types'; +import { DataStreamStat, NonAggregatableDatasets } from '../../../../common/api_types'; import { Integration } from '../../../../common/data_streams_stats/integration'; -import { IDataStreamDetailsClient } from '../../../services/data_stream_details'; import { - DataStreamSettings, - DataStreamDetails, GetDataStreamsStatsQuery, GetIntegrationsParams, GetNonAggregatableDataStreamsParams, DataStreamStatServiceResponse, } from '../../../../common/data_streams_stats'; import { DegradedDocsStat } from '../../../../common/data_streams_stats/malformed_docs_stat'; -import { DataStreamType } from '../../../../common/types'; -import { dataStreamPartsToIndexName } from '../../../../common/utils'; import { IDataStreamsStatsClient } from '../../../services/data_streams_stats'; import { generateDatasets } from '../../../utils'; import { DEFAULT_CONTEXT } from './defaults'; import { - fetchDatasetDetailsFailedNotifier, fetchDatasetStatsFailedNotifier, fetchDegradedStatsFailedNotifier, fetchIntegrationsFailedNotifier, - noDatasetSelected, - assertBreakdownFieldEcsFailedNotifier, } from './notifications'; import { fetchNonAggregatableDatasetsFailedNotifier } from '../../common/notifications'; import { @@ -45,13 +31,7 @@ import { DatasetQualityControllerEvent, DatasetQualityControllerTypeState, DefaultDatasetQualityControllerState, - FlyoutDataset, } from './types'; -import { - fetchDataStreamSettingsFailedNotifier, - fetchIntegrationDashboardsFailedNotifier, - fetchDataStreamIntegrationFailedNotifier, -} from '../../dataset_quality_details_controller/notifications'; export const createPureDatasetQualityControllerStateMachine = ( initialContext: DatasetQualityControllerContext @@ -227,231 +207,6 @@ export const createPureDatasetQualityControllerStateMachine = ( }, }, }, - flyout: { - initial: 'closed', - states: { - initializing: { - type: 'parallel', - states: { - nonAggregatableDataset: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDatasetIsNonAggregatable', - onDone: { - target: 'done', - actions: ['storeDatasetIsNonAggregatable'], - }, - onError: { - target: 'done', - actions: ['notifyFetchNonAggregatableDatasetsFailed'], - }, - }, - }, - done: { - on: { - UPDATE_INSIGHTS_TIME_RANGE: { - target: 'fetching', - actions: ['storeFlyoutOptions'], - }, - SELECT_DATASET: { - target: 'fetching', - actions: ['storeFlyoutOptions'], - }, - }, - }, - }, - }, - dataStreamSettings: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDataStreamSettings', - onDone: { - target: 'initializeIntegrations', - actions: ['storeDataStreamSettings'], - }, - onError: { - target: 'done', - actions: ['notifyFetchDataStreamSettingsFailed'], - }, - }, - }, - initializeIntegrations: { - type: 'parallel', - states: { - integrationDetails: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDataStreamIntegration', - onDone: { - target: 'done', - actions: ['storeDataStreamIntegration'], - }, - onError: { - target: 'done', - actions: ['notifyFetchDatasetIntegrationsFailed'], - }, - }, - }, - done: { - type: 'final', - }, - }, - }, - integrationDashboards: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadIntegrationDashboards', - onDone: { - target: 'done', - actions: ['storeIntegrationDashboards'], - }, - onError: [ - { - target: 'unauthorized', - cond: 'checkIfActionForbidden', - }, - { - target: 'done', - actions: ['notifyFetchIntegrationDashboardsFailed'], - }, - ], - }, - }, - done: { - type: 'final', - }, - unauthorized: { - type: 'final', - }, - }, - }, - }, - }, - done: { - type: 'final', - }, - }, - }, - dataStreamDetails: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDataStreamDetails', - onDone: { - target: 'done', - actions: ['storeDatasetDetails'], - }, - onError: { - target: 'done', - actions: ['notifyFetchDatasetDetailsFailed'], - }, - }, - }, - done: { - on: { - UPDATE_INSIGHTS_TIME_RANGE: { - target: 'fetching', - actions: ['storeFlyoutOptions'], - }, - BREAKDOWN_FIELD_CHANGE: { - target: - '#DatasetQualityController.flyout.initializing.assertBreakdownFieldIsEcs.fetching', - actions: ['storeFlyoutOptions'], - }, - }, - }, - }, - }, - dataStreamDegradedFields: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDegradedFieldsPerDataStream', - onDone: { - target: 'done', - actions: ['storeDegradedFields'], - }, - onError: { - target: 'done', - }, - }, - }, - done: { - on: { - UPDATE_INSIGHTS_TIME_RANGE: { - target: 'fetching', - actions: ['resetDegradedFieldPage'], - }, - UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA: { - target: 'done', - actions: ['storeDegradedFieldTableOptions'], - }, - }, - }, - }, - }, - assertBreakdownFieldIsEcs: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'assertBreakdownFieldIsEcs', - onDone: { - target: 'done', - actions: ['storeBreakdownFieldIsEcs'], - }, - onError: { - target: 'done', - actions: ['notifyAssertBreakdownFieldEcsFailed'], - }, - }, - }, - done: {}, - }, - }, - }, - onDone: { - target: '#DatasetQualityController.flyout.loaded', - }, - }, - loaded: { - on: { - CLOSE_FLYOUT: { - target: 'closed', - actions: ['resetFlyoutOptions'], - }, - }, - }, - closed: { - on: { - OPEN_FLYOUT: { - target: '#DatasetQualityController.flyout.initializing', - actions: ['storeFlyoutOptions'], - }, - }, - }, - }, - on: { - SELECT_NEW_DATASET: { - target: '#DatasetQualityController.flyout.initializing', - actions: ['storeFlyoutOptions'], - }, - CLOSE_FLYOUT: { - target: '#DatasetQualityController.flyout.closed', - actions: ['resetFlyoutOptions'], - }, - }, - }, }, }, { @@ -463,38 +218,12 @@ export const createPureDatasetQualityControllerStateMachine = ( } : {}; }), - storeDegradedFieldTableOptions: assign((context, event) => { - return 'degraded_field_criteria' in event - ? { - flyout: { - ...context.flyout, - degradedFields: { - ...context.flyout.degradedFields, - table: event.degraded_field_criteria, - }, - }, - } - : {}; - }), resetPage: assign((context, _event) => ({ table: { ...context.table, page: 0, }, })), - resetDegradedFieldPage: assign((context, _event) => ({ - flyout: { - ...context.flyout, - degradedFields: { - ...context.flyout.degradedFields, - table: { - ...context.flyout.degradedFields.table, - page: 0, - rowsPerPage: 10, - }, - }, - }, - })), storeInactiveDatasetsVisibility: assign((context, _event) => { return { filters: { @@ -561,37 +290,6 @@ export const createPureDatasetQualityControllerStateMachine = ( } : {}; }), - storeFlyoutOptions: assign((context, event) => { - const insightsTimeRange = - 'timeRange' in event - ? event.timeRange - : context.flyout?.insightsTimeRange ?? context.filters?.timeRange; - const dataset = - 'dataset' in event ? (event.dataset as FlyoutDataset) : context.flyout?.dataset; - const breakdownField = - 'breakdownField' in event - ? event.breakdownField ?? undefined - : context.flyout?.breakdownField; - - return { - flyout: { - ...context.flyout, - dataset, - insightsTimeRange, - breakdownField, - }, - }; - }), - storeBreakdownFieldIsEcs: assign((context, event: DoneInvokeEvent) => { - return { - flyout: { - ...context.flyout, - isBreakdownFieldEcs: - 'data' in event && typeof event.data === 'boolean' ? event.data : null, - }, - }; - }), - resetFlyoutOptions: assign((_context, _event) => ({ flyout: DEFAULT_CONTEXT.flyout })), storeDataStreamStats: assign( (_context, event: DoneInvokeEvent) => { if ('data' in event && 'dataStreamsStats' in event.data) { @@ -618,19 +316,6 @@ export const createPureDatasetQualityControllerStateMachine = ( } : {}; }), - storeDegradedFields: assign((context, event: DoneInvokeEvent) => { - return 'data' in event - ? { - flyout: { - ...context.flyout, - degradedFields: { - ...context.flyout.degradedFields, - data: event.data.degradedFields, - }, - }, - } - : {}; - }), storeNonAggregatableDatasets: assign( ( _context: DefaultDatasetQualityControllerState, @@ -643,41 +328,6 @@ export const createPureDatasetQualityControllerStateMachine = ( : {}; } ), - storeDataStreamSettings: assign((context, event) => { - return 'data' in event - ? { - flyout: { - ...context.flyout, - dataStreamSettings: (event.data ?? {}) as DataStreamSettings, - }, - } - : {}; - }), - storeDatasetDetails: assign((context, event) => { - return 'data' in event - ? { - flyout: { - ...context.flyout, - datasetDetails: event.data as DataStreamDetails, - }, - } - : {}; - }), - storeDatasetIsNonAggregatable: assign( - ( - context: DefaultDatasetQualityControllerState, - event: DoneInvokeEvent - ) => { - return 'data' in event - ? { - flyout: { - ...context.flyout, - isNonAggregatable: !event.data.aggregatable, - }, - } - : {}; - } - ), storeIntegrations: assign((_context, event) => { return 'data' in event ? { @@ -690,32 +340,6 @@ export const createPureDatasetQualityControllerStateMachine = ( integrations: [], }; }), - storeDataStreamIntegration: assign((context, event: DoneInvokeEvent) => { - return 'data' in event - ? { - flyout: { - ...context.flyout, - integration: { - ...context.flyout.integration, - integrationDetails: event.data, - }, - }, - } - : {}; - }), - storeIntegrationDashboards: assign((context, event: DoneInvokeEvent) => { - return 'data' in event - ? { - flyout: { - ...context.flyout, - integration: { - ...context.flyout.integration, - dashboards: event.data, - }, - }, - } - : {}; - }), storeDatasets: assign((context, _event) => { return context.integrations && (context.dataStreamStats || context.degradedDocStats) ? { @@ -743,18 +367,14 @@ export const createPureDatasetQualityControllerStateMachine = ( export interface DatasetQualityControllerStateMachineDependencies { initialContext?: DatasetQualityControllerContext; - plugins: DatasetQualityStartDeps; toasts: IToasts; dataStreamStatsClient: IDataStreamsStatsClient; - dataStreamDetailsClient: IDataStreamDetailsClient; } export const createDatasetQualityControllerStateMachine = ({ initialContext = DEFAULT_CONTEXT, - plugins, toasts, dataStreamStatsClient, - dataStreamDetailsClient, }: DatasetQualityControllerStateMachineDependencies) => createPureDatasetQualityControllerStateMachine(initialContext).withConfig({ actions: { @@ -764,20 +384,8 @@ export const createDatasetQualityControllerStateMachine = ({ fetchDegradedStatsFailedNotifier(toasts, event.data), notifyFetchNonAggregatableDatasetsFailed: (_context, event: DoneInvokeEvent) => fetchNonAggregatableDatasetsFailedNotifier(toasts, event.data), - notifyFetchDataStreamSettingsFailed: (_context, event: DoneInvokeEvent) => - fetchDataStreamSettingsFailedNotifier(toasts, event.data), - notifyFetchDatasetDetailsFailed: (_context, event: DoneInvokeEvent) => - fetchDatasetDetailsFailedNotifier(toasts, event.data), - notifyFetchIntegrationDashboardsFailed: (_context, event: DoneInvokeEvent) => - fetchIntegrationDashboardsFailedNotifier(toasts, event.data), notifyFetchIntegrationsFailed: (_context, event: DoneInvokeEvent) => fetchIntegrationsFailedNotifier(toasts, event.data), - notifyFetchDatasetIntegrationsFailed: (context, event: DoneInvokeEvent) => { - const integrationName = context.flyout.dataStreamSettings?.integration; - return fetchDataStreamIntegrationFailedNotifier(toasts, event.data, integrationName); - }, - notifyAssertBreakdownFieldEcsFailed: (_context, event: DoneInvokeEvent) => - assertBreakdownFieldEcsFailedNotifier(toasts, event.data), }, services: { loadDataStreamStats: (context) => @@ -795,27 +403,6 @@ export const createDatasetQualityControllerStateMachine = ({ end, }); }, - - loadDegradedFieldsPerDataStream: (context) => { - if (!context.flyout.dataset || !context.flyout.insightsTimeRange) { - return Promise.resolve({}); - } - - const { startDate: start, endDate: end } = getDateISORange( - context.flyout.insightsTimeRange - ); - const { type, name: dataset, namespace } = context.flyout.dataset; - - return dataStreamDetailsClient.getDataStreamDegradedFields({ - dataStream: dataStreamPartsToIndexName({ - type: type as DataStreamType, - dataset, - namespace, - }), - start, - end, - }); - }, loadIntegrations: (context) => { return dataStreamStatsClient.getIntegrations({ type: context.type as GetIntegrationsParams['query']['type'], @@ -830,108 +417,6 @@ export const createDatasetQualityControllerStateMachine = ({ end, }); }, - loadDataStreamSettings: (context) => { - if (!context.flyout.dataset) { - fetchDataStreamSettingsFailedNotifier(toasts, new Error(noDatasetSelected)); - - return Promise.resolve({}); - } - - const { type, name: dataset, namespace } = context.flyout.dataset; - - return dataStreamDetailsClient.getDataStreamSettings({ - dataStream: dataStreamPartsToIndexName({ - type: type as DataStreamType, - dataset, - namespace, - }), - }); - }, - loadDataStreamIntegration: (context) => { - if (context.flyout.dataStreamSettings?.integration && context.flyout.dataset) { - const { type } = context.flyout.dataset; - return dataStreamDetailsClient.getDataStreamIntegration({ - type: type as DataStreamType, - integrationName: context.flyout.dataStreamSettings.integration, - }); - } - return Promise.resolve(); - }, - loadDataStreamDetails: (context) => { - if (!context.flyout.dataset || !context.flyout.insightsTimeRange) { - fetchDatasetDetailsFailedNotifier(toasts, new Error(noDatasetSelected)); - - return Promise.resolve({}); - } - - const { type, name: dataset, namespace } = context.flyout.dataset; - const { startDate: start, endDate: end } = getDateISORange( - context.flyout.insightsTimeRange - ); - - return dataStreamDetailsClient.getDataStreamDetails({ - dataStream: dataStreamPartsToIndexName({ - type: type as DataStreamType, - dataset, - namespace, - }), - start, - end, - }); - }, - loadIntegrationDashboards: (context) => { - if (context.flyout.dataStreamSettings?.integration) { - return dataStreamDetailsClient.getIntegrationDashboards({ - integration: context.flyout.dataStreamSettings.integration, - }); - } - - return Promise.resolve(); - }, - loadDatasetIsNonAggregatable: async (context) => { - if (!context.flyout.dataset || !context.flyout.insightsTimeRange) { - fetchDatasetDetailsFailedNotifier(toasts, new Error(noDatasetSelected)); - - return Promise.resolve({}); - } - - const { type, name: dataset, namespace } = context.flyout.dataset; - const { startDate: start, endDate: end } = getDateISORange( - context.flyout.insightsTimeRange - ); - - return dataStreamStatsClient.getNonAggregatableDatasets({ - type: context.type as GetNonAggregatableDataStreamsParams['type'], - start, - end, - dataStream: dataStreamPartsToIndexName({ - type: type as DataStreamType, - dataset, - namespace, - }), - }); - }, - assertBreakdownFieldIsEcs: async (context) => { - if (context.flyout.breakdownField) { - const allowedFieldSources = ['ecs', 'metadata']; - - // This timeout is to avoid a runtime error that randomly happens on breakdown field change - // TypeError: Cannot read properties of undefined (reading 'timeFieldName') - await new Promise((res) => setTimeout(res, 300)); - - const client = await plugins.fieldsMetadata.getClient(); - const { fields } = await client.find({ - attributes: ['source'], - fieldNames: [context.flyout.breakdownField], - }); - - const breakdownFieldSource = fields[context.flyout.breakdownField]?.source; - - return !!(breakdownFieldSource && allowedFieldSources.includes(breakdownFieldSource)); - } - - return null; - }, }, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts index d6bfaaad216b9..a03bddcc9e93e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts @@ -7,35 +7,18 @@ import { DoneInvokeEvent } from 'xstate'; import { QualityIndicators, TableCriteria, TimeRangeConfig } from '../../../../common/types'; -import { - Dashboard, - DatasetUserPrivileges, - NonAggregatableDatasets, -} from '../../../../common/api_types'; +import { DatasetUserPrivileges, NonAggregatableDatasets } from '../../../../common/api_types'; import { Integration } from '../../../../common/data_streams_stats/integration'; -import { DatasetTableSortField, DegradedFieldSortField } from '../../../hooks'; +import { DatasetTableSortField } from '../../../hooks'; import { DegradedDocsStat } from '../../../../common/data_streams_stats/malformed_docs_stat'; import { DataStreamDegradedDocsStatServiceResponse, - DataStreamSettings, DataStreamDetails, DataStreamStatServiceResponse, DataStreamStat, DataStreamStatType, - DegradedField, - DegradedFieldResponse, } from '../../../../common/data_streams_stats'; -export type FlyoutDataset = Omit< - DataStreamStat, - 'type' | 'size' | 'sizeBytes' | 'lastActivity' | 'degradedDocs' -> & { type: string }; - -export interface DegradedFields { - table: TableCriteria; - data?: DegradedField[]; -} - interface FiltersCriteria { inactive: boolean; fullNames: boolean; @@ -46,29 +29,10 @@ interface FiltersCriteria { query?: string; } -export interface DataStreamIntegrations { - integrationDetails?: Integration; - dashboards?: Dashboard[]; -} - export interface WithTableOptions { table: TableCriteria; } -export interface WithFlyoutOptions { - flyout: { - dataset?: FlyoutDataset; - dataStreamSettings?: DataStreamSettings; - datasetDetails?: DataStreamDetails; - insightsTimeRange?: TimeRangeConfig; - breakdownField?: string; - degradedFields: DegradedFields; - isNonAggregatable?: boolean; - integration?: DataStreamIntegrations; - isBreakdownFieldEcs: boolean | null; - }; -} - export interface WithFilters { filters: FiltersCriteria; } @@ -98,14 +62,12 @@ export interface WithIntegrations { export type DefaultDatasetQualityControllerState = { type: string } & WithTableOptions & WithDataStreamStats & Partial & - WithFlyoutOptions & WithDatasets & WithFilters & WithNonAggregatableDatasets & Partial; -type DefaultDatasetQualityStateContext = DefaultDatasetQualityControllerState & - Partial; +type DefaultDatasetQualityStateContext = DefaultDatasetQualityControllerState; export type DatasetQualityControllerTypeState = | { @@ -131,48 +93,6 @@ export type DatasetQualityControllerTypeState = | { value: 'nonAggregatableDatasets.fetching'; context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamSettings.fetching'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.fetching'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.unauthorized'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDetails.done'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamDetails.fetching'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamDetails.done'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.assertBreakdownFieldIsEcs.fetching'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.assertBreakdownFieldIsEcs.done'; - context: DefaultDatasetQualityStateContext; - } - | { - value: 'flyout.initializing.dataStreamDegradedFields.fetching'; - context: DefaultDatasetQualityStateContext; - } - | { - value: - | 'flyout.initializing.integrationDashboards.fetching' - | 'flyout.initializing.integrationDashboards.unauthorized'; - context: DefaultDatasetQualityStateContext; }; export type DatasetQualityControllerContext = DatasetQualityControllerTypeState['context']; @@ -182,29 +102,10 @@ export type DatasetQualityControllerEvent = type: 'UPDATE_TABLE_CRITERIA'; dataset_criteria: TableCriteria; } - | { - type: 'UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA'; - degraded_field_criteria: TableCriteria; - } - | { - type: 'OPEN_FLYOUT'; - dataset: FlyoutDataset; - } - | { - type: 'SELECT_NEW_DATASET'; - dataset: FlyoutDataset; - } | { type: 'UPDATE_INSIGHTS_TIME_RANGE'; timeRange: TimeRangeConfig; } - | { - type: 'BREAKDOWN_FIELD_CHANGE'; - breakdownField: string | null; - } - | { - type: 'CLOSE_FLYOUT'; - } | { type: 'TOGGLE_INACTIVE_DATASETS'; } @@ -236,10 +137,7 @@ export type DatasetQualityControllerEvent = } | DoneInvokeEvent | DoneInvokeEvent - | DoneInvokeEvent | DoneInvokeEvent - | DoneInvokeEvent - | DoneInvokeEvent | DoneInvokeEvent | DoneInvokeEvent | DoneInvokeEvent diff --git a/x-pack/plugins/observability_solution/infra/public/containers/react_query_provider.tsx b/x-pack/plugins/observability_solution/infra/public/containers/react_query_provider.tsx index ee49e9cd081e0..cc47833ae3217 100644 --- a/x-pack/plugins/observability_solution/infra/public/containers/react_query_provider.tsx +++ b/x-pack/plugins/observability_solution/infra/public/containers/react_query_provider.tsx @@ -6,6 +6,7 @@ */ import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; import { QueryClient, QueryClientConfig, QueryClientProvider } from '@tanstack/react-query'; import merge from 'lodash/merge'; import { EuiButtonIcon } from '@elastic/eui'; @@ -36,7 +37,7 @@ export function ReactQueryProvider({ children, config = {} }: ProviderProps) { function HideableReactQueryDevTools() { const [isHidden, setIsHidden] = useState(false); - return !isHidden ? ( + return !isHidden && process.env.NODE_ENV === 'development' ? (
setIsHidden(!isHidden)} - aria-label="Disable React Query Dev Tools" + aria-label={i18n.translate( + 'xpack.infra.hideableReactQueryDevTools.euiButtonIcon.disableReactQueryDevLabel', + { defaultMessage: 'Disable React Query Dev Tools' } + )} />
diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/table/add_data_troubleshooting_popover.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/table/add_data_troubleshooting_popover.tsx new file mode 100644 index 0000000000000..419f78a892352 --- /dev/null +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/table/add_data_troubleshooting_popover.tsx @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { + EuiBadge, + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiPopover, + EuiPopoverFooter, + EuiPopoverTitle, + EuiText, +} from '@elastic/eui'; + +import { + ObservabilityOnboardingLocatorParams, + OBSERVABILITY_ONBOARDING_LOCATOR, +} from '@kbn/deeplinks-observability'; +import { i18n } from '@kbn/i18n'; +import { useBoolean } from '@kbn/react-hooks'; + +import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana'; +import { APM_HOST_TROUBLESHOOTING_LINK } from '../../../../../components/asset_details/constants'; + +const popoverContent = { + title: i18n.translate('xpack.infra.addDataPopover.wantToSeeMorePopoverTitleLabel', { + defaultMessage: 'Want to see more?', + }), + content: i18n.translate('xpack.infra.addDataPopover.understandHostPerformanceByTextLabel', { + defaultMessage: 'Understand host performance by collecting more metrics.', + }), + button: i18n.translate('xpack.infra.addDataPopover.understandHostPerformanceByTextLabel', { + defaultMessage: 'Add data', + }), + link: i18n.translate('xpack.infra.addDataPopover.troubleshootingLinkLabel', { + defaultMessage: 'Troubleshooting', + }), +}; + +const badgeContent = i18n.translate('xpack.infra.addDataPopover.naBadgeLabel', { + defaultMessage: 'N/A', +}); + +export const AddDataTroubleshootingPopover = () => { + const [isPopoverOpen, { off: closePopover, toggle: togglePopover }] = useBoolean(false); + + const { + services: { share }, + } = useKibanaContextForPlugin(); + const addDataLinkHref = share.url.locators + .get(OBSERVABILITY_ONBOARDING_LOCATOR) + ?.getRedirectUrl({ category: 'logs' }); + + const onButtonClick = () => togglePopover(); + + return ( + + {badgeContent} + + } + isOpen={isPopoverOpen} + closePopover={closePopover} + > + {popoverContent.title} + + {popoverContent.content} + + + + + + {popoverContent.button} + + + + + + {popoverContent.link} + + + + + + + ); +}; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts index 965f6acd24c93..a0ebb20184912 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useHostsTable } from './use_hosts_table'; +import { type HostNodeRow, useHostsTable } from './use_hosts_table'; import { renderHook } from '@testing-library/react-hooks'; import { InfraAssetMetricsItem } from '../../../../../common/http_api'; import * as useUnifiedSearchHooks from './use_unified_search'; @@ -158,7 +158,7 @@ describe('useHostTable hook', () => { } as unknown as ReturnType); }); it('it should map the nodes returned from the snapshot api to a format matching eui table items', () => { - const expected = [ + const expected: Array> = [ { name: 'host-0', os: '-', diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx index 4bdb72e625a89..e881950df570c 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.tsx @@ -40,6 +40,7 @@ import { ColumnHeader } from '../components/table/column_header'; import { TABLE_COLUMN_LABEL, TABLE_CONTENT_LABEL } from '../translations'; import { METRICS_TOOLTIP } from '../../../../common/visualizations'; import { buildCombinedAssetFilter } from '../../../../utils/filters/build'; +import { AddDataTroubleshootingPopover } from '../components/table/add_data_troubleshooting_popover'; /** * Columns and items types @@ -64,10 +65,31 @@ export type HostNodeRow = HostMetadata & * Helper functions */ const formatMetric = (type: InfraAssetMetricType, value: number | undefined | null) => { - return value || value === 0 ? createInventoryMetricFormatter({ type })(value) : 'N/A'; + const defaultValue = value ?? 0; + return createInventoryMetricFormatter({ type })(defaultValue); +}; + +const buildMetricCell = ( + value: number | null, + formatType: InfraAssetMetricType, + hasSystemMetrics?: boolean +) => { + if (!hasSystemMetrics && value === null) { + return ; + } + + return formatMetric(formatType, value); }; const buildItemsList = (nodes: InfraAssetMetricsItem[]): HostNodeRow[] => { + nodes.map((node) => { + if (node.name === 'instance') { + node.metrics[0].value = 0; + node.hasSystemMetrics = true; + } + return node; + }); + return nodes.map(({ metrics, metadata, name, alertsCount, hasSystemMetrics }) => { const metadataKeyValue = metadata.reduce( (acc, curr) => ({ @@ -89,7 +111,7 @@ const buildItemsList = (nodes: InfraAssetMetricsItem[]): HostNodeRow[] => { ...metrics.reduce( (acc, curr) => ({ ...acc, - [curr.name]: curr.value ?? 0, + [curr.name]: curr.value, }), {} as HostMetrics ), @@ -104,12 +126,15 @@ const isTitleColumn = (cell: HostNodeRow[keyof HostNodeRow]): cell is HostNodeRo }; const sortValues = (aValue: any, bValue: any, { direction }: Sorting) => { - if (typeof aValue === 'string' && typeof bValue === 'string') { - return direction === 'desc' ? bValue.localeCompare(aValue) : aValue.localeCompare(bValue); + const a = aValue ?? -1; + const b = bValue ?? -1; + + if (typeof a === 'string' && typeof b === 'string') { + return direction === 'desc' ? b.localeCompare(a) : a.localeCompare(b); } - if (isNumber(aValue) && isNumber(bValue)) { - return direction === 'desc' ? bValue - aValue : aValue - bValue; + if (isNumber(a) && isNumber(b)) { + return direction === 'desc' ? b - a : a - b; } return 1; @@ -358,7 +383,8 @@ export const useHostsTable = () => { field: 'cpuV2', sortable: true, 'data-test-subj': 'hostsView-tableRow-cpuUsage', - render: (avg: number) => formatMetric('cpuV2', avg), + render: (avg: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(avg, 'cpuV2', hasSystemMetrics), align: 'right', }, { @@ -373,7 +399,8 @@ export const useHostsTable = () => { field: 'normalizedLoad1m', sortable: true, 'data-test-subj': 'hostsView-tableRow-normalizedLoad1m', - render: (avg: number) => formatMetric('normalizedLoad1m', avg), + render: (avg: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(avg, 'normalizedLoad1m', hasSystemMetrics), align: 'right', }, { @@ -388,7 +415,8 @@ export const useHostsTable = () => { field: 'memory', sortable: true, 'data-test-subj': 'hostsView-tableRow-memoryUsage', - render: (avg: number) => formatMetric('memory', avg), + render: (avg: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(avg, 'memory', hasSystemMetrics), align: 'right', }, { @@ -403,7 +431,8 @@ export const useHostsTable = () => { field: 'memoryFree', sortable: true, 'data-test-subj': 'hostsView-tableRow-memoryFree', - render: (avg: number) => formatMetric('memoryFree', avg), + render: (avg: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(avg, 'memoryFree', hasSystemMetrics), align: 'right', }, { @@ -418,7 +447,8 @@ export const useHostsTable = () => { field: 'diskSpaceUsage', sortable: true, 'data-test-subj': 'hostsView-tableRow-diskSpaceUsage', - render: (max: number) => formatMetric('diskSpaceUsage', max), + render: (max: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(max, 'diskSpaceUsage', hasSystemMetrics), align: 'right', }, { @@ -433,7 +463,8 @@ export const useHostsTable = () => { field: 'rxV2', sortable: true, 'data-test-subj': 'hostsView-tableRow-rx', - render: (avg: number) => formatMetric('rx', avg), + render: (avg: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(avg, 'rx', hasSystemMetrics), align: 'right', }, { @@ -448,7 +479,8 @@ export const useHostsTable = () => { field: 'txV2', sortable: true, 'data-test-subj': 'hostsView-tableRow-tx', - render: (avg: number) => formatMetric('tx', avg), + render: (avg: number, { hasSystemMetrics }: HostNodeRow) => + buildMetricCell(avg, 'tx', hasSystemMetrics), align: 'right', }, ], diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.test.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.test.ts index f4da045101626..40f392084942b 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_service/synthetics_service.test.ts @@ -392,7 +392,7 @@ describe('SyntheticsService', () => { describe('getSyntheticsParams', () => { it('returns the params for all spaces', async () => { const { service } = getMockedService(); - jest.spyOn(service, 'getSyntheticsParams').mockReset(); + jest.spyOn(service, 'getSyntheticsParams').mockRestore(); (axios as jest.MockedFunction).mockResolvedValue({} as AxiosResponse); @@ -416,7 +416,7 @@ describe('SyntheticsService', () => { it('returns the params for specific space', async () => { const { service } = getMockedService(); - jest.spyOn(service, 'getSyntheticsParams').mockReset(); + jest.spyOn(service, 'getSyntheticsParams').mockRestore(); serverMock.encryptedSavedObjects = mockEncryptedSO({ params: [ @@ -440,7 +440,7 @@ describe('SyntheticsService', () => { }); it('returns the space limited params', async () => { const { service } = getMockedService(); - jest.spyOn(service, 'getSyntheticsParams').mockReset(); + jest.spyOn(service, 'getSyntheticsParams').mockRestore(); serverMock.encryptedSavedObjects = mockEncryptedSO({ params: [ diff --git a/x-pack/plugins/osquery/public/packs/form/shards/shards_policy_field.tsx b/x-pack/plugins/osquery/public/packs/form/shards/shards_policy_field.tsx index bf4bdf0540bdc..bf14459f8edb0 100644 --- a/x-pack/plugins/osquery/public/packs/form/shards/shards_policy_field.tsx +++ b/x-pack/plugins/osquery/public/packs/form/shards/shards_policy_field.tsx @@ -28,15 +28,17 @@ const ShardsPolicyFieldComponent = ({ }: ShardsPolicyFieldComponent) => { const { data: { agentPoliciesById } = {} } = useAgentPolicies(); + const missingValueError = i18n.translate( + 'xpack.osquery.pack.form.shardsPolicyFieldMissingErrorMessage', + { + defaultMessage: 'Policy is a required field', + } + ); + const policyFieldValidator = useCallback( - (policy: { key: string; label: string }) => - !policy - ? i18n.translate('xpack.osquery.pack.form.shardsPolicyFieldMissingErrorMessage', { - defaultMessage: 'Policy is a required field', - }) - : undefined, + (policy: { key: string; label: string }) => (!policy ? missingValueError : undefined), - [] + [missingValueError] ); const { @@ -47,6 +49,7 @@ const ShardsPolicyFieldComponent = ({ name: `shardsArray.${index}.policy`, rules: { validate: policyFieldValidator, + required: missingValueError, }, }); 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 165c06baa579b..6d3fccff0b91a 100644 --- a/x-pack/plugins/reporting/server/lib/content_stream.test.ts +++ b/x-pack/plugins/reporting/server/lib/content_stream.test.ts @@ -44,6 +44,11 @@ describe('ContentStream', () => { ); }); + afterEach(() => { + stream.destroy(); + base64Stream.destroy(); + }); + describe('read', () => { it('should perform a search using index and the document id', async () => { await new Promise((resolve) => stream.once('data', resolve)); diff --git a/x-pack/plugins/rule_registry/server/plugin.ts b/x-pack/plugins/rule_registry/server/plugin.ts index 2a430c45b54d8..7f6b6e0bf6002 100644 --- a/x-pack/plugins/rule_registry/server/plugin.ts +++ b/x-pack/plugins/rule_registry/server/plugin.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { type Subject, ReplaySubject } from 'rxjs'; -import type { +import { type Subject, ReplaySubject, Observable, map, distinctUntilChanged } from 'rxjs'; +import { PluginInitializerContext, Plugin, CoreSetup, @@ -14,6 +14,8 @@ import type { KibanaRequest, CoreStart, IContextProvider, + CoreStatus, + ServiceStatusLevels, } from '@kbn/core/server'; import type { @@ -91,6 +93,8 @@ export class RuleRegistryPlugin ): RuleRegistryPluginSetupContract { const { logger, kibanaVersion } = this; + const elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); + const startDependencies = core.getStartServices().then(([coreStart, pluginStart]) => { return { core: coreStart, @@ -115,6 +119,7 @@ export class RuleRegistryPlugin frameworkAlerts: plugins.alerting.frameworkAlerts, pluginStop$: this.pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); this.ruleDataService.initializeService(); @@ -200,3 +205,14 @@ export class RuleRegistryPlugin this.pluginStop$.complete(); } } + +function getElasticsearchAndSOAvailability(core$: Observable): Observable { + return core$.pipe( + map( + ({ elasticsearch, savedObjects }) => + elasticsearch.level === ServiceStatusLevels.available && + savedObjects.level === ServiceStatusLevels.available + ), + distinctUntilChanged() + ); +} diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.test.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.test.ts index 335ab73dd8fe6..d2011139adbb7 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.test.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type Subject, ReplaySubject } from 'rxjs'; +import { Subject, ReplaySubject, of } from 'rxjs'; import { ResourceInstaller } from './resource_installer'; import { loggerMock } from '@kbn/logging-mocks'; import { AlertConsumers } from '@kbn/rule-data-utils'; @@ -59,6 +59,7 @@ const GetDataStreamResponse: IndicesGetDataStreamResponse = { describe('resourceInstaller', () => { let pluginStop$: Subject; let dataStreamAdapter: DataStreamAdapter; + const elasticsearchAndSOAvailability$ = of(true); for (const useDataStreamForAlerts of [false, true]) { const label = useDataStreamForAlerts ? 'data streams' : 'aliases'; @@ -87,6 +88,7 @@ describe('resourceInstaller', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await installer.installCommonResources(); expect(getClusterClient).not.toHaveBeenCalled(); @@ -105,6 +107,7 @@ describe('resourceInstaller', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { feature: AlertConsumers.LOGS, @@ -137,6 +140,7 @@ describe('resourceInstaller', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await installer.installCommonResources(); @@ -155,6 +159,33 @@ describe('resourceInstaller', () => { ); }); + it('should not install common resources if ES is not ready', async () => { + const mockClusterClient = elasticsearchServiceMock.createElasticsearchClient(); + const getClusterClient = jest.fn(() => Promise.resolve(mockClusterClient)); + const test$ = new Subject(); + + const installer = new ResourceInstaller({ + logger: loggerMock.create(), + isWriteEnabled: true, + disabledRegistrationContexts: [], + getResourceName: jest.fn(), + getClusterClient, + frameworkAlerts: frameworkAlertsService, + pluginStop$, + dataStreamAdapter, + elasticsearchAndSOAvailability$: test$, + }); + + const install = installer.installCommonResources(); + const timeout = new Promise((resolve) => { + setTimeout(resolve, 1000); + }); + + await Promise.race([install, timeout]); + + expect(mockClusterClient.cluster.putComponentTemplate).not.toHaveBeenCalled(); + }); + it('should install subset of common resources when framework alerts are enabled', async () => { const mockClusterClient = elasticsearchServiceMock.createElasticsearchClient(); const getClusterClient = jest.fn(() => Promise.resolve(mockClusterClient)); @@ -170,6 +201,7 @@ describe('resourceInstaller', () => { }, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); await installer.installCommonResources(); @@ -196,6 +228,7 @@ describe('resourceInstaller', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { @@ -232,6 +265,7 @@ describe('resourceInstaller', () => { }, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { @@ -281,6 +315,7 @@ describe('resourceInstaller', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { @@ -347,6 +382,7 @@ describe('resourceInstaller', () => { }, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { @@ -384,6 +420,7 @@ describe('resourceInstaller', () => { }, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { @@ -426,6 +463,7 @@ describe('resourceInstaller', () => { }, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { @@ -490,6 +528,7 @@ describe('resourceInstaller', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }; const indexOptions = { feature: AlertConsumers.OBSERVABILITY, diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts index f1dfb6f851eb0..2a6533d7e1002 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/resource_installer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type Observable } from 'rxjs'; +import { type Observable, firstValueFrom, filter } from 'rxjs'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { PublicMethodsOf } from '@kbn/utility-types'; import { @@ -37,6 +37,7 @@ interface ConstructorOptions { frameworkAlerts: PublicFrameworkAlertsService; pluginStop$: Observable; dataStreamAdapter: DataStreamAdapter; + elasticsearchAndSOAvailability$: Observable; } export type IResourceInstaller = PublicMethodsOf; @@ -53,6 +54,11 @@ export class ResourceInstaller { * - component template containing all standard ECS fields */ public async installCommonResources(): Promise { + await firstValueFrom( + this.options.elasticsearchAndSOAvailability$.pipe( + filter((areESAndSOAvailable) => areESAndSOAvailable) + ) + ); const resourceDescription = 'common resources shared between all indices'; const { logger, isWriteEnabled } = this.options; if (!isWriteEnabled) { diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.test.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.test.ts index b2736ee7f3cfe..1f36799fc65ec 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.test.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { type Subject, ReplaySubject } from 'rxjs'; +import { type Subject, ReplaySubject, of } from 'rxjs'; import { loggerMock } from '@kbn/logging-mocks'; import { RuleDataService } from './rule_data_plugin_service'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; @@ -29,6 +29,7 @@ const frameworkAlertsService = { describe('ruleDataPluginService', () => { let pluginStop$: Subject; let dataStreamAdapter: DataStreamAdapter; + const elasticsearchAndSOAvailability$ = of(true); beforeEach(() => { jest.resetAllMocks(); @@ -56,6 +57,7 @@ describe('ruleDataPluginService', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); expect(ruleDataService.isRegistrationContextDisabled('observability.logs')).toBe(true); }); @@ -74,6 +76,7 @@ describe('ruleDataPluginService', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); expect(ruleDataService.isRegistrationContextDisabled('observability.apm')).toBe(false); }); @@ -94,6 +97,7 @@ describe('ruleDataPluginService', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); expect(ruleDataService.isWriteEnabled('observability.logs')).toBe(false); @@ -115,6 +119,7 @@ describe('ruleDataPluginService', () => { frameworkAlerts: frameworkAlertsService, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); const indexOptions = { feature: AlertConsumers.LOGS, diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts index a5f160f05c537..efe4a5dd4f32f 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts @@ -99,6 +99,7 @@ interface ConstructorOptions { frameworkAlerts: PublicFrameworkAlertsService; pluginStop$: Observable; dataStreamAdapter: DataStreamAdapter; + elasticsearchAndSOAvailability$: Observable; } export class RuleDataService implements IRuleDataService { @@ -122,6 +123,7 @@ export class RuleDataService implements IRuleDataService { frameworkAlerts: options.frameworkAlerts, pluginStop$: options.pluginStop$, dataStreamAdapter: options.dataStreamAdapter, + elasticsearchAndSOAvailability$: this.options.elasticsearchAndSOAvailability$, }); this.installCommonResources = Promise.resolve(right('ok')); diff --git a/x-pack/plugins/search_indices/common/index.ts b/x-pack/plugins/search_indices/common/index.ts index a0e7d3fe35e68..f2b3e62577e4f 100644 --- a/x-pack/plugins/search_indices/common/index.ts +++ b/x-pack/plugins/search_indices/common/index.ts @@ -7,3 +7,5 @@ export const PLUGIN_ID = 'searchIndices'; export const PLUGIN_NAME = 'searchIndices'; + +export type { IndicesStatusResponse, UserStartPrivilegesResponse } from './types'; diff --git a/x-pack/plugins/search_indices/common/types.ts b/x-pack/plugins/search_indices/common/types.ts new file mode 100644 index 0000000000000..8c7af3889a5a2 --- /dev/null +++ b/x-pack/plugins/search_indices/common/types.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. + */ + +export interface IndicesStatusResponse { + indexNames: string[]; +} + +export interface UserStartPrivilegesResponse { + privileges: { + canCreateApiKeys: boolean; + canCreateIndex: boolean; + }; +} diff --git a/x-pack/plugins/search_indices/server/lib/status.test.ts b/x-pack/plugins/search_indices/server/lib/status.test.ts new file mode 100644 index 0000000000000..ff5a8fc1eadd5 --- /dev/null +++ b/x-pack/plugins/search_indices/server/lib/status.test.ts @@ -0,0 +1,231 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { + IndicesGetResponse, + SecurityHasPrivilegesResponse, +} from '@elastic/elasticsearch/lib/api/types'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { Logger } from '@kbn/logging'; +import { fetchIndicesStatus, fetchUserStartPrivileges } from './status'; + +const mockLogger = { + warn: jest.fn(), + error: jest.fn(), +}; +const logger: Logger = mockLogger as unknown as Logger; + +const mockClient = { + indices: { + get: jest.fn(), + }, + security: { + hasPrivileges: jest.fn(), + }, +}; +const client = mockClient as unknown as ElasticsearchClient; + +describe('status api lib', function () { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('fetchIndicesStatus', function () { + it('should return results from get', async () => { + const mockResult: IndicesGetResponse = {}; + mockClient.indices.get.mockResolvedValue(mockResult); + + await expect(fetchIndicesStatus(client, logger)).resolves.toEqual({ indexNames: [] }); + expect(mockClient.indices.get).toHaveBeenCalledTimes(1); + expect(mockClient.indices.get).toHaveBeenCalledWith({ + expand_wildcards: ['open'], + features: ['settings'], + index: '*', + }); + }); + it('should return index names', async () => { + const mockResult: IndicesGetResponse = { + 'unit-test-index': { + settings: {}, + }, + }; + mockClient.indices.get.mockResolvedValue(mockResult); + + await expect(fetchIndicesStatus(client, logger)).resolves.toEqual({ + indexNames: ['unit-test-index'], + }); + }); + it('should not return hidden indices', async () => { + const mockResult: IndicesGetResponse = { + 'unit-test-index': { + settings: {}, + }, + 'hidden-index': { + settings: { + index: { + hidden: true, + }, + }, + }, + }; + mockClient.indices.get.mockResolvedValue(mockResult); + + await expect(fetchIndicesStatus(client, logger)).resolves.toEqual({ + indexNames: ['unit-test-index'], + }); + + mockResult['hidden-index']!.settings!.index!.hidden = 'true'; + await expect(fetchIndicesStatus(client, logger)).resolves.toEqual({ + indexNames: ['unit-test-index'], + }); + }); + it('should not return closed indices', async () => { + const mockResult: IndicesGetResponse = { + 'unit-test-index': { + settings: {}, + }, + 'closed-index': { + settings: { + index: { + verified_before_close: true, + }, + }, + }, + }; + mockClient.indices.get.mockResolvedValue(mockResult); + + await expect(fetchIndicesStatus(client, logger)).resolves.toEqual({ + indexNames: ['unit-test-index'], + }); + + mockResult['closed-index']!.settings!.index!.verified_before_close = 'true'; + await expect(fetchIndicesStatus(client, logger)).resolves.toEqual({ + indexNames: ['unit-test-index'], + }); + }); + it('should raise exceptions', async () => { + const error = new Error('boom'); + mockClient.indices.get.mockRejectedValue(error); + + await expect(fetchIndicesStatus(client, logger)).rejects.toThrow(error); + }); + }); + + describe('fetchUserStartPrivileges', function () { + it('should return privileges true', async () => { + const result: SecurityHasPrivilegesResponse = { + application: {}, + cluster: { + manage_api_key: true, + }, + has_all_requested: true, + index: { + 'test-index-name': { + create_index: true, + }, + }, + username: 'unit-test', + }; + mockClient.security.hasPrivileges.mockResolvedValue(result); + + await expect(fetchUserStartPrivileges(client, logger)).resolves.toEqual({ + privileges: { + canCreateIndex: true, + canCreateApiKeys: true, + }, + }); + + expect(mockClient.security.hasPrivileges).toHaveBeenCalledTimes(1); + expect(mockClient.security.hasPrivileges).toHaveBeenCalledWith({ + cluster: ['manage_api_key'], + index: [ + { + names: ['test-index-name'], + privileges: ['create_index'], + }, + ], + }); + }); + it('should return privileges false', async () => { + const result: SecurityHasPrivilegesResponse = { + application: {}, + cluster: { + manage_api_key: false, + }, + has_all_requested: false, + index: { + 'test-index-name': { + create_index: false, + }, + }, + username: 'unit-test', + }; + mockClient.security.hasPrivileges.mockResolvedValue(result); + + await expect(fetchUserStartPrivileges(client, logger)).resolves.toEqual({ + privileges: { + canCreateIndex: false, + canCreateApiKeys: false, + }, + }); + }); + it('should return mixed privileges', async () => { + const result: SecurityHasPrivilegesResponse = { + application: {}, + cluster: { + manage_api_key: false, + }, + has_all_requested: false, + index: { + 'test-index-name': { + create_index: true, + }, + }, + username: 'unit-test', + }; + mockClient.security.hasPrivileges.mockResolvedValue(result); + + await expect(fetchUserStartPrivileges(client, logger)).resolves.toEqual({ + privileges: { + canCreateIndex: true, + canCreateApiKeys: false, + }, + }); + }); + it('should handle malformed responses', async () => { + const result: SecurityHasPrivilegesResponse = { + application: {}, + cluster: {}, + has_all_requested: true, + index: { + 'test-index-name': { + create_index: true, + }, + }, + username: 'unit-test', + }; + mockClient.security.hasPrivileges.mockResolvedValue(result); + + await expect(fetchUserStartPrivileges(client, logger)).resolves.toEqual({ + privileges: { + canCreateIndex: true, + canCreateApiKeys: false, + }, + }); + }); + it('should default privileges on exceptions', async () => { + mockClient.security.hasPrivileges.mockRejectedValue(new Error('Boom!!')); + + await expect(fetchUserStartPrivileges(client, logger)).resolves.toEqual({ + privileges: { + canCreateIndex: false, + canCreateApiKeys: false, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/search_indices/server/lib/status.ts b/x-pack/plugins/search_indices/server/lib/status.ts new file mode 100644 index 0000000000000..752e897ab1707 --- /dev/null +++ b/x-pack/plugins/search_indices/server/lib/status.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 type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { Logger } from '@kbn/logging'; + +import type { IndicesStatusResponse, UserStartPrivilegesResponse } from '../../common/types'; + +import { isHidden, isClosed } from '../utils/index_utils'; + +export async function fetchIndicesStatus( + client: ElasticsearchClient, + logger: Logger +): Promise { + const indexMatches = await client.indices.get({ + expand_wildcards: ['open'], + // for better performance only compute settings of indices but not mappings + features: ['settings'], + index: '*', + }); + + const indexNames = Object.keys(indexMatches).filter( + (indexName) => + indexMatches[indexName] && + !isHidden(indexMatches[indexName]) && + !isClosed(indexMatches[indexName]) + ); + + return { + indexNames, + }; +} + +export async function fetchUserStartPrivileges( + client: ElasticsearchClient, + logger: Logger, + indexName: string = 'test-index-name' +): Promise { + try { + const securityCheck = await client.security.hasPrivileges({ + cluster: ['manage_api_key'], + index: [ + { + names: [indexName], + privileges: ['create_index'], + }, + ], + }); + + return { + privileges: { + canCreateIndex: securityCheck?.index?.[indexName]?.create_index ?? false, + canCreateApiKeys: securityCheck?.cluster?.manage_api_key ?? false, + }, + }; + } catch (e) { + logger.error(`Error checking user privileges for searchIndices elasticsearch start`); + logger.error(e); + return { + privileges: { + canCreateIndex: false, + canCreateApiKeys: false, + }, + }; + } +} diff --git a/x-pack/plugins/search_indices/server/plugin.ts b/x-pack/plugins/search_indices/server/plugin.ts index 666e49016f551..f0adbb112356e 100644 --- a/x-pack/plugins/search_indices/server/plugin.ts +++ b/x-pack/plugins/search_indices/server/plugin.ts @@ -31,7 +31,7 @@ export class SearchIndicesPlugin const router = core.http.createRouter(); // Register server side APIs - defineRoutes(router); + defineRoutes(router, this.logger); return {}; } diff --git a/x-pack/plugins/search_indices/server/routes/index.ts b/x-pack/plugins/search_indices/server/routes/index.ts index c98be5b6a4490..03cb1371870cb 100644 --- a/x-pack/plugins/search_indices/server/routes/index.ts +++ b/x-pack/plugins/search_indices/server/routes/index.ts @@ -6,5 +6,10 @@ */ import type { IRouter } from '@kbn/core/server'; +import type { Logger } from '@kbn/logging'; -export function defineRoutes(router: IRouter) {} +import { registerStatusRoutes } from './status'; + +export function defineRoutes(router: IRouter, logger: Logger) { + registerStatusRoutes(router, logger); +} diff --git a/x-pack/plugins/search_indices/server/routes/status.ts b/x-pack/plugins/search_indices/server/routes/status.ts new file mode 100644 index 0000000000000..ab3a426510e6e --- /dev/null +++ b/x-pack/plugins/search_indices/server/routes/status.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IRouter } from '@kbn/core/server'; +import type { Logger } from '@kbn/logging'; + +import { fetchIndicesStatus, fetchUserStartPrivileges } from '../lib/status'; + +export function registerStatusRoutes(router: IRouter, logger: Logger) { + router.get( + { + path: '/internal/search_indices/status', + validate: {}, + options: { + access: 'internal', + }, + }, + async (context, _request, response) => { + const core = await context.core; + const client = core.elasticsearch.client.asCurrentUser; + const body = await fetchIndicesStatus(client, logger); + + return response.ok({ + body, + headers: { 'content-type': 'application/json' }, + }); + } + ); + + router.get( + { + path: '/internal/search_indices/start_privileges', + validate: {}, + options: { + access: 'internal', + }, + }, + async (context, _request, response) => { + const core = await context.core; + const client = core.elasticsearch.client.asCurrentUser; + const body = await fetchUserStartPrivileges(client, logger); + + return response.ok({ + body, + headers: { 'content-type': 'application/json' }, + }); + } + ); +} diff --git a/x-pack/plugins/search_indices/server/utils/index_utils.test.ts b/x-pack/plugins/search_indices/server/utils/index_utils.test.ts new file mode 100644 index 0000000000000..95860468e5fcf --- /dev/null +++ b/x-pack/plugins/search_indices/server/utils/index_utils.test.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isClosed, isHidden } from './index_utils'; + +describe('index utils', function () { + describe('isClosed', function () { + it('handles boolean values', () => { + expect( + isClosed({ + settings: { + index: { + verified_before_close: true, + }, + }, + }) + ).toBe(true); + expect( + isClosed({ + settings: { + index: { + verified_before_close: false, + }, + }, + }) + ).toBe(false); + }); + it('handles string values', () => { + expect( + isClosed({ + settings: { + index: { + verified_before_close: 'true', + }, + }, + }) + ).toBe(true); + expect( + isClosed({ + settings: { + index: { + verified_before_close: 'false', + }, + }, + }) + ).toBe(false); + }); + it('handles undefined index settings', () => { + expect( + isClosed({ + settings: {}, + }) + ).toBe(false); + }); + }); + describe('isHidden', function () { + it('handles boolean values', () => { + expect( + isHidden({ + settings: { + index: { + hidden: true, + }, + }, + }) + ).toBe(true); + expect( + isHidden({ + settings: { + index: { + hidden: false, + }, + }, + }) + ).toBe(false); + }); + it('handles string values', () => { + expect( + isHidden({ + settings: { + index: { + hidden: 'true', + }, + }, + }) + ).toBe(true); + expect( + isHidden({ + settings: { + index: { + hidden: 'false', + }, + }, + }) + ).toBe(false); + }); + it('handles undefined index settings', () => { + expect( + isHidden({ + settings: {}, + }) + ).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/search_indices/server/utils/index_utils.ts b/x-pack/plugins/search_indices/server/utils/index_utils.ts new file mode 100644 index 0000000000000..d0b47b303679e --- /dev/null +++ b/x-pack/plugins/search_indices/server/utils/index_utils.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 { IndicesIndexState } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +export function isHidden(index: IndicesIndexState): boolean { + return index.settings?.index?.hidden === true || index.settings?.index?.hidden === 'true'; +} + +export function isClosed(index: IndicesIndexState): boolean { + return ( + index.settings?.index?.verified_before_close === true || + index.settings?.index?.verified_before_close === 'true' + ); +} diff --git a/x-pack/plugins/search_indices/tsconfig.json b/x-pack/plugins/search_indices/tsconfig.json index 48969cf7142bb..406b9de2400ce 100644 --- a/x-pack/plugins/search_indices/tsconfig.json +++ b/x-pack/plugins/search_indices/tsconfig.json @@ -14,6 +14,8 @@ "@kbn/core", "@kbn/navigation-plugin", "@kbn/config-schema", + "@kbn/core-elasticsearch-server", + "@kbn/logging", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index ed8d76c1949a7..fde8e1f4537a7 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -170,7 +170,7 @@ export const allowedExperimentalValues = Object.freeze({ /** * Enables experimental JAMF integration data to be available in Analyzer */ - jamfDataInAnalyzerEnabled: false, + jamfDataInAnalyzerEnabled: true, /* * Disables discover esql tab within timeline diff --git a/x-pack/plugins/security_solution/public/attack_discovery/attack_discovery_markdown_formatter/field_markdown_renderer/index.test.tsx b/x-pack/plugins/security_solution/public/attack_discovery/attack_discovery_markdown_formatter/field_markdown_renderer/index.test.tsx index 8f647d02a626f..344370c0f165f 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/attack_discovery_markdown_formatter/field_markdown_renderer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/attack_discovery_markdown_formatter/field_markdown_renderer/index.test.tsx @@ -11,10 +11,9 @@ import React from 'react'; import { TestProviders } from '../../../common/mock'; import { getFieldMarkdownRenderer } from '.'; +import { createExpandableFlyoutApiMock } from '../../../common/mock/expandable_flyout'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), -})); +jest.mock('@kbn/expandable-flyout'); describe('getFieldMarkdownRenderer', () => { const mockOpenRightPanel = jest.fn(); @@ -26,14 +25,7 @@ describe('getFieldMarkdownRenderer', () => { jest.clearAllMocks(); mockUseExpandableFlyoutApi.mockReturnValue({ - closeFlyout: jest.fn(), - closeLeftPanel: jest.fn(), - closePreviewPanel: jest.fn(), - closeRightPanel: jest.fn(), - previousPreviewPanel: jest.fn(), - openFlyout: jest.fn(), - openLeftPanel: jest.fn(), - openPreviewPanel: jest.fn(), + ...createExpandableFlyoutApiMock(), openRightPanel: mockOpenRightPanel, }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts b/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts index fdd22f50aa7cb..a6073395f45fc 100644 --- a/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/assignees/translations.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; export const ASSIGNEES_SELECTION_STATUS_MESSAGE = (total: number) => i18n.translate('xpack.securitySolution.assignees.totalUsersAssigned', { - defaultMessage: '{total, plural, one {# filter} other {# filters}} selected', + defaultMessage: '{total, plural, one {# assignee} other {# assignees}} selected', values: { total }, }); diff --git a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.test.tsx index a680590d3752a..17039cd443888 100644 --- a/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/control_columns/row_action/index.test.tsx @@ -16,6 +16,9 @@ import type { RouteSpyState } from '../../../utils/route/types'; import { SecurityPageName } from '@kbn/deeplinks-security'; import { createTelemetryServiceMock } from '../../../lib/telemetry/telemetry_service.mock'; import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/shared/constants/panel_keys'; +import type { ExpandableFlyoutState } from '@kbn/expandable-flyout'; +import { useExpandableFlyoutApi, useExpandableFlyoutState } from '@kbn/expandable-flyout'; +import { createExpandableFlyoutApiMock } from '../../../mock/expandable_flyout'; const mockDispatch = jest.fn(); jest.mock('react-redux', () => { @@ -26,16 +29,11 @@ jest.mock('react-redux', () => { useDispatch: () => mockDispatch, }; }); -const mockOpenFlyout = jest.fn(); jest.mock('../../../utils/route/use_route_spy'); -jest.mock('@kbn/expandable-flyout', () => { - return { - useExpandableFlyoutApi: () => ({ openFlyout: mockOpenFlyout }), - useExpandableFlyoutState: () => ({ left: false }), - }; -}); +const mockOpenFlyout = jest.fn(); +jest.mock('@kbn/expandable-flyout'); const mockedTelemetry = createTelemetryServiceMock(); jest.mock('../../../lib/kibana', () => { @@ -102,6 +100,11 @@ describe('RowAction', () => { }; beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue({ + ...createExpandableFlyoutApiMock(), + openFlyout: mockOpenFlyout, + }); + jest.mocked(useExpandableFlyoutState).mockReturnValue({} as unknown as ExpandableFlyoutState); (useRouteSpy as jest.Mock).mockReturnValue([mockRouteSpy]); jest.clearAllMocks(); }); diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/use_timelines_events.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/use_timelines_events.tsx index 375346e42c834..4455e613b8776 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/use_timelines_events.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/use_timelines_events.tsx @@ -126,7 +126,7 @@ const useApmTracking = (tableId: string) => { // The blocking span needs to be ended manually when the batched request finishes. const span = transaction?.startSpan('batched search', 'http-request', { blocking: true }); return { - endTracking: (result: 'success' | 'error' | 'aborted' | 'invalid') => { + endTracking: (result: 'success' | 'error' | 'aborted') => { transaction?.addLabels({ result }); span?.end(); }, @@ -230,7 +230,7 @@ export const useTimelineEventsHandler = ({ abortCtrl.current = new AbortController(); setLoading(true); if (data && data.search) { - startTracking(); + const { endTracking } = startTracking(); const abortSignal = abortCtrl.current.signal; searchSubscription$.current = data.search .search>( @@ -249,6 +249,7 @@ export const useTimelineEventsHandler = ({ next: (response) => { if (!isRunningResponse(response)) { setTimelineResponse((prevResponse) => { + endTracking('success'); const newTimelineResponse = { ...prevResponse, consumers: response.consumers, @@ -271,6 +272,7 @@ export const useTimelineEventsHandler = ({ } }, error: (msg) => { + endTracking(abortSignal.aborted ? 'aborted' : 'error'); setLoading(false); data.search.showError(msg); searchSubscription$.current.unsubscribe(); diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts index 14800d0a2b78f..27a6d28418e9e 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/kibana_react.mock.ts @@ -58,6 +58,7 @@ import { indexPatternFieldEditorPluginMock } from '@kbn/data-view-field-editor-p import { UpsellingService } from '@kbn/security-solution-upselling/service'; import { calculateBounds } from '@kbn/data-plugin/common'; import { alertingPluginMock } from '@kbn/alerting-plugin/public/mocks'; +import { createTelemetryServiceMock } from '../telemetry/telemetry_service.mock'; const mockUiSettings: Record = { [DEFAULT_TIME_RANGE]: { from: 'now-15m', to: 'now', mode: 'quick' }, @@ -214,7 +215,7 @@ export const createStartServicesMock = ( ml: { locator, }, - telemetry: {}, + telemetry: createTelemetryServiceMock(), theme: themeServiceMock.createSetupContract(), timelines: { getLastUpdated: jest.fn(), diff --git a/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx b/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx new file mode 100644 index 0000000000000..a987e99a67d0e --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx @@ -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'; + +export const createExpandableFlyoutApiMock = () => ({ + closeFlyout: jest.fn(), + closeLeftPanel: jest.fn(), + closePreviewPanel: jest.fn(), + closeRightPanel: jest.fn(), + previousPreviewPanel: jest.fn(), + openFlyout: jest.fn(), + openLeftPanel: jest.fn(), + openPreviewPanel: jest.fn(), + openRightPanel: jest.fn(), +}); + +export const createExpandableFlyoutMock = () => { + return { + useExpandableFlyoutApi: jest.fn().mockReturnValue(createExpandableFlyoutApiMock()), + useExpandableFlyoutState: jest.fn(), + ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, + withExpandableFlyoutProvider: (Component: React.ComponentType) => { + return (props: T) => { + return ; + }; + }, + ExpandableFlyout: jest.fn(), + }; +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.test.ts index d8a1823622bdf..6937026e8ba0a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.test.ts @@ -10,7 +10,12 @@ import { getExceptionListSchemaMock } from '@kbn/lists-plugin/common/schemas/res import { ExceptionListTypeEnum } from '@kbn/securitysolution-io-ts-list-types'; import { getRulesSchemaMock } from '../../../../../common/api/detection_engine/model/rule_schema/rule_response_schema.mock'; -import { isSubmitDisabled, prepareNewItemsForSubmission, prepareToCloseAlerts } from './helpers'; +import { + isSubmitDisabled, + prepareNewItemsForSubmission, + prepareToCloseAlerts, + getSuccessToastTitle, +} from './helpers'; import type { Rule } from '../../../rule_management/logic/types'; import type { AlertData } from '../../utils/types'; @@ -469,4 +474,18 @@ describe('add_exception_flyout#helpers', () => { expect(ruleStaticIds).toEqual(['query-rule-id']); }); }); + + describe('getSuccessToastTitle', () => { + it('returns endpoint title when list type is "endpoint"', () => { + expect(getSuccessToastTitle(ExceptionListTypeEnum.ENDPOINT)).toEqual( + 'Endpoint exception added to shared exception list' + ); + }); + + it('returns non endpoint title when list type is not "endpoint"', () => { + expect(getSuccessToastTitle(ExceptionListTypeEnum.DETECTION)).toEqual( + 'Rule exception added to shared exception list' + ); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.ts index 23d20f699780d..76478ddc67023 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/helpers.ts @@ -14,6 +14,7 @@ import type { ExceptionsBuilderReturnExceptionItem } from '@kbn/securitysolution import type { Rule } from '../../../rule_management/logic/types'; import { enrichNewExceptionItems } from '../flyout_components/utils'; import type { AlertData } from '../../utils/types'; +import * as i18n from './translations'; const RULE_DEFAULT_OPTIONS = ['add_to_rule', 'add_to_rules', 'select_rules_to_add_to']; @@ -183,3 +184,14 @@ export const prepareToCloseAlerts = ({ ruleStaticIds, }; }; + +export const getSuccessToastTitle = (listType: ExceptionListTypeEnum) => + listType === ExceptionListTypeEnum.ENDPOINT + ? i18n.ADD_ENDPOINT_EXCEPTION_SUCCESS + : i18n.ADD_EXCEPTION_SUCCESS; + +export const getSuccessToastText = (listType: ExceptionListTypeEnum, sharedListNames: string[]) => + i18n.ADD_EXCEPTION_SUCCESS_DETAILS( + listType === ExceptionListTypeEnum.ENDPOINT ? 'Endpoint' : 'Rule', + sharedListNames.join(',') + ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts index d27d7994bb375..a8dbde51b2b56 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/translations.ts @@ -53,14 +53,18 @@ export const ADD_EXCEPTION_SUCCESS = i18n.translate( } ); -export const ADD_EXCEPTION_SUCCESS_DETAILS = (listNames: string) => - i18n.translate( - 'xpack.securitySolution.ruleExceptions.addExceptionFlyout.closeAlerts.successDetails', - { - values: { listNames }, - defaultMessage: 'Rule exception has been added to shared lists: {listNames}.', - } - ); +export const ADD_ENDPOINT_EXCEPTION_SUCCESS = i18n.translate( + 'xpack.securitySolution.ruleExceptions.addEndpointException.success', + { + defaultMessage: 'Endpoint exception added to shared exception list', + } +); + +export const ADD_EXCEPTION_SUCCESS_DETAILS = (listType: string, listNames: string) => + i18n.translate('xpack.securitySolution.ruleExceptions.addExceptionFlyout.successDetails', { + values: { listNames, listType }, + defaultMessage: '{listType} exception has been added to shared lists: {listNames}.', + }); export const ADD_RULE_EXCEPTION_SUCCESS_TITLE = i18n.translate( 'xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessTitle', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts index 7aa686ed43cdf..136a93ab13329 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/use_add_new_exceptions.ts @@ -25,6 +25,7 @@ import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import type { Rule } from '../../../rule_management/logic/types'; import { useCreateOrUpdateException } from '../../logic/use_create_update_exception'; import { useAddRuleDefaultException } from '../../logic/use_add_rule_exception'; +import { getSuccessToastText, getSuccessToastTitle } from './helpers'; export interface AddNewExceptionItemHookProps { itemsToAdd: ExceptionsBuilderReturnExceptionItem[]; @@ -110,10 +111,12 @@ export const useAddNewExceptionItems = (): ReturnUseAddNewExceptionItems => { result = await addSharedExceptions(itemsToAdd); const sharedListNames = sharedLists.map(({ name }) => name); + const title = getSuccessToastTitle(listType); + const text = getSuccessToastText(listType, sharedListNames); addSuccess({ - title: i18n.ADD_EXCEPTION_SUCCESS, - text: i18n.ADD_EXCEPTION_SUCCESS_DETAILS(sharedListNames.join(',')), + title, + text, }); } diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.test.tsx index 7de22b5a529b0..d398d380f8a5d 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_analytics_risk_score/index.test.tsx @@ -15,6 +15,7 @@ import { useKibana as mockUseKibana } from '../../../common/lib/kibana/__mocks__ import { createTelemetryServiceMock } from '../../../common/lib/telemetry/telemetry_service.mock'; import { useRiskScore } from '../../api/hooks/use_risk_score'; import { useRiskScoreKpi } from '../../api/hooks/use_risk_score_kpi'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; const mockedTelemetry = createTelemetryServiceMock(); const mockedUseKibana = mockUseKibana(); @@ -70,18 +71,15 @@ jest.mock('../../../common/hooks/use_navigate_to_alerts_page_with_filters', () = }); const mockOpenRightPanel = jest.fn(); -jest.mock('@kbn/expandable-flyout', () => { - return { - useExpandableFlyoutApi: () => ({ - openRightPanel: mockOpenRightPanel, - }), - }; -}); +jest.mock('@kbn/expandable-flyout'); describe.each([RiskScoreEntity.host, RiskScoreEntity.user])( 'EntityAnalyticsRiskScores entityType: %s', (riskEntity) => { beforeEach(() => { + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ + openRightPanel: mockOpenRightPanel, + }); jest.clearAllMocks(); mockUseRiskScoreKpi.mockReturnValue({ severityCount: mockSeverityCount, diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx index d9c7f61201789..21ea627d3f65d 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.tsx @@ -22,6 +22,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { euiThemeVars } from '@kbn/ui-theme'; import dateMath from '@kbn/datemath'; import { i18n } from '@kbn/i18n'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { ENABLE_ASSET_CRITICALITY_SETTING } from '../../../../common/constants'; import { useKibana, useUiSetting$ } from '../../../common/lib/kibana/kibana_react'; @@ -32,7 +33,6 @@ import { ONE_WEEK_IN_HOURS } from '../../../flyout/entity_details/shared/constan import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; import { RiskScoreEntity } from '../../../../common/entity_analytics/risk_engine'; import { VisualizationEmbeddable } from '../../../common/components/visualization_actions/visualization_embeddable'; -import { ExpandablePanel } from '../../../flyout/shared/components/expandable_panel'; import type { RiskScoreState } from '../../api/hooks/use_risk_score'; import { getRiskScoreSummaryAttributes } from '../../lens_attributes/risk_score_summary'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/alert_reason.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/alert_reason.tsx index 62e6e9f492b2f..03b84bc625552 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/alert_reason.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/alert_reason.tsx @@ -10,11 +10,11 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui'; import styled from '@emotion/styled'; import { euiThemeVars } from '@kbn/ui-theme'; import { FormattedMessage } from '@kbn/i18n-react'; +import { FlyoutError } from '@kbn/security-solution-common'; import { ALERT_REASON_BODY_TEST_ID } from './test_ids'; import { useAlertReasonPanelContext } from './context'; import { getRowRenderer } from '../../../timelines/components/timeline/body/renderers/get_row_renderer'; import { defaultRowRenderers } from '../../../timelines/components/timeline/body/renderers'; -import { FlyoutError } from '../../shared/components/flyout_error'; const ReasonContainerWrapper = styled.div` overflow-x: auto; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/context.tsx index b67c9af508d96..ec8096d60e72c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/alert_reason/context.tsx @@ -7,9 +7,8 @@ import React, { createContext, memo, useContext, useMemo } from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { FlyoutError, FlyoutLoading } from '@kbn/security-solution-common'; import { useEventDetails } from '../shared/hooks/use_event_details'; -import { FlyoutError } from '../../shared/components/flyout_error'; -import { FlyoutLoading } from '../../shared/components/flyout_loading'; import type { AlertReasonPanelProps } from '.'; export interface AlertReasonPanelContext { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx index 0c9f05391d82a..6ae172ca62556 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/content.tsx @@ -8,6 +8,7 @@ import type { FC } from 'react'; import React, { useCallback } from 'react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { FlyoutBody } from '@kbn/security-solution-common'; import { DocumentDetailsRightPanelKey } from '../shared/constants/panel_keys'; import { useBasicDataFromDetailsData } from '../shared/hooks/use_basic_data_from_details_data'; import { @@ -16,7 +17,6 @@ import { } from '../../../common/components/endpoint/host_isolation'; import { useHostIsolation } from '../shared/hooks/use_host_isolation'; import { useIsolateHostPanelContext } from './context'; -import { FlyoutBody } from '../../shared/components/flyout_body'; /** * Document details expandable flyout section content for the isolate host component, displaying the form or the success banner diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/context.tsx index 53393e2f8a79b..6abfe1c4e8650 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/context.tsx @@ -8,9 +8,8 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import React, { createContext, memo, useContext, useMemo } from 'react'; +import { FlyoutError, FlyoutLoading } from '@kbn/security-solution-common'; import { useEventDetails } from '../shared/hooks/use_event_details'; -import { FlyoutError } from '../../shared/components/flyout_error'; -import { FlyoutLoading } from '../../shared/components/flyout_loading'; import type { IsolateHostPanelProps } from '.'; export interface IsolateHostPanelContext { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx index aa4c04623dfba..80f75f9808620 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/isolate_host/header.tsx @@ -8,12 +8,12 @@ import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import type { FC } from 'react'; import React, { useMemo } from 'react'; +import { FlyoutHeader } from '@kbn/security-solution-common'; import { AgentTypeIntegration } from '../../../common/components/endpoint/agents/agent_type_integration'; import { useAlertResponseActionsSupport } from '../../../common/hooks/endpoint/use_alert_response_actions_support'; import { TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_TOOLTIP } from '../../../common/translations'; import { useIsolateHostPanelContext } from './context'; import { FLYOUT_HEADER_TITLE_TEST_ID } from './test_ids'; -import { FlyoutHeader } from '../../shared/components/flyout_header'; import { ISOLATE_HOST, UNISOLATE_HOST } from '../../../common/components/endpoint'; /** diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx index b3b129a75c13d..859da37c4082d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx @@ -28,7 +28,7 @@ import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_f import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; import { mockContextValue } from '../../shared/mocks/mock_context'; import { useTimelineDataFilters } from '../../../../timelines/containers/use_timeline_data_filters'; -import { EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID } from '../../../shared/components/test_ids'; +import { EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID } from '@kbn/security-solution-common'; jest.mock('react-router-dom', () => { const actual = jest.requireActual('react-router-dom'); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx index f9391fe8fec06..ddf05af5d3908 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.test.tsx @@ -22,10 +22,7 @@ jest.mock('../hooks/use_paginated_alerts'); jest.mock('../../../../common/hooks/use_experimental_features'); const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const TEST_ID = 'TEST'; const alertIds = ['id1', 'id2', 'id3']; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx index 178adabb80700..70b238825d66a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details_alerts_table.tsx @@ -14,12 +14,12 @@ import { isRight } from 'fp-ts/lib/Either'; import { ALERT_REASON, ALERT_RULE_NAME } from '@kbn/rule-data-utils'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { CellTooltipWrapper } from '../../shared/components/cell_tooltip_wrapper'; import type { DataProvider } from '../../../../../common/types'; import { SeverityBadge } from '../../../../common/components/severity_badge'; import { usePaginatedAlerts } from '../hooks/use_paginated_alerts'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import { InvestigateInTimelineButton } from '../../../../common/components/event_details/table/investigate_in_timeline_button'; import { ACTION_INVESTIGATE_IN_TIMELINE } from '../../../../detections/components/alerts_table/translations'; import { getDataProvider } from '../../../../common/components/event_details/table/use_action_cell_data_provider'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx index d9d468649a221..b6c5dc0078b02 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/entities_details.test.tsx @@ -13,7 +13,7 @@ import { TestProviders } from '../../../../common/mock'; import { EntitiesDetails } from './entities_details'; import { ENTITIES_DETAILS_TEST_ID, HOST_DETAILS_TEST_ID, USER_DETAILS_TEST_ID } from './test_ids'; import { mockContextValue } from '../../shared/mocks/mock_context'; -import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '../../../shared/components/test_ids'; +import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '@kbn/security-solution-common'; import type { Anomalies } from '../../../../common/components/ml/types'; import { useMlCapabilities } from '../../../../common/components/ml/hooks/use_ml_capabilities'; import { mockAnomalies } from '../../../../common/components/ml/mock'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx index 213bfbbecaa25..7ba3d7823f24d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.test.tsx @@ -24,7 +24,7 @@ import { HOST_DETAILS_LINK_TEST_ID, HOST_DETAILS_RELATED_USERS_LINK_TEST_ID, } from './test_ids'; -import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '../../../shared/components/test_ids'; +import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '@kbn/security-solution-common'; import { useRiskScore } from '../../../../entity_analytics/api/hooks/use_risk_score'; import { mockContextValue } from '../../shared/mocks/mock_context'; import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context'; @@ -34,10 +34,7 @@ import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview import { UserPreviewPanelKey } from '../../../entity_details/user_right'; import { USER_PREVIEW_BANNER } from '../../right/components/user_entity_overview'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../common/hooks/use_experimental_features'); const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx index 594409c82f880..49813f43d3de1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/host_details.tsx @@ -24,8 +24,8 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import type { RelatedUser } from '../../../../../common/search_strategy/security_solution/related_entities/related_users'; import type { RiskSeverity } from '../../../../../common/search_strategy'; import { HostOverview } from '../../../../overview/components/host_overview'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx index ee1bebdb336ce..f39057a16bfdb 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/investigation_guide.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { FlyoutLoading } from '@kbn/security-solution-common'; import { useInvestigationGuide } from '../../shared/hooks/use_investigation_guide'; import { useDocumentDetailsContext } from '../../shared/context'; import { INVESTIGATION_GUIDE_TEST_ID, INVESTIGATION_GUIDE_LOADING_TEST_ID } from './test_ids'; import { InvestigationGuideView } from './investigation_guide_view'; -import { FlyoutLoading } from '../../../shared/components/flyout_loading'; /** * Investigation guide displayed in the left panel. diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx index 5b7da67186e34..f1abc48f0e87a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/prevalence_details.test.tsx @@ -33,10 +33,7 @@ import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview import { UserPreviewPanelKey } from '../../../entity_details/user_right'; import { USER_PREVIEW_BANNER } from '../../right/components/user_entity_overview'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../common/hooks/use_experimental_features'); const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_ancestry.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_ancestry.test.tsx index 52468f0aedbb9..62012b72052bc 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_ancestry.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_ancestry.test.tsx @@ -20,7 +20,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { usePaginatedAlerts } from '../hooks/use_paginated_alerts'; jest.mock('../../shared/hooks/use_fetch_related_alerts_by_ancestry'); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx index 3cf2d93896bc3..f4244fcc59a04 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx @@ -20,7 +20,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { usePaginatedAlerts } from '../hooks/use_paginated_alerts'; jest.mock('../../shared/hooks/use_fetch_related_alerts_by_same_source_event'); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_session.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_session.test.tsx index 0120f462b9ac5..54df7e8924f68 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_session.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_session.test.tsx @@ -21,7 +21,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; jest.mock('../../shared/hooks/use_fetch_related_alerts_by_session'); jest.mock('../hooks/use_paginated_alerts'); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx index db9eb7bdfb3ae..4d90cc7f56133 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.test.tsx @@ -18,7 +18,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; jest.mock('../../shared/hooks/use_fetch_related_cases'); jest.mock('../../../../common/components/links', () => ({ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx index 13df33a2deb1b..8e00e0e65478b 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_cases.tsx @@ -10,6 +10,7 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { EuiInMemoryTable } from '@elastic/eui'; import type { RelatedCase } from '@kbn/cases-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { CellTooltipWrapper } from '../../shared/components/cell_tooltip_wrapper'; import { CaseDetailsLink } from '../../../../common/components/links'; import { @@ -17,7 +18,6 @@ import { CORRELATIONS_DETAILS_CASES_SECTION_TEST_ID, } from './test_ids'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; const ICON = 'warning'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.test.tsx index 3b73199494187..a97a601f082dd 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.test.tsx @@ -17,7 +17,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_ICON_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { DocumentDetailsContext } from '../../shared/context'; import { mockContextValue } from '../../shared/mocks/mock_context'; import { isSuppressionRuleInGA } from '../../../../../common/detection_engine/utils'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.tsx index 02f00264470e0..efd1628f9d70a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/suppressed_alerts.tsx @@ -11,7 +11,7 @@ import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; import { EuiBetaBadge, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_SECTION_TEST_ID, SUPPRESSED_ALERTS_SECTION_TECHNICAL_PREVIEW_TEST_ID, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/threat_intelligence_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/threat_intelligence_details.tsx index f473ae2c3262b..6ac43fbe5cd31 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/threat_intelligence_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/threat_intelligence_details.tsx @@ -9,6 +9,7 @@ import React, { memo } from 'react'; import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import isEmpty from 'lodash/isEmpty'; import { groupBy } from 'lodash'; +import { FlyoutLoading } from '@kbn/security-solution-common'; import { EnrichmentSection } from './threat_details_view_enrichment_section'; import { ENRICHMENT_TYPES } from '../../../../../common/cti/constants'; import { EnrichmentRangePicker } from './threat_intelligence_view_enrichment_range_picker'; @@ -19,7 +20,6 @@ import { THREAT_INTELLIGENCE_ENRICHMENTS_TEST_ID, THREAT_INTELLIGENCE_MATCHES_TEST_ID, } from './test_ids'; -import { FlyoutLoading } from '../../../shared/components/flyout_loading'; export const THREAT_INTELLIGENCE_TAB_ID = 'threatIntelligence'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx index c1bafab10d9a7..196d9113457a3 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/tour.tsx @@ -10,9 +10,9 @@ import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; import { getField } from '../../shared/utils'; import { EventKind } from '../../shared/constants/event_kinds'; import { useDocumentDetailsContext } from '../../shared/context'; -import { FlyoutTour } from '../../shared/components/flyout_tour'; import { getLeftSectionTourSteps } from '../../shared/utils/tour_step_config'; import { Flyouts } from '../../shared/constants/flyouts'; +import { FlyoutTour } from '../../shared/components/flyout_tour'; /** * Guided tour for the left panel in details flyout diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx index 02764d25b975e..ddf0b51f929b8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.test.tsx @@ -24,7 +24,7 @@ import { USER_DETAILS_RELATED_HOSTS_TABLE_TEST_ID, USER_DETAILS_RELATED_HOSTS_LINK_TEST_ID, } from './test_ids'; -import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '../../../shared/components/test_ids'; +import { EXPANDABLE_PANEL_CONTENT_TEST_ID } from '@kbn/security-solution-common'; import { useRiskScore } from '../../../../entity_analytics/api/hooks/use_risk_score'; import { mockContextValue } from '../../shared/mocks/mock_context'; import { mockFlyoutApi } from '../../shared/mocks/mock_flyout_context'; @@ -34,10 +34,7 @@ import { HOST_PREVIEW_BANNER } from '../../right/components/host_entity_overview import { UserPreviewPanelKey } from '../../../entity_details/user_right'; import { USER_PREVIEW_BANNER } from '../../right/components/user_entity_overview'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../common/hooks/use_experimental_features'); const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx index a3d335b913148..1a93eab1c46e4 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/user_details.tsx @@ -24,8 +24,8 @@ import type { EuiBasicTableColumn } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import type { RelatedHost } from '../../../../../common/search_strategy/security_solution/related_entities/related_hosts'; import type { RiskSeverity } from '../../../../../common/search_strategy'; import { UserOverview } from '../../../../overview/components/user_overview'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/content.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/content.tsx index 53d2efe883397..226765e6c4e37 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/content.tsx @@ -9,9 +9,9 @@ import { useEuiBackgroundColor } from '@elastic/eui'; import type { FC } from 'react'; import React, { useMemo } from 'react'; import { css } from '@emotion/react'; +import { FlyoutBody } from '@kbn/security-solution-common'; import type { LeftPanelPaths } from '.'; import type { LeftPanelTabType } from './tabs'; -import { FlyoutBody } from '../../shared/components/flyout_body'; export interface PanelContentProps { /** diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/header.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/header.tsx index 2b61a97577e06..f276ccca842be 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/header.tsx @@ -9,8 +9,8 @@ import { EuiTab, EuiTabs, useEuiBackgroundColor } from '@elastic/eui'; import type { FC } from 'react'; import React, { memo } from 'react'; import { css } from '@emotion/react'; +import { FlyoutHeader } from '@kbn/security-solution-common'; import type { LeftPanelPaths } from '.'; -import { FlyoutHeader } from '../../shared/components/flyout_header'; import type { LeftPanelTabType } from './tabs'; import { getField } from '../shared/utils'; import { EventKind } from '../shared/constants/event_kinds'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts index 9f5eeb035786c..4e2c1be90b01c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/test_ids.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PREFIX } from '../../shared/test_ids'; +import { PREFIX } from '@kbn/security-solution-common'; export const VISUALIZE_TAB_TEST_ID = `${PREFIX}VisualizeTab` as const; export const INSIGHTS_TAB_TEST_ID = `${PREFIX}InsightsTab` as const; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.test.tsx index d0b46038f44e0..2bf185a44942d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.test.tsx @@ -15,10 +15,7 @@ import { DocumentDetailsContext } from '../shared/context'; import { PreviewPanelFooter } from './footer'; import { PREVIEW_FOOTER_TEST_ID, PREVIEW_FOOTER_LINK_TEST_ID } from './test_ids'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); describe('', () => { beforeAll(() => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx index 0ab0c9f44eb15..404a3debefc2e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/footer.tsx @@ -9,7 +9,7 @@ import { EuiLink, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { FlyoutFooter } from '../../shared/components/flyout_footer'; +import { FlyoutFooter } from '@kbn/security-solution-common'; import { DocumentDetailsRightPanelKey } from '../shared/constants/panel_keys'; import { useDocumentDetailsContext } from '../shared/context'; import { PREVIEW_FOOTER_TEST_ID, PREVIEW_FOOTER_LINK_TEST_ID } from './test_ids'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.test.tsx index c8a00cf0837fa..4949b97e87917 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_description.test.tsx @@ -34,7 +34,7 @@ jest.mock('../../../../common/lib/kibana', () => { }; }); -jest.mock('@kbn/expandable-flyout', () => ({ useExpandableFlyoutApi: jest.fn() })); +jest.mock('@kbn/expandable-flyout'); const ruleUuid = { category: 'kibana', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx index 8d3b0577230a8..a54a3a027fad1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/alert_header_title.tsx @@ -10,6 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel, useEuiTheme, EuiLink } import { css } from '@emotion/css'; import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils'; import { i18n } from '@kbn/i18n'; +import { FlyoutTitle } from '@kbn/security-solution-common'; import { useRuleDetailsLink } from '../../shared/hooks/use_rule_details_link'; import { DocumentStatus } from './status'; import { DocumentSeverity } from './severity'; @@ -20,7 +21,6 @@ import { useDocumentDetailsContext } from '../../shared/context'; import { PreferenceFormattedDate } from '../../../../common/components/formatted_date'; import { FLYOUT_ALERT_HEADER_TITLE_TEST_ID, ALERT_SUMMARY_PANEL_TEST_ID } from './test_ids'; import { Assignees } from './assignees'; -import { FlyoutTitle } from '../../../shared/components/flyout_title'; /** * Alert details flyout right section header diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx index 7dae9400358c5..550bda40e5e68 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.test.tsx @@ -21,7 +21,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser'; import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx index ad85e8e8701e1..f3d99d9144ad2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/analyzer_preview_container.tsx @@ -10,6 +10,7 @@ import { useDispatch } from 'react-redux'; import { TimelineTabs } from '@kbn/securitysolution-data-table'; import { EuiLink, EuiMark } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline'; import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions'; @@ -19,7 +20,6 @@ import { useDocumentDetailsContext } from '../../shared/context'; import { useIsInvestigateInResolverActionEnabled } from '../../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver'; import { AnalyzerPreview } from './analyzer_preview'; import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; const timelineId = 'timeline-1'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx index fb6b2f4edcfb2..f4a97b7deed11 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.test.tsx @@ -39,7 +39,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { useTourContext } from '../../../../common/components/guided_onboarding_tour'; import { AlertsCasesTourSteps } from '../../../../common/components/guided_onboarding_tour/tour_config'; @@ -92,10 +92,7 @@ const flyoutContextValue = { openLeftPanel: jest.fn(), } as unknown as ExpandableFlyoutApi; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../timelines/containers/use_timeline_data_filters', () => ({ useTimelineDataFilters: jest.fn(), diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx index d4e9a6fe58113..058db7c8dc79e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx @@ -12,7 +12,7 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; import { ALERT_RULE_TYPE } from '@kbn/rule-data-utils'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useShowRelatedAlertsBySession } from '../../shared/hooks/use_show_related_alerts_by_session'; import { RelatedAlertsBySession } from './related_alerts_by_session'; import { useShowRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_show_related_alerts_by_same_source_event'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.test.tsx index 92248c6de2828..e4975d3136424 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.test.tsx @@ -24,7 +24,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { useRiskScore } from '../../../../entity_analytics/api/hooks/use_risk_score'; const from = '2022-04-05T12:00:00.000Z'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.tsx index 16fe6cbe1c1e0..60657a1346101 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/entities_overview.tsx @@ -9,8 +9,8 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { INSIGHTS_ENTITIES_TEST_ID } from './test_ids'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import { useDocumentDetailsContext } from '../../shared/context'; import { getField } from '../../shared/utils'; import { HostEntityOverview } from './host_entity_overview'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/event_header_title.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/event_header_title.tsx index 953a2371ffa88..f93b8451c744a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/event_header_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/event_header_title.tsx @@ -9,7 +9,7 @@ import React, { memo, useMemo } from 'react'; import { startCase } from 'lodash'; import { EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { FlyoutTitle } from '../../../shared/components/flyout_title'; +import { FlyoutTitle } from '@kbn/security-solution-common'; import { DocumentSeverity } from './severity'; import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data'; import { useDocumentDetailsContext } from '../../shared/context'; 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 3ebb00c3b7c75..0426d9861b93c 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 @@ -30,10 +30,7 @@ import { USER_PREVIEW_BANNER } from './user_entity_overview'; jest.mock('../../../../management/hooks'); jest.mock('../../../../management/hooks/agents/use_get_agent_status'); -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const useGetAgentStatusMock = useGetAgentStatus as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx index f554f578c86cd..dcaf51761239d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/host_entity_overview.test.tsx @@ -44,10 +44,7 @@ const panelContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, }; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../common/hooks/use_experimental_features'); const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.test.tsx index 74f532fc6809b..f70039230cc45 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/investigation_guide.test.tsx @@ -23,7 +23,7 @@ import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelInvestigationTab } from '../../left'; jest.mock('../../shared/hooks/use_investigation_guide'); -jest.mock('@kbn/expandable-flyout', () => ({ useExpandableFlyoutApi: jest.fn() })); +jest.mock('@kbn/expandable-flyout'); const mockFlyoutContextValue = { openLeftPanel: jest.fn() }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx index 6b3e287d80915..a47ed04c85b5a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.test.tsx @@ -20,7 +20,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_LOADING_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; import { mockContextValue } from '../../shared/mocks/mock_context'; import { type ExpandableFlyoutApi, useExpandableFlyoutApi } from '@kbn/expandable-flyout'; @@ -38,10 +38,7 @@ const flyoutContextValue = { openLeftPanel: jest.fn(), } as unknown as ExpandableFlyoutApi; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const renderPrevalenceOverview = (contextValue: DocumentDetailsContext = mockContextValue) => render( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx index 3776e486b426b..96ee603607742 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/prevalence_overview.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; import { PREVALENCE_TEST_ID } from './test_ids'; import { useDocumentDetailsContext } from '../../shared/context'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx index e69f2d833e949..f4faa9a3d730e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/reason.test.tsx @@ -33,10 +33,7 @@ jest.mock('../../../../common/lib/kibana', () => { }; }); -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const panelContextValue = { eventId: 'event id', diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx index f6f56f1c9cd2a..26bbdcebe22f1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.test.tsx @@ -19,7 +19,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_LINK_TEST_ID, EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; import { mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; jest.mock('../hooks/use_session_preview'); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx index 43a19667d4fb6..aa97b904c1381 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx @@ -11,13 +11,13 @@ import { useDispatch } from 'react-redux'; import { EuiLink, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/css'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useLicense } from '../../../../common/hooks/use_license'; import { SessionPreview } from './session_preview'; import { useSessionPreview } from '../hooks/use_session_preview'; import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline'; import { useDocumentDetailsContext } from '../../shared/context'; import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import { SESSION_PREVIEW_TEST_ID } from './test_ids'; import { useStartTransaction } from '../../../../common/lib/apm/use_start_transaction'; import { setActiveTabTimeline } from '../../../../timelines/store/actions'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx index 2e2ffa99efe42..af92283b781b5 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.test.tsx @@ -23,7 +23,7 @@ import { EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID, EXPANDABLE_PANEL_LOADING_TEST_ID, EXPANDABLE_PANEL_TOGGLE_ICON_TEST_ID, -} from '../../../shared/components/test_ids'; +} from '@kbn/security-solution-common'; jest.mock('../hooks/use_fetch_threat_intelligence'); @@ -48,10 +48,7 @@ const panelContextValue = { dataFormattedForFieldBrowser: [], } as unknown as DocumentDetailsContext; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const renderThreatIntelligenceOverview = (contextValue: DocumentDetailsContext) => ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx index ca47113ad12c3..10b23ecfc2340 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/threat_intelligence_overview.tsx @@ -10,7 +10,7 @@ import React, { useCallback, useMemo } from 'react'; import { EuiFlexGroup } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { useFetchThreatIntelligence } from '../hooks/use_fetch_threat_intelligence'; import { InsightsSummaryRow } from './insights_summary_row'; import { useDocumentDetailsContext } from '../../shared/context'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx index 093a93149285c..839b77766886a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/tour.tsx @@ -10,7 +10,6 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { useWhichFlyout } from '../../shared/hooks/use_which_flyout'; import { Flyouts } from '../../shared/constants/flyouts'; import { useDocumentDetailsContext } from '../../shared/context'; -import { FlyoutTour } from '../../shared/components/flyout_tour'; import { getRightSectionTourSteps, getLeftSectionTourSteps, @@ -24,6 +23,7 @@ import { EventKind } from '../../shared/constants/event_kinds'; import { useTourContext } from '../../../../common/components/guided_onboarding_tour/tour'; import { SecurityStepId } from '../../../../common/components/guided_onboarding_tour/tour_config'; import { useKibana } from '../../../../common/lib/kibana'; +import { FlyoutTour } from '../../shared/components/flyout_tour'; /** * Guided tour for the right panel in details flyout diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx index d1d9651b9d5f1..000da8946ff61 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/user_entity_overview.test.tsx @@ -44,19 +44,11 @@ const panelContextValue = { dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, }; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../common/hooks/use_experimental_features'); const mockUseIsExperimentalFeatureEnabled = useIsExperimentalFeatureEnabled as jest.Mock; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); - const mockUseGlobalTime = jest.fn().mockReturnValue({ from, to }); jest.mock('../../../../common/containers/use_global_time', () => { return { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/content.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/content.tsx index dbc530a4dd3f6..075921de192b8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/content.tsx @@ -7,10 +7,10 @@ import type { FC } from 'react'; import React, { useMemo } from 'react'; +import { FlyoutBody } from '@kbn/security-solution-common'; import { FLYOUT_BODY_TEST_ID } from './test_ids'; import type { RightPanelPaths } from '.'; import type { RightPanelTabType } from './tabs'; -import { FlyoutBody } from '../../shared/components/flyout_body'; export interface PanelContentProps { /** diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/header.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/header.tsx index 3bf4e1a741251..189fe250fbab2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/header.tsx @@ -9,10 +9,9 @@ import type { EuiFlyoutHeader } from '@elastic/eui'; import { EuiSpacer, EuiTab } from '@elastic/eui'; import type { FC } from 'react'; import React, { memo, useMemo } from 'react'; +import { FlyoutHeader, FlyoutHeaderTabs } from '@kbn/security-solution-common'; import type { RightPanelPaths } from '.'; import type { RightPanelTabType } from './tabs'; -import { FlyoutHeader } from '../../shared/components/flyout_header'; -import { FlyoutHeaderTabs } from '../../shared/components/flyout_header_tabs'; import { AlertHeaderTitle } from './components/alert_header_title'; import { EventHeaderTitle } from './components/event_header_title'; import { useDocumentDetailsContext } from '../shared/context'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx index b4f12fbabf94f..79aad96c209db 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/navigation.tsx @@ -8,9 +8,9 @@ import type { FC } from 'react'; import React, { memo, useCallback } from 'react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { FlyoutNavigation } from '@kbn/security-solution-common'; import { useKibana } from '../../../common/lib/kibana'; import { HeaderActions } from './components/header_actions'; -import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; import { DocumentDetailsLeftPanelKey } from '../shared/constants/panel_keys'; import { useDocumentDetailsContext } from '../shared/context'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/footer.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/footer.tsx index ebc204f8cb921..aca0d23027a61 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/footer.tsx @@ -8,8 +8,8 @@ import React, { memo } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FlyoutFooter } from '@kbn/security-solution-common'; import { useRuleOverviewPanelContext } from '../context'; -import { FlyoutFooter } from '../../../shared/components/flyout_footer'; import { RULE_OVERVIEW_FOOTER_TEST_ID, RULE_OVERVIEW_NAVIGATE_TO_RULE_TEST_ID } from './test_ids'; import { useRuleDetailsLink } from '../../shared/hooks/use_rule_details_link'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/rule_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/rule_overview.tsx index 73f9cc12dd053..2e61501241899 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/rule_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/components/rule_overview.tsx @@ -8,6 +8,7 @@ import React, { memo, useState, useEffect } from 'react'; import { EuiText, EuiHorizontalRule, EuiSpacer, EuiPanel } from '@elastic/eui'; import { css } from '@emotion/css'; import { FormattedMessage } from '@kbn/i18n-react'; +import { FlyoutLoading, FlyoutError } from '@kbn/security-solution-common'; import { useRuleOverviewPanelContext } from '../context'; import { ExpandableSection } from '../../right/components/expandable_section'; import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback'; @@ -17,8 +18,6 @@ import { RuleAboutSection } from '../../../../detection_engine/rule_management/c import { RuleScheduleSection } from '../../../../detection_engine/rule_management/components/rule_details/rule_schedule_section'; import { RuleDefinitionSection } from '../../../../detection_engine/rule_management/components/rule_details/rule_definition_section'; import { StepRuleActionsReadOnly } from '../../../../detection_engine/rule_creation/components/step_rule_actions'; -import { FlyoutLoading } from '../../../shared/components/flyout_loading'; -import { FlyoutError } from '../../../shared/components/flyout_error'; import { RULE_OVERVIEW_BODY_TEST_ID, RULE_OVERVIEW_ABOUT_TEST_ID, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/context.tsx index 1b379b3c3ece8..cae182b839e6d 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/context.tsx @@ -6,7 +6,7 @@ */ import React, { createContext, memo, useContext, useMemo } from 'react'; -import { FlyoutError } from '../../shared/components/flyout_error'; +import { FlyoutError } from '@kbn/security-solution-common'; import type { RuleOverviewPanelProps } from '.'; export interface RuleOverviewPanelContext { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/index.tsx index 504be510a09f7..b978a1697bbd5 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/rule_overview/index.tsx @@ -7,7 +7,7 @@ import React, { memo } from 'react'; import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; -import { FlyoutBody } from '../../shared/components/flyout_body'; +import { FlyoutBody } from '@kbn/security-solution-common'; import type { DocumentDetailsRuleOverviewPanelKey } from '../shared/constants/panel_keys'; import { RuleOverview } from './components/rule_overview'; import { RuleFooter } from './components/footer'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/context.tsx index 12e2ad4f2a0b6..f2c5d8bfa530f 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/context.tsx @@ -9,9 +9,8 @@ import type { BrowserFields, TimelineEventsDetailsItem } from '@kbn/timelines-pl import React, { createContext, memo, useContext, useMemo } from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; import { TableId } from '@kbn/securitysolution-data-table'; +import { FlyoutError, FlyoutLoading } from '@kbn/security-solution-common/src/flyout'; import { useEventDetails } from './hooks/use_event_details'; -import { FlyoutError } from '../../shared/components/flyout_error'; -import { FlyoutLoading } from '../../shared/components/flyout_loading'; import type { SearchHit } from '../../../../common/search_strategy'; import { useBasicDataFromDetailsData } from './hooks/use_basic_data_from_details_data'; import type { DocumentDetailsProps } from './types'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/tour_step_config.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/tour_step_config.tsx index 7b850cca82450..3f597e47c770c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/tour_step_config.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/tour_step_config.tsx @@ -9,7 +9,7 @@ import { EuiText, EuiCode, type EuiTourStepProps } from '@elastic/eui'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { HEADER_NAVIGATION_BUTTON_TEST_ID } from '../../../shared/components/test_ids'; +import { HEADER_NAVIGATION_BUTTON_TEST_ID } from '@kbn/security-solution-common'; import { OVERVIEW_TAB_LABEL_TEST_ID } from '../../right/test_ids'; import { RULE_SUMMARY_BUTTON_TEST_ID } from '../../right/components/test_ids'; import { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.test.tsx index 8bfc575e5b573..403e9cf1c0ed0 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.test.tsx @@ -12,10 +12,7 @@ import { mockFlyoutApi } from '../../document_details/shared/mocks/mock_flyout_c import type { HostPreviewPanelFooterProps } from './footer'; import { HostPreviewPanelFooter } from './footer'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const mockProps: HostPreviewPanelFooterProps = { hostName: 'test', diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.tsx index e550da28b532a..3ea6d7a5e0438 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_preview/footer.tsx @@ -9,7 +9,7 @@ import { EuiLink, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { FlyoutFooter } from '../../shared/components/flyout_footer'; +import { FlyoutFooter } from '@kbn/security-solution-common'; import { HostPanelKey } from '../host_right'; export interface HostPreviewPanelFooterProps { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx index af3eae38fc1f8..27e824d39c913 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/content.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { EuiHorizontalRule } from '@elastic/eui'; +import { FlyoutBody } from '@kbn/security-solution-common'; import { AssetCriticalityAccordion } from '../../../entity_analytics/components/asset_criticality/asset_criticality_selector'; import { FlyoutRiskSummary } from '../../../entity_analytics/components/risk_summary_flyout/risk_summary'; import type { RiskScoreState } from '../../../entity_analytics/api/hooks/use_risk_score'; import type { RiskScoreEntity, HostItem } from '../../../../common/search_strategy'; -import { FlyoutBody } from '../../shared/components/flyout_body'; import { ObservedEntity } from '../shared/components/observed_entity'; import { HOST_PANEL_OBSERVED_HOST_QUERY_ID, HOST_PANEL_RISK_SCORE_QUERY_ID } from '.'; import type { ObservedEntityData } from '../shared/components/observed_entity/types'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx index b5df2f81d1b0a..706790770eb6c 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/header.tsx @@ -9,12 +9,11 @@ import { EuiSpacer, EuiBadge, EuiText, EuiFlexItem, EuiFlexGroup } from '@elasti import { FormattedMessage } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; import { SecurityPageName } from '@kbn/security-solution-navigation'; +import { FlyoutHeader, FlyoutTitle } from '@kbn/security-solution-common'; import type { HostItem } from '../../../../common/search_strategy'; import { getHostDetailsUrl } from '../../../common/components/link_to'; import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; -import { FlyoutHeader } from '../../shared/components/flyout_header'; -import { FlyoutTitle } from '../../shared/components/flyout_title'; import type { ObservedEntityData } from '../shared/components/observed_entity/types'; interface HostPanelHeaderProps { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx index 798bff18b9c16..4799c396a7be3 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/host_right/index.tsx @@ -9,6 +9,7 @@ import React, { useCallback, useMemo } from 'react'; import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { FlyoutLoading, FlyoutNavigation } from '@kbn/security-solution-common'; import { useRefetchQueryById } from '../../../entity_analytics/api/hooks/use_refetch_query_by_id'; import { RISK_INPUTS_TAB_QUERY_ID } from '../../../entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab'; import type { Refetch } from '../../../common/types'; @@ -21,8 +22,6 @@ import { useGlobalTime } from '../../../common/containers/use_global_time'; import type { HostItem } from '../../../../common/search_strategy'; import { buildHostNamesFilter } from '../../../../common/search_strategy'; import { RiskScoreEntity } from '../../../../common/entity_analytics/risk_engine'; -import { FlyoutLoading } from '../../shared/components/flyout_loading'; -import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; import { HostPanelContent } from './content'; import { HostPanelHeader } from './header'; import { AnomalyTableProvider } from '../../../common/components/ml/anomaly/anomaly_table_provider'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx index 5a66a5b305611..f52480285a567 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_content.tsx @@ -9,7 +9,7 @@ import { useEuiBackgroundColor } from '@elastic/eui'; import type { VFC } from 'react'; import React, { useMemo } from 'react'; import { css } from '@emotion/react'; -import { FlyoutBody } from '../../../../shared/components/flyout_body'; +import { FlyoutBody } from '@kbn/security-solution-common'; import type { EntityDetailsLeftPanelTab, LeftPanelTabsType } from './left_panel_header'; export interface PanelContentProps { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx index ea62ce25f3ca4..7a537d64aa755 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/shared/components/left_panel/left_panel_header.tsx @@ -9,7 +9,7 @@ import { EuiTab, EuiTabs, useEuiBackgroundColor } from '@elastic/eui'; import type { ReactElement, VFC } from 'react'; import React, { memo } from 'react'; import { css } from '@emotion/react'; -import { FlyoutHeader } from '../../../../shared/components/flyout_header'; +import { FlyoutHeader } from '@kbn/security-solution-common'; export type LeftPanelTabsType = Array<{ id: EntityDetailsLeftPanelTab; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx index 2ba1e274e0c5b..a04bd739eb299 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/index.tsx @@ -8,9 +8,9 @@ import React, { useMemo } from 'react'; import type { FlyoutPanelProps, PanelPath } from '@kbn/expandable-flyout'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { FlyoutLoading } from '@kbn/security-solution-common'; import { useManagedUser } from '../shared/hooks/use_managed_user'; import { useTabs } from './tabs'; -import { FlyoutLoading } from '../../shared/components/flyout_loading'; import type { EntityDetailsLeftPanelTab, LeftPanelTabsType, diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs/asset_document.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs/asset_document.tsx index 3aa4a72ffe898..31053cf88d931 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs/asset_document.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_details_left/tabs/asset_document.tsx @@ -12,10 +12,10 @@ import { FormattedMessage } from '@kbn/i18n-react'; import type { EuiButtonGroupOptionProps } from '@elastic/eui'; import { EuiButtonGroup } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FlyoutBody } from '@kbn/security-solution-common'; import { JsonTab } from '../../../document_details/right/tabs/json_tab'; import { TableTab } from '../../../document_details/right/tabs/table_tab'; import { FLYOUT_BODY_TEST_ID, JSON_TAB_TEST_ID, TABLE_TAB_TEST_ID } from './test_ids'; -import { FlyoutBody } from '../../../shared/components/flyout_body'; export type RightPanelPaths = 'overview' | 'table' | 'json'; export interface AssetDocumentPanelProps extends FlyoutPanelProps { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.test.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.test.tsx index 52fcee31028e1..93d14644476ef 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.test.tsx @@ -12,10 +12,7 @@ import { mockFlyoutApi } from '../../document_details/shared/mocks/mock_flyout_c import type { UserPreviewPanelFooterProps } from './footer'; import { UserPreviewPanelFooter } from './footer'; -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, -})); +jest.mock('@kbn/expandable-flyout'); const mockProps: UserPreviewPanelFooterProps = { userName: 'test', diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.tsx index 7f55feb7a347c..6921d1a73d4e2 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_preview/footer.tsx @@ -9,7 +9,7 @@ import { EuiLink, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React, { useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -import { FlyoutFooter } from '../../shared/components/flyout_footer'; +import { FlyoutFooter } from '@kbn/security-solution-common'; import { UserPanelKey } from '../user_right'; export interface UserPreviewPanelFooterProps { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/components/managed_user_accordion.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/components/managed_user_accordion.tsx index 8d9007713549e..84f6c96cb772b 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/components/managed_user_accordion.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/components/managed_user_accordion.tsx @@ -11,13 +11,14 @@ import React from 'react'; import { css } from '@emotion/react'; import { FormattedMessage } from '@kbn/i18n-react'; import { get } from 'lodash/fp'; +import { ExpandablePanel } from '@kbn/security-solution-common'; import { EntityDetailsLeftPanelTab } from '../../shared/components/left_panel/left_panel_header'; -import { ExpandablePanel } from '../../../shared/components/expandable_panel'; import type { ManagedUserFields } from '../../../../../common/search_strategy/security_solution/users/managed_details'; import { FormattedRelativePreferenceDate } from '../../../../common/components/formatted_date'; import { ONE_WEEK_IN_HOURS } from '../../shared/constants'; import { UserAssetTableType } from '../../../../explore/users/store/model'; + interface ManagedUserAccordionProps { children: React.ReactNode; title: string; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx index d06309ea09d02..26945a12f8bd6 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/content.tsx @@ -8,6 +8,7 @@ import { EuiHorizontalRule } from '@elastic/eui'; import React from 'react'; +import { FlyoutBody } from '@kbn/security-solution-common'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; import { AssetCriticalityAccordion } from '../../../entity_analytics/components/asset_criticality/asset_criticality_selector'; @@ -18,7 +19,6 @@ import { ManagedUser } from './components/managed_user'; import type { ManagedUserData } from './types'; import type { RiskScoreEntity, UserItem } from '../../../../common/search_strategy'; import { USER_PANEL_RISK_SCORE_QUERY_ID } from '.'; -import { FlyoutBody } from '../../shared/components/flyout_body'; import { ObservedEntity } from '../shared/components/observed_entity'; import type { ObservedEntityData } from '../shared/components/observed_entity/types'; import { useObservedUserItems } from './hooks/use_observed_user_items'; diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx index e141779b559cf..8fb54478b3c4f 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/header.tsx @@ -10,6 +10,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React, { useMemo } from 'react'; import { max } from 'lodash/fp'; import { SecurityPageName } from '@kbn/security-solution-navigation'; +import { FlyoutHeader, FlyoutTitle } from '@kbn/security-solution-common'; import type { UserItem } from '../../../../common/search_strategy'; import { ManagedUserDatasetKey } from '../../../../common/search_strategy/security_solution/users/managed_details'; import { getUsersDetailsUrl } from '../../../common/components/link_to/redirect_to_users'; @@ -17,8 +18,6 @@ import type { ManagedUserData } from './types'; import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; import { PreferenceFormattedDate } from '../../../common/components/formatted_date'; -import { FlyoutHeader } from '../../shared/components/flyout_header'; -import { FlyoutTitle } from '../../shared/components/flyout_title'; import type { ObservedEntityData } from '../shared/components/observed_entity/types'; interface UserPanelHeaderProps { diff --git a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx index 6addcd92b6602..15ebee33010a0 100644 --- a/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/entity_details/user_right/index.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useMemo } from 'react'; import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { FlyoutLoading, FlyoutNavigation } from '@kbn/security-solution-common/src/flyout'; import { useRefetchQueryById } from '../../../entity_analytics/api/hooks/use_refetch_query_by_id'; import type { Refetch } from '../../../common/types'; import { RISK_INPUTS_TAB_QUERY_ID } from '../../../entity_analytics/components/entity_details_flyout/tabs/risk_inputs/risk_inputs_tab'; @@ -23,8 +24,6 @@ import { useGlobalTime } from '../../../common/containers/use_global_time'; import { AnomalyTableProvider } from '../../../common/components/ml/anomaly/anomaly_table_provider'; import { buildUserNamesFilter } from '../../../../common/search_strategy'; import { RiskScoreEntity } from '../../../../common/entity_analytics/risk_engine'; -import { FlyoutLoading } from '../../shared/components/flyout_loading'; -import { FlyoutNavigation } from '../../shared/components/flyout_navigation'; import { UserPanelContent } from './content'; import { UserPanelHeader } from './header'; import { UserDetailsPanelKey } from '../user_details_left'; diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/content.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/content.tsx index 8c9aa355ed43a..3634f73ef5a7f 100644 --- a/x-pack/plugins/security_solution/public/flyout/network_details/content.tsx +++ b/x-pack/plugins/security_solution/public/flyout/network_details/content.tsx @@ -8,8 +8,8 @@ import type { FC } from 'react'; import React, { memo } from 'react'; import { EuiSpacer } from '@elastic/eui'; +import { FlyoutBody } from '@kbn/security-solution-common'; import { NetworkDetails } from './components/network_details'; -import { FlyoutBody } from '../shared/components/flyout_body'; import type { FlowTargetSourceDest } from '../../../common/search_strategy'; export interface PanelContentProps { diff --git a/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx b/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx index 8ffceb345b1e0..1ef47c00689d9 100644 --- a/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx +++ b/x-pack/plugins/security_solution/public/flyout/network_details/header.tsx @@ -9,11 +9,10 @@ import type { FC } from 'react'; import React, { memo, useMemo } from 'react'; import type { EuiFlyoutHeader } from '@elastic/eui'; import { SecurityPageName } from '@kbn/deeplinks-security'; +import { FlyoutHeader, FlyoutTitle } from '@kbn/security-solution-common'; import { getNetworkDetailsUrl } from '../../common/components/link_to'; import { SecuritySolutionLinkAnchor } from '../../common/components/links'; import type { FlowTargetSourceDest } from '../../../common/search_strategy'; -import { FlyoutHeader } from '../shared/components/flyout_header'; -import { FlyoutTitle } from '../shared/components/flyout_title'; import { encodeIpv6 } from '../../common/lib/helpers'; export interface PanelHeaderProps extends React.ComponentProps { diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/alert_preview_button.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/alert_preview_button.test.tsx index f478812f96f93..1d9358cb1bb31 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/alert_preview_button.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/alert_preview_button.test.tsx @@ -11,11 +11,14 @@ import React from 'react'; import { AlertPreviewButton } from './alert_preview_button'; import { DocumentDetailsPreviewPanelKey } from '../../document_details/shared/constants/panel_keys'; import { ALERT_PREVIEW_BANNER } from '../../document_details/preview/constants'; +import { createExpandableFlyoutApiMock } from '../../../common/mock/expandable_flyout'; const mockOpenPreviewPanel = jest.fn(); +const mockExpandableFlyoutApi = createExpandableFlyoutApiMock(); jest.mock('@kbn/expandable-flyout', () => { return { useExpandableFlyoutApi: () => ({ + ...mockExpandableFlyoutApi, openPreviewPanel: mockOpenPreviewPanel, }), }; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.test.tsx index e342cbd388ad6..1d9be2b33ef7e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.test.tsx @@ -61,4 +61,16 @@ describe('Policy form SettingCard component', () => { expect(renderResult.getByTestId('test-rightCornerContainer')).not.toBeEmptyDOMElement(); expect(renderResult.getByTestId('test-rightContent')); }); + + it('should show right corner content in viewport width greater than 1600px', () => { + // Set the viewport above xxl breakpoint + window.innerWidth = 1601; + window.dispatchEvent(new Event('resize')); + + formProps.rightCorner =
{'foo'}
; + render(); + + const rightContent = renderResult.getByTestId('test-rightContent'); + expect(rightContent).toBeVisible(); + }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.tsx index 646c807e8376b..d460eaa068e38 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_settings_form/components/setting_card.tsx @@ -127,7 +127,7 @@ export const SettingCard: FC = memo( )} - + diff --git a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx index 8a4f911468e4a..04cfeaff92d0b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.test.tsx @@ -13,6 +13,8 @@ import { TestProviders } from '../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../common/types/timeline'; import { StatefulEventContext } from '../../../common/components/events_viewer/stateful_event_context'; import { NetworkPanelKey } from '../../../flyout/network_details'; +import { createExpandableFlyoutApiMock } from '../../../common/mock/expandable_flyout'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; jest.mock('react-redux', () => { const origin = jest.requireActual('react-redux'); @@ -46,13 +48,15 @@ jest.mock('../../../common/components/drag_and_drop/draggable_wrapper', () => { jest.mock('../../store'); const mockOpenFlyout = jest.fn(); -jest.mock('@kbn/expandable-flyout', () => ({ - useExpandableFlyoutApi: () => ({ - openFlyout: mockOpenFlyout, - }), -})); +jest.mock('@kbn/expandable-flyout'); describe('FormattedIp', () => { + beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue({ + ...createExpandableFlyoutApiMock(), + openFlyout: mockOpenFlyout, + }); + }); const props = { value: '192.168.1.1', contextId: 'test-context-id', diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx index 98d3ea8f507bb..9674b9146ecb0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx @@ -39,6 +39,8 @@ import type { } from '@hello-pangea/dnd'; import { DocumentDetailsRightPanelKey } from '../../../../flyout/document_details/shared/constants/panel_keys'; import { createTelemetryServiceMock } from '../../../../common/lib/telemetry/telemetry_service.mock'; +import { createExpandableFlyoutApiMock } from '../../../../common/mock/expandable_flyout'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; jest.mock('../../../../common/hooks/use_app_toasts'); jest.mock('../../../../common/components/guided_onboarding_tour/tour_step'); @@ -99,11 +101,7 @@ jest.mock('react-redux', () => { }); const mockOpenFlyout = jest.fn(); -jest.mock('@kbn/expandable-flyout', () => { - return { - useExpandableFlyoutApi: () => ({ openFlyout: mockOpenFlyout }), - }; -}); +jest.mock('@kbn/expandable-flyout'); const mockedTelemetry = createTelemetryServiceMock(); @@ -236,6 +234,11 @@ describe('Body', () => { let appToastsMock: jest.Mocked>; beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue({ + ...createExpandableFlyoutApiMock(), + openFlyout: mockOpenFlyout, + }); + mockUseCurrentUser.mockReturnValue({ username: 'test-username' }); mockUseKibana.mockReturnValue({ services: { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx index d00ad83b9b556..52344857a07c1 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { type PropsWithChildren } from 'react'; +import React from 'react'; import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; @@ -14,18 +14,13 @@ import { TimelineId, TimelineTabs } from '../../../../../../common/types/timelin import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; import { TableId } from '@kbn/securitysolution-data-table'; +import { createExpandableFlyoutApiMock } from '../../../../../common/mock/expandable_flyout'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; const mockedTelemetry = createTelemetryServiceMock(); const mockOpenRightPanel = jest.fn(); -jest.mock('@kbn/expandable-flyout', () => { - return { - useExpandableFlyoutApi: () => ({ - openRightPanel: mockOpenRightPanel, - }), - TestProvider: ({ children }: PropsWithChildren<{}>) => <>{children}, - }; -}); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../../common/lib/kibana/kibana_react', () => { return { @@ -46,6 +41,13 @@ jest.mock('../../../../../common/components/draggables', () => ({ })); describe('HostName', () => { + beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue({ + ...createExpandableFlyoutApiMock(), + openRightPanel: mockOpenRightPanel, + }); + }); + afterEach(() => { jest.clearAllMocks(); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx index 471d43dcf8462..6c3dffc58ce25 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { type PropsWithChildren } from 'react'; +import React from 'react'; import { mount } from 'enzyme'; import { waitFor } from '@testing-library/react'; @@ -14,18 +14,13 @@ import { UserName } from './user_name'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; import { TableId } from '@kbn/securitysolution-data-table'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { createExpandableFlyoutApiMock } from '../../../../../common/mock/expandable_flyout'; const mockedTelemetry = createTelemetryServiceMock(); const mockOpenRightPanel = jest.fn(); -jest.mock('@kbn/expandable-flyout', () => { - return { - useExpandableFlyoutApi: () => ({ - openRightPanel: mockOpenRightPanel, - }), - TestProvider: ({ children }: PropsWithChildren<{}>) => <>{children}, - }; -}); +jest.mock('@kbn/expandable-flyout'); jest.mock('../../../../../common/lib/kibana/kibana_react', () => { return { @@ -46,6 +41,12 @@ jest.mock('../../../../../common/components/draggables', () => ({ })); describe('UserName', () => { + beforeEach(() => { + jest.mocked(useExpandableFlyoutApi).mockReturnValue({ + ...createExpandableFlyoutApiMock(), + openRightPanel: mockOpenRightPanel, + }); + }); afterEach(() => { jest.clearAllMocks(); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx index 8b7b3742f0f27..973e0626aacc2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/query_tab_unified_components.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import type { ComponentProps, FunctionComponent, PropsWithChildren } from 'react'; +import type { ComponentProps, FunctionComponent } from 'react'; import React, { useEffect } from 'react'; import QueryTabContent from '.'; import { defaultRowRenderers } from '../../body/renderers'; @@ -35,6 +35,8 @@ import { defaultColumnHeaderType } from '../../body/column_headers/default_heade import { useUserPrivileges } from '../../../../../common/components/user_privileges'; import { getEndpointPrivilegesInitialStateMock } from '../../../../../common/components/user_privileges/endpoint/mocks'; import * as timelineActions from '../../../../store/actions'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { createExpandableFlyoutApiMock } from '../../../../../common/mock/expandable_flyout'; jest.mock('../../../../../common/components/user_privileges'); @@ -87,15 +89,7 @@ jest.mock(`@elastic/ebt/client`); const mockOpenFlyout = jest.fn(); const mockCloseFlyout = jest.fn(); -jest.mock('@kbn/expandable-flyout', () => { - return { - useExpandableFlyoutApi: () => ({ - openFlyout: mockOpenFlyout, - closeFlyout: mockCloseFlyout, - }), - TestProvider: ({ children }: PropsWithChildren<{}>) => <>{children}, - }; -}); +jest.mock('@kbn/expandable-flyout'); const TestComponent = (props: Partial>) => { const testComponentDefaultProps: ComponentProps = { @@ -162,6 +156,13 @@ let useTimelineEventsMock = jest.fn(); describe('query tab with unified timeline', () => { beforeAll(() => { // https://github.com/atlassian/react-beautiful-dnd/blob/4721a518356f72f1dac45b5fd4ee9d466aa2996b/docs/guides/setup-problem-detection-and-error-recovery.md#disable-logging + + jest.mocked(useExpandableFlyoutApi).mockImplementation(() => ({ + ...createExpandableFlyoutApiMock(), + openFlyout: mockOpenFlyout, + closeFlyout: mockCloseFlyout, + })); + Object.defineProperty(window, '__@hello-pangea/dnd-disable-dev-warnings', { get() { return true; diff --git a/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts b/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts index dc9290e5a4b9a..1987a019f8887 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/common/response_actions.ts @@ -10,7 +10,7 @@ import type { Client } from '@elastic/elasticsearch'; import type { SearchHit } from '@elastic/elasticsearch/lib/api/types'; import { basename } from 'path'; -import * as cborx from 'cbor-x'; +import { encode } from '@kbn/cbor'; import { AGENT_ACTIONS_INDEX, AGENT_ACTIONS_RESULTS_INDEX } from '@kbn/fleet-plugin/common'; import { FleetActionGenerator } from '../../../common/endpoint/data_generators/fleet_action_generator'; import { EndpointActionGenerator } from '../../../common/endpoint/data_generators/endpoint_action_generator'; @@ -236,7 +236,7 @@ export const sendEndpointActionResponse = async ( { index: FILE_STORAGE_DATA_INDEX, id: `${fileMeta._id}.0`, - document: cborx.encode({ + document: encode({ bid: fileMeta._id, last: true, '@timestamp': new Date().toISOString(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts index 381a2dce89df8..2737c4f2d8085 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.test.ts @@ -36,13 +36,25 @@ describe('duplicateRule', () => { meta: undefined, maxSignals: 100, responseActions: [], - relatedIntegrations: [], - requiredFields: [], + relatedIntegrations: [ + { + package: 'aws', + version: '~1.2.3', + integration: 'route53', + }, + ], + requiredFields: [ + { + name: 'event.action', + type: 'keyword', + ecs: true, + }, + ], riskScore: 42, riskScoreMapping: [], severity: 'low', severityMapping: [], - setup: 'Some setup guide.', + setup: `## Config\n\nThe 'Audit Detailed File Share' audit policy must be configured...`, threat: [], to: 'now', references: [], @@ -94,106 +106,23 @@ describe('duplicateRule', () => { jest.clearAllMocks(); }); - it('returns an object with fields copied from a given rule', async () => { - const rule = createTestRule(); - const result = await duplicateRule({ - rule, - }); - - expect(result).toEqual({ - name: expect.anything(), // covered in a separate test - params: { - ...rule.params, - ruleSource: { - type: 'internal', - }, - ruleId: expect.anything(), // covered in a separate test - }, - tags: rule.tags, - alertTypeId: rule.alertTypeId, - consumer: rule.consumer, - schedule: rule.schedule, - actions: rule.actions, - systemActions: rule.actions, - enabled: false, // covered in a separate test - }); - }); - - it('appends [Duplicate] to the name', async () => { - const rule = createTestRule(); - rule.name = 'PowerShell Keylogging Script'; - const result = await duplicateRule({ - rule, - }); - - expect(result).toEqual( - expect.objectContaining({ - name: 'PowerShell Keylogging Script [Duplicate]', - }) - ); - }); - - it('generates a new ruleId', async () => { - const rule = createTestRule(); - const result = await duplicateRule({ - rule, - }); - - expect(result).toEqual( - expect.objectContaining({ - params: expect.objectContaining({ - ruleId: 'new ruleId', - }), - }) - ); - }); - - it('makes sure the duplicated rule is disabled', async () => { - const rule = createTestRule(); - rule.enabled = true; - const result = await duplicateRule({ - rule, - }); - - expect(result).toEqual( - expect.objectContaining({ - enabled: false, - }) - ); - }); - - describe('when duplicating a prebuilt (immutable) rule', () => { - const createPrebuiltRule = () => { + describe('when duplicating any kind of rule', () => { + it('appends [Duplicate] to the name', async () => { const rule = createTestRule(); - rule.params.immutable = true; - return rule; - }; - - it('transforms it to a custom (mutable) rule', async () => { - const rule = createPrebuiltRule(); + rule.name = 'PowerShell Keylogging Script'; const result = await duplicateRule({ rule, }); expect(result).toEqual( expect.objectContaining({ - params: expect.objectContaining({ - immutable: false, - }), + name: 'PowerShell Keylogging Script [Duplicate]', }) ); }); - it('resets related integrations to an empty array', async () => { - const rule = createPrebuiltRule(); - rule.params.relatedIntegrations = [ - { - package: 'aws', - version: '~1.2.3', - integration: 'route53', - }, - ]; - + it('generates a new ruleId', async () => { + const rule = createTestRule(); const result = await duplicateRule({ rule, }); @@ -201,45 +130,40 @@ describe('duplicateRule', () => { expect(result).toEqual( expect.objectContaining({ params: expect.objectContaining({ - relatedIntegrations: [], + ruleId: 'new ruleId', }), }) ); }); - it('resets required fields to an empty array', async () => { - const rule = createPrebuiltRule(); - rule.params.requiredFields = [ - { - name: 'event.action', - type: 'keyword', - ecs: true, - }, - ]; - + it('makes sure the duplicated rule is disabled', async () => { + const rule = createTestRule(); + rule.enabled = true; const result = await duplicateRule({ rule, }); expect(result).toEqual( expect.objectContaining({ - params: expect.objectContaining({ - requiredFields: [], - }), + enabled: false, }) ); }); }); - describe('when duplicating a custom (mutable) rule', () => { - const createCustomRule = () => { + describe('when duplicating a prebuilt rule', () => { + const createPrebuiltRule = () => { const rule = createTestRule(); - rule.params.immutable = false; + rule.params.immutable = true; + rule.params.ruleSource = { + type: 'external', + isCustomized: false, + }; return rule; }; - it('keeps it custom', async () => { - const rule = createCustomRule(); + it('transforms it to a custom rule', async () => { + const rule = createPrebuiltRule(); const result = await duplicateRule({ rule, }); @@ -248,44 +172,51 @@ describe('duplicateRule', () => { expect.objectContaining({ params: expect.objectContaining({ immutable: false, + ruleSource: { + type: 'internal', + }, }), }) ); }); - it('copies related integrations as is', async () => { - const rule = createCustomRule(); - rule.params.relatedIntegrations = [ - { - package: 'aws', - version: '~1.2.3', - integration: 'route53', - }, - ]; - + it('copies fields from the original rule', async () => { + const rule = createPrebuiltRule(); const result = await duplicateRule({ rule, }); - expect(result).toEqual( - expect.objectContaining({ - params: expect.objectContaining({ - relatedIntegrations: rule.params.relatedIntegrations, - }), - }) - ); + expect(result).toEqual({ + name: expect.anything(), // covered in a separate test + params: { + ...rule.params, + ruleId: expect.anything(), // covered in a separate test + immutable: expect.anything(), // covered in a separate test + ruleSource: expect.anything(), // covered in a separate test + }, + tags: rule.tags, + alertTypeId: rule.alertTypeId, + consumer: rule.consumer, + schedule: rule.schedule, + actions: rule.actions, + systemActions: rule.actions, + enabled: false, // covered in a separate test + }); }); + }); - it('copies required fields as is', async () => { - const rule = createCustomRule(); - rule.params.requiredFields = [ - { - name: 'event.action', - type: 'keyword', - ecs: true, - }, - ]; + describe('when duplicating a custom rule', () => { + const createCustomRule = () => { + const rule = createTestRule(); + rule.params.immutable = false; + rule.params.ruleSource = { + type: 'internal', + }; + return rule; + }; + it('keeps it custom', async () => { + const rule = createCustomRule(); const result = await duplicateRule({ rule, }); @@ -293,26 +224,35 @@ describe('duplicateRule', () => { expect(result).toEqual( expect.objectContaining({ params: expect.objectContaining({ - requiredFields: rule.params.requiredFields, + immutable: false, + ruleSource: { + type: 'internal', + }, }), }) ); }); - it('copies setup guide as is', async () => { + it('copies fields from the original rule', async () => { const rule = createCustomRule(); - rule.params.setup = `## Config\n\nThe 'Audit Detailed File Share' audit policy must be configured...`; const result = await duplicateRule({ rule, }); - expect(result).toEqual( - expect.objectContaining({ - params: expect.objectContaining({ - setup: rule.params.setup, - }), - }) - ); + expect(result).toEqual({ + name: expect.anything(), // covered in a separate test + params: { + ...rule.params, + ruleId: expect.anything(), // covered in a separate test + }, + tags: rule.tags, + alertTypeId: rule.alertTypeId, + consumer: rule.consumer, + schedule: rule.schedule, + actions: rule.actions, + systemActions: rule.actions, + enabled: false, // covered in a separate test + }); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts index 1324e2adb01ab..58c214950728d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/actions/duplicate_rule.ts @@ -27,18 +27,18 @@ interface DuplicateRuleParams { export const duplicateRule = async ({ rule }: DuplicateRuleParams): Promise => { // Generate a new static ruleId - const ruleId = uuidv4(); - - // If it's a prebuilt rule, reset Related Integrations, Required Fields and Setup Guide. - // We do this because for now we don't allow the users to edit these fields for custom rules. - const isPrebuilt = rule.params.immutable; - const relatedIntegrations = isPrebuilt ? [] : rule.params.relatedIntegrations; - const requiredFields = isPrebuilt ? [] : rule.params.requiredFields; - - const actions = transformToActionFrequency(rule.actions, rule.throttle); + const ruleId: InternalRuleCreate['params']['ruleId'] = uuidv4(); // Duplicated rules are always considered custom rules - const immutable = false; + const immutable: InternalRuleCreate['params']['immutable'] = false; + const ruleSource: InternalRuleCreate['params']['ruleSource'] = { + type: 'internal', + }; + + const actions: InternalRuleCreate['actions'] = transformToActionFrequency( + rule.actions, + rule.throttle + ); return { name: `${rule.name} [${DUPLICATE_TITLE}]`, @@ -47,13 +47,9 @@ export const duplicateRule = async ({ rule }: DuplicateRuleParams): Promise { - for (const useDataStreamForAlerts of [false, true]) { - const label = useDataStreamForAlerts ? 'data streams' : 'aliases'; + describe.each(['data streams', 'aliases'])(`using %s for alert indices`, () => { + let riskEngineDataClient: RiskEngineDataClient; + let mockSavedObjectClient: ReturnType; + let logger: ReturnType; - describe(`using ${label} for alert indices`, () => { - let riskEngineDataClient: RiskEngineDataClient; - let mockSavedObjectClient: ReturnType; - let logger: ReturnType; + beforeEach(() => { const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + logger = loggingSystemMock.createLogger(); + mockSavedObjectClient = savedObjectsClientMock.create(); + const options = { + logger, + kibanaVersion: '8.9.0', + esClient, + soClient: mockSavedObjectClient, + namespace: 'default', + auditLogger: undefined, + }; + riskEngineDataClient = new RiskEngineDataClient(options); + }); - beforeEach(() => { - logger = loggingSystemMock.createLogger(); - mockSavedObjectClient = savedObjectsClientMock.create(); - const options = { - logger, - kibanaVersion: '8.9.0', - esClient, - soClient: mockSavedObjectClient, - namespace: 'default', - auditLogger: undefined, - }; - riskEngineDataClient = new RiskEngineDataClient(options); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - afterEach(() => { - jest.clearAllMocks(); - }); + afterAll(() => { + jest.restoreAllMocks(); + }); - describe('#getConfiguration', () => { - it('retrieves configuration from the saved object', async () => { - mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); + describe('#getConfiguration', () => { + it('retrieves configuration from the saved object', async () => { + mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); - const configuration = await riskEngineDataClient.getConfiguration(); + const configuration = await riskEngineDataClient.getConfiguration(); - expect(mockSavedObjectClient.find).toHaveBeenCalledTimes(1); + expect(mockSavedObjectClient.find).toHaveBeenCalledTimes(1); - expect(configuration).toEqual({ - enabled: false, - }); + expect(configuration).toEqual({ + enabled: false, }); }); + }); - describe('enableRiskEngine', () => { - let mockTaskManagerStart: ReturnType; + describe('enableRiskEngine', () => { + let mockTaskManagerStart: ReturnType; - beforeEach(() => { - mockSavedObjectClient.find.mockResolvedValue(getSavedObjectConfiguration()); - mockTaskManagerStart = taskManagerMock.createStart(); + beforeEach(() => { + mockSavedObjectClient.find.mockResolvedValue(getSavedObjectConfiguration()); + mockTaskManagerStart = taskManagerMock.createStart(); + }); + + it('returns an error if saved object does not exist', async () => { + mockSavedObjectClient.find.mockResolvedValue({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [], }); - it('returns an error if saved object does not exist', async () => { - mockSavedObjectClient.find.mockResolvedValue({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [], - }); + await expect( + riskEngineDataClient.enableRiskEngine({ taskManager: mockTaskManagerStart }) + ).rejects.toThrow('Risk engine configuration not found'); + }); - await expect( - riskEngineDataClient.enableRiskEngine({ taskManager: mockTaskManagerStart }) - ).rejects.toThrow('Risk engine configuration not found'); + it('should update saved object attribute', async () => { + await riskEngineDataClient.enableRiskEngine({ taskManager: mockTaskManagerStart }); + + expect(mockSavedObjectClient.update).toHaveBeenCalledWith( + 'risk-engine-configuration', + 'de8ca330-2d26-11ee-bc86-f95bf6192ee6', + { + enabled: true, + }, + { + refresh: 'wait_for', + } + ); + }); + + describe('if task manager throws an error', () => { + beforeEach(() => { + mockTaskManagerStart.ensureScheduled.mockRejectedValueOnce( + new Error('Task Manager error') + ); }); - it('should update saved object attribute', async () => { - await riskEngineDataClient.enableRiskEngine({ taskManager: mockTaskManagerStart }); + it('disables the risk engine and re-throws the error', async () => { + await expect( + riskEngineDataClient.enableRiskEngine({ taskManager: mockTaskManagerStart }) + ).rejects.toThrow('Task Manager error'); expect(mockSavedObjectClient.update).toHaveBeenCalledWith( 'risk-engine-configuration', 'de8ca330-2d26-11ee-bc86-f95bf6192ee6', { - enabled: true, + enabled: false, }, { refresh: 'wait_for', } ); }); - - describe('if task manager throws an error', () => { - beforeEach(() => { - mockTaskManagerStart.ensureScheduled.mockRejectedValueOnce( - new Error('Task Manager error') - ); - }); - - it('disables the risk engine and re-throws the error', async () => { - await expect( - riskEngineDataClient.enableRiskEngine({ taskManager: mockTaskManagerStart }) - ).rejects.toThrow('Task Manager error'); - - expect(mockSavedObjectClient.update).toHaveBeenCalledWith( - 'risk-engine-configuration', - 'de8ca330-2d26-11ee-bc86-f95bf6192ee6', - { - enabled: false, - }, - { - refresh: 'wait_for', - } - ); - }); - }); }); + }); - describe('disableRiskEngine', () => { - let mockTaskManagerStart: ReturnType; + describe('disableRiskEngine', () => { + let mockTaskManagerStart: ReturnType; - beforeEach(() => { - mockTaskManagerStart = taskManagerMock.createStart(); - }); + beforeEach(() => { + mockTaskManagerStart = taskManagerMock.createStart(); + }); - it('should return error if saved object not exist', async () => { - mockSavedObjectClient.find.mockResolvedValueOnce({ - page: 1, - per_page: 20, - total: 0, - saved_objects: [], - }); - - expect.assertions(1); - try { - await riskEngineDataClient.disableRiskEngine({ taskManager: mockTaskManagerStart }); - } catch (e) { - expect(e.message).toEqual('Risk engine configuration not found'); - } + it('should return error if saved object not exist', async () => { + mockSavedObjectClient.find.mockResolvedValueOnce({ + page: 1, + per_page: 20, + total: 0, + saved_objects: [], }); - it('should update saved object attrubute', async () => { - mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); - + expect.assertions(1); + try { await riskEngineDataClient.disableRiskEngine({ taskManager: mockTaskManagerStart }); + } catch (e) { + expect(e.message).toEqual('Risk engine configuration not found'); + } + }); - expect(mockSavedObjectClient.update).toHaveBeenCalledWith( - 'risk-engine-configuration', - 'de8ca330-2d26-11ee-bc86-f95bf6192ee6', - { - enabled: false, - }, - { - refresh: 'wait_for', - } - ); - }); + it('should update saved object attribute', async () => { + mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); + + await riskEngineDataClient.disableRiskEngine({ taskManager: mockTaskManagerStart }); + + expect(mockSavedObjectClient.update).toHaveBeenCalledWith( + 'risk-engine-configuration', + 'de8ca330-2d26-11ee-bc86-f95bf6192ee6', + { + enabled: false, + }, + { + refresh: 'wait_for', + } + ); }); + }); - describe('init', () => { - let mockTaskManagerStart: ReturnType; - const initRiskScore = jest.spyOn(RiskScoreDataClient.prototype, 'init'); - const enableRiskEngineMock = jest.spyOn(RiskEngineDataClient.prototype, 'enableRiskEngine'); + describe('init', () => { + let mockTaskManagerStart: ReturnType; + let initRiskScore: jest.SpyInstance; + let enableRiskEngineMock: jest.SpyInstance; + let disableLegacyRiskEngineMock: jest.SpyInstance; - const disableLegacyRiskEngineMock = jest.spyOn( + beforeEach(() => { + initRiskScore = jest.spyOn(RiskScoreDataClient.prototype, 'init'); + enableRiskEngineMock = jest.spyOn(RiskEngineDataClient.prototype, 'enableRiskEngine'); + disableLegacyRiskEngineMock = jest.spyOn( RiskEngineDataClient.prototype, 'disableLegacyRiskEngine' ); - beforeEach(() => { - mockTaskManagerStart = taskManagerMock.createStart(); - disableLegacyRiskEngineMock.mockImplementation(() => Promise.resolve(true)); - initRiskScore.mockImplementation(() => { - return Promise.resolve(); - }); + mockTaskManagerStart = taskManagerMock.createStart(); + disableLegacyRiskEngineMock.mockImplementation(() => Promise.resolve(true)); - enableRiskEngineMock.mockImplementation(() => { - return Promise.resolve(getSavedObjectConfiguration().saved_objects[0]); - }); + initRiskScore.mockImplementation(() => { + return Promise.resolve(); + }); - jest - .spyOn(savedObjectConfig, 'initSavedObjects') - .mockResolvedValue({} as unknown as SavedObject); + enableRiskEngineMock.mockImplementation(() => { + return Promise.resolve(getSavedObjectConfiguration().saved_objects[0]); }); - afterEach(() => { - initRiskScore.mockReset(); - enableRiskEngineMock.mockReset(); - disableLegacyRiskEngineMock.mockReset(); + jest + .spyOn(savedObjectConfig, 'initSavedObjects') + .mockResolvedValue({} as unknown as SavedObject); + }); + + afterEach(() => { + initRiskScore.mockReset(); + enableRiskEngineMock.mockReset(); + disableLegacyRiskEngineMock.mockReset(); + }); + + it('success', async () => { + const initResult = await riskEngineDataClient.init({ + namespace: 'default', + taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); - it('success', async () => { - const initResult = await riskEngineDataClient.init({ - namespace: 'default', - taskManager: mockTaskManagerStart, - riskScoreDataClient: riskScoreDataClientMock.create(), - }); - - expect(initResult).toEqual({ - errors: [], - legacyRiskEngineDisabled: true, - riskEngineConfigurationCreated: true, - riskEngineEnabled: true, - riskEngineResourcesInstalled: true, - }); + expect(initResult).toEqual({ + errors: [], + legacyRiskEngineDisabled: true, + riskEngineConfigurationCreated: true, + riskEngineEnabled: true, + riskEngineResourcesInstalled: true, }); + }); - it('should catch error for disableLegacyRiskEngine, but continue', async () => { - disableLegacyRiskEngineMock.mockImplementation(() => { - throw new Error('Error disableLegacyRiskEngineMock'); - }); - const initResult = await riskEngineDataClient.init({ - namespace: 'default', - taskManager: mockTaskManagerStart, - riskScoreDataClient: riskScoreDataClientMock.create(), - }); - - expect(initResult).toEqual({ - errors: ['Error disableLegacyRiskEngineMock'], - legacyRiskEngineDisabled: false, - riskEngineConfigurationCreated: true, - riskEngineEnabled: true, - riskEngineResourcesInstalled: true, - }); + it('should catch error for disableLegacyRiskEngine, but continue', async () => { + disableLegacyRiskEngineMock.mockImplementation(() => { + throw new Error('Error disableLegacyRiskEngineMock'); + }); + const initResult = await riskEngineDataClient.init({ + namespace: 'default', + taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); - it('should catch error for resource init', async () => { - disableLegacyRiskEngineMock.mockImplementationOnce(() => { - throw new Error('Error disableLegacyRiskEngineMock'); - }); - - const initResult = await riskEngineDataClient.init({ - namespace: 'default', - taskManager: mockTaskManagerStart, - riskScoreDataClient: riskScoreDataClientMock.create(), - }); - - expect(initResult).toEqual({ - errors: ['Error disableLegacyRiskEngineMock'], - legacyRiskEngineDisabled: false, - riskEngineConfigurationCreated: true, - riskEngineEnabled: true, - riskEngineResourcesInstalled: true, - }); + expect(initResult).toEqual({ + errors: ['Error disableLegacyRiskEngineMock'], + legacyRiskEngineDisabled: false, + riskEngineConfigurationCreated: true, + riskEngineEnabled: true, + riskEngineResourcesInstalled: true, }); + }); - it('should catch error for initializeResources and stop', async () => { - const riskScoreDataClient = riskScoreDataClientMock.create(); - riskScoreDataClient.init.mockImplementationOnce(() => { - throw new Error('Error riskScoreDataClient'); - }); - - const initResult = await riskEngineDataClient.init({ - namespace: 'default', - taskManager: mockTaskManagerStart, - riskScoreDataClient, - }); - - expect(initResult).toEqual({ - errors: ['Error riskScoreDataClient'], - legacyRiskEngineDisabled: true, - riskEngineConfigurationCreated: false, - riskEngineEnabled: false, - riskEngineResourcesInstalled: false, - }); + it('should catch error for resource init', async () => { + disableLegacyRiskEngineMock.mockImplementationOnce(() => { + throw new Error('Error disableLegacyRiskEngineMock'); }); - it('should catch error for initSavedObjects and stop', async () => { - jest.spyOn(savedObjectConfig, 'initSavedObjects').mockImplementationOnce(() => { - throw new Error('Error initSavedObjects'); - }); - - const initResult = await riskEngineDataClient.init({ - namespace: 'default', - taskManager: mockTaskManagerStart, - riskScoreDataClient: riskScoreDataClientMock.create(), - }); - - expect(initResult).toEqual({ - errors: ['Error initSavedObjects'], - legacyRiskEngineDisabled: true, - riskEngineConfigurationCreated: false, - riskEngineEnabled: false, - riskEngineResourcesInstalled: true, - }); + const initResult = await riskEngineDataClient.init({ + namespace: 'default', + taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); - it('should catch error for enableRiskEngineMock and stop', async () => { - enableRiskEngineMock.mockImplementationOnce(() => { - throw new Error('Error enableRiskEngineMock'); - }); - - const initResult = await riskEngineDataClient.init({ - namespace: 'default', - taskManager: mockTaskManagerStart, - riskScoreDataClient: riskScoreDataClientMock.create(), - }); - - expect(initResult).toEqual({ - errors: ['Error enableRiskEngineMock'], - legacyRiskEngineDisabled: true, - riskEngineConfigurationCreated: true, - riskEngineEnabled: false, - riskEngineResourcesInstalled: true, - }); + expect(initResult).toEqual({ + errors: ['Error disableLegacyRiskEngineMock'], + legacyRiskEngineDisabled: false, + riskEngineConfigurationCreated: true, + riskEngineEnabled: true, + riskEngineResourcesInstalled: true, }); }); - describe('tearDownRiskEngine', () => { - const mockTaskManagerStart = taskManagerMock.createStart(); + it('should catch error for initializeResources and stop', async () => { + const riskScoreDataClient = riskScoreDataClientMock.create(); + riskScoreDataClient.init.mockImplementationOnce(() => { + throw new Error('Error riskScoreDataClient'); + }); - it('should delete the risk engine object and task if it exists', async () => { - mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); - const riskScoreDataClient = riskScoreDataClientMock.create(); - await riskEngineDataClient.tearDown({ - taskManager: mockTaskManagerStart, - riskScoreDataClient, - }); + const initResult = await riskEngineDataClient.init({ + namespace: 'default', + taskManager: mockTaskManagerStart, + riskScoreDataClient, + }); - expect(mockSavedObjectClient.delete).toHaveBeenCalledTimes(1); - expect(mockTaskManagerStart.remove).toHaveBeenCalledTimes(1); - expect(riskScoreDataClient.tearDown).toHaveBeenCalledTimes(1); + expect(initResult).toEqual({ + errors: ['Error riskScoreDataClient'], + legacyRiskEngineDisabled: true, + riskEngineConfigurationCreated: false, + riskEngineEnabled: false, + riskEngineResourcesInstalled: false, }); + }); - it('should return errors when exception is thrown ', async () => { - const error = new Error('testError'); - mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); - mockTaskManagerStart.remove.mockRejectedValueOnce(error); - mockSavedObjectClient.delete.mockRejectedValueOnce(error); + it('should catch error for initSavedObjects and stop', async () => { + jest.spyOn(savedObjectConfig, 'initSavedObjects').mockImplementationOnce(() => { + throw new Error('Error initSavedObjects'); + }); + + const initResult = await riskEngineDataClient.init({ + namespace: 'default', + taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), + }); + + expect(initResult).toEqual({ + errors: ['Error initSavedObjects'], + legacyRiskEngineDisabled: true, + riskEngineConfigurationCreated: false, + riskEngineEnabled: false, + riskEngineResourcesInstalled: true, + }); + }); - const errors = await riskEngineDataClient.tearDown({ - taskManager: mockTaskManagerStart, - riskScoreDataClient: riskScoreDataClientMock.create(), - }); + it('should catch error for enableRiskEngineMock and stop', async () => { + enableRiskEngineMock.mockImplementationOnce(() => { + throw new Error('Error enableRiskEngineMock'); + }); - await expect(errors).toEqual([error, error]); + const initResult = await riskEngineDataClient.init({ + namespace: 'default', + taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), }); - it('should return errors from riskScoreDataClient.tearDown ', async () => { - const error = new Error('testError'); - mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); - const riskScoreDataClient = riskScoreDataClientMock.create(); - riskScoreDataClient.tearDown.mockResolvedValueOnce([error]); + expect(initResult).toEqual({ + errors: ['Error enableRiskEngineMock'], + legacyRiskEngineDisabled: true, + riskEngineConfigurationCreated: true, + riskEngineEnabled: false, + riskEngineResourcesInstalled: true, + }); + }); + }); - const errors = await riskEngineDataClient.tearDown({ - taskManager: mockTaskManagerStart, - riskScoreDataClient, - }); + describe('tearDownRiskEngine', () => { + const mockTaskManagerStart = taskManagerMock.createStart(); - await expect(errors).toEqual([error]); + it('should delete the risk engine object and task if it exists', async () => { + mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); + const riskScoreDataClient = riskScoreDataClientMock.create(); + await riskEngineDataClient.tearDown({ + taskManager: mockTaskManagerStart, + riskScoreDataClient, }); + + expect(mockSavedObjectClient.delete).toHaveBeenCalledTimes(1); + expect(mockTaskManagerStart.remove).toHaveBeenCalledTimes(1); + expect(riskScoreDataClient.tearDown).toHaveBeenCalledTimes(1); + }); + + it('should return errors when exception is thrown ', async () => { + const error = new Error('testError'); + mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); + mockTaskManagerStart.remove.mockRejectedValueOnce(error); + mockSavedObjectClient.delete.mockRejectedValueOnce(error); + + const errors = await riskEngineDataClient.tearDown({ + taskManager: mockTaskManagerStart, + riskScoreDataClient: riskScoreDataClientMock.create(), + }); + + expect(errors).toEqual([error, error]); + }); + + it('should return errors from riskScoreDataClient.tearDown ', async () => { + const error = new Error('testError'); + mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration()); + const riskScoreDataClient = riskScoreDataClientMock.create(); + riskScoreDataClient.tearDown.mockResolvedValueOnce([error]); + + const errors = await riskEngineDataClient.tearDown({ + taskManager: mockTaskManagerStart, + riskScoreDataClient, + }); + + expect(errors).toEqual([error]); }); }); - } + }); }); diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index c274cb0e0d382..a2a9fda8ecc44 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -15,7 +15,11 @@ "public/**/*.json", "../../../typings/**/*" ], - "exclude": ["target/**/*", "**/cypress/**", "public/management/cypress.config.ts"], + "exclude": [ + "target/**/*", + "**/cypress/**", + "public/management/cypress.config.ts" + ], "kbn_references": [ "@kbn/core", { @@ -208,9 +212,11 @@ "@kbn/core-theme-browser", "@kbn/integration-assistant-plugin", "@kbn/avc-banner", + "@kbn/security-solution-common", "@kbn/esql-ast", "@kbn/esql-validation-autocomplete", "@kbn/config", + "@kbn/cbor", "@kbn/zod", ] } diff --git a/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts b/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts index cd5a6a79eed33..8eb74f781096a 100644 --- a/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts +++ b/x-pack/plugins/security_solution_serverless/server/cloud_security/constants.ts @@ -6,10 +6,12 @@ */ import { - CNVM_POLICY_TEMPLATE, CSPM_POLICY_TEMPLATE, KSPM_POLICY_TEMPLATE, CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN, +} from '@kbn/cloud-security-posture-common'; +import { + CNVM_POLICY_TEMPLATE, LATEST_VULNERABILITIES_INDEX_PATTERN, } from '@kbn/cloud-security-posture-plugin/common/constants'; import { INTEGRATION_PACKAGE_NAME } from '@kbn/cloud-defend-plugin/common/constants'; diff --git a/x-pack/plugins/security_solution_serverless/tsconfig.json b/x-pack/plugins/security_solution_serverless/tsconfig.json index b6bfbea1cc7be..55a4882655dc7 100644 --- a/x-pack/plugins/security_solution_serverless/tsconfig.json +++ b/x-pack/plugins/security_solution_serverless/tsconfig.json @@ -45,5 +45,6 @@ "@kbn/discover-plugin", "@kbn/logging", "@kbn/integration-assistant-plugin", + "@kbn/cloud-security-posture-common", ] } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts index ce85e27a8eb43..2a4d91a07f1d3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.test.ts @@ -25,6 +25,7 @@ import { import { DEFAULT_BODY } from '../../../public/connector_types/bedrock/constants'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { AxiosError } from 'axios'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); // @ts-ignore @@ -37,6 +38,7 @@ describe('BedrockConnector', () => { completion: mockResponseString, stop_reason: 'stop_sequence', }; + const logger = loggingSystemMock.createLogger(); const claude3Response = { id: 'compl_01E7D3vTBHdNdKWCe6zALmLH', @@ -57,12 +59,18 @@ describe('BedrockConnector', () => { headers: {}, data: claude3Response, }; + let connectorUsageCollector: ConnectorUsageCollector; + beforeEach(() => { jest.clearAllMocks(); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); const connector = new BedrockConnector({ @@ -73,7 +81,7 @@ describe('BedrockConnector', () => { defaultModel: DEFAULT_BEDROCK_MODEL, }, secrets: { accessKey: '123', secret: 'secret' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); @@ -85,7 +93,13 @@ describe('BedrockConnector', () => { describe('runApi', () => { it('the aws signature has non-streaming headers', async () => { - await connector.runApi({ body: DEFAULT_BODY }); + await connector.runApi( + { body: DEFAULT_BODY }, + new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }) + ); expect(mockSigner).toHaveBeenCalledWith( { body: DEFAULT_BODY, @@ -101,16 +115,19 @@ describe('BedrockConnector', () => { ); }); it('the Bedrock API call is successful with Claude 3 parameters; returns the response formatted for Claude 2 along with usage object', async () => { - const response = await connector.runApi({ body: DEFAULT_BODY }); + const response = await connector.runApi({ body: DEFAULT_BODY }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: DEFAULT_BODY, - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: DEFAULT_BODY, + }, + connectorUsageCollector + ); expect(response).toEqual({ ...claude2Response, usage: claude3Response.usage, @@ -128,16 +145,19 @@ describe('BedrockConnector', () => { }); // @ts-ignore connector.request = mockRequest; - const response = await connector.runApi({ body: v2Body }); + const response = await connector.runApi({ body: v2Body }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunActionResponseSchema, - data: v2Body, - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunActionResponseSchema, + data: v2Body, + }, + connectorUsageCollector + ); expect(response).toEqual(claude2Response); }); @@ -145,7 +165,15 @@ describe('BedrockConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: DEFAULT_BODY })).rejects.toThrow('API Error'); + await expect( + connector.runApi( + { body: DEFAULT_BODY }, + new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }) + ) + ).rejects.toThrow('API Error'); }); }); @@ -170,7 +198,7 @@ describe('BedrockConnector', () => { }; it('the aws signature has streaming headers', async () => { - await connector.invokeStream(aiAssistantBody); + await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(mockSigner).toHaveBeenCalledWith( { @@ -189,170 +217,197 @@ describe('BedrockConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody); + await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), + }, + connectorUsageCollector + ); }); it('signal and timeout is properly passed to streamApi', async () => { const signal = jest.fn(); const timeout = 180000; - await connector.invokeStream({ ...aiAssistantBody, timeout, signal }); - - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), - timeout, - signal, - }); + await connector.invokeStream( + { ...aiAssistantBody, timeout, signal }, + connectorUsageCollector + ); + + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ ...JSON.parse(DEFAULT_BODY), temperature: 0 }), + timeout, + signal, + }, + connectorUsageCollector + ); }); it('ensureMessageFormat - formats messages from user, assistant, and system', async () => { - await connector.invokeStream({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - }); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - responseType: 'stream', - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot', + await connector.invokeStream( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + }, + connectorUsageCollector + ); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); }); it('ensureMessageFormat - formats messages from when double user/assistant occurs', async () => { - await connector.invokeStream({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'assistant', - content: 'But I can be naughty', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - { - role: 'user', - content: 'I can be naughty too', - }, - { - role: 'system', - content: 'This is extra tricky', - }, - ], - }); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - responseType: 'stream', - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot\nThis is extra tricky', + await connector.invokeStream( + { messages: [ - { content: 'Hi, I am a good chatbot\nBut I can be naughty', role: 'assistant' }, - { content: 'What is 2+2?\nI can be naughty too', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'assistant', + content: 'But I can be naughty', + }, + { + role: 'user', + content: 'What is 2+2?', + }, + { + role: 'user', + content: 'I can be naughty too', + }, + { + role: 'system', + content: 'This is extra tricky', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + }, + connectorUsageCollector + ); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot\nThis is extra tricky', + messages: [ + { content: 'Hi, I am a good chatbot\nBut I can be naughty', role: 'assistant' }, + { content: 'What is 2+2?\nI can be naughty too', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); }); it('formats the system message as a user message for claude<2.1', async () => { const modelOverride = 'anthropic.claude-v2'; - await connector.invokeStream({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - model: modelOverride, - }); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - responseType: 'stream', - url: `${DEFAULT_BEDROCK_URL}/model/${modelOverride}/invoke-with-response-stream`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot', + await connector.invokeStream( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + model: modelOverride, + }, + connectorUsageCollector + ); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + responseType: 'stream', + url: `${DEFAULT_BEDROCK_URL}/model/${modelOverride}/invoke-with-response-stream`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); }); it('responds with a readable stream', async () => { - const response = await connector.invokeStream(aiAssistantBody); + const response = await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(response instanceof PassThrough).toEqual(true); }); @@ -360,7 +415,9 @@ describe('BedrockConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeStream(aiAssistantBody)).rejects.toThrow('API Error'); + await expect( + connector.invokeStream(aiAssistantBody, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); }); @@ -376,175 +433,201 @@ describe('BedrockConnector', () => { }; it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(aiAssistantBody); + const response = await connector.invokeAI(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - ...JSON.parse(DEFAULT_BODY), - messages: [{ content: 'Hello world', role: 'user' }], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + ...JSON.parse(DEFAULT_BODY), + messages: [{ content: 'Hello world', role: 'user' }], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); expect(response.message).toEqual(mockResponseString); }); it('formats messages from user, assistant, and system', async () => { - const response = await connector.invokeAI({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'Be a good chatbot', + const response = await connector.invokeAI( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'Be a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); expect(response.message).toEqual(mockResponseString); }); it('adds system message from argument', async () => { - const response = await connector.invokeAI({ - messages: [ - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - system: 'This is a system message', - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'This is a system message', + const response = await connector.invokeAI( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + system: 'This is a system message', + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'This is a system message', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); expect(response.message).toEqual(mockResponseString); }); it('combines argument system message with conversation system message', async () => { - const response = await connector.invokeAI({ - messages: [ - { - role: 'system', - content: 'Be a good chatbot', - }, - { - role: 'user', - content: 'Hello world', - }, - { - role: 'assistant', - content: 'Hi, I am a good chatbot', - }, - { - role: 'user', - content: 'What is 2+2?', - }, - ], - system: 'This is a system message', - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - timeout: DEFAULT_TIMEOUT_MS, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - anthropic_version: 'bedrock-2023-05-31', - system: 'This is a system message\nBe a good chatbot', + const response = await connector.invokeAI( + { messages: [ - { content: 'Hello world', role: 'user' }, - { content: 'Hi, I am a good chatbot', role: 'assistant' }, - { content: 'What is 2+2?', role: 'user' }, + { + role: 'system', + content: 'Be a good chatbot', + }, + { + role: 'user', + content: 'Hello world', + }, + { + role: 'assistant', + content: 'Hi, I am a good chatbot', + }, + { + role: 'user', + content: 'What is 2+2?', + }, ], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - }); + system: 'This is a system message', + }, + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + timeout: DEFAULT_TIMEOUT_MS, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + anthropic_version: 'bedrock-2023-05-31', + system: 'This is a system message\nBe a good chatbot', + messages: [ + { content: 'Hello world', role: 'user' }, + { content: 'Hi, I am a good chatbot', role: 'assistant' }, + { content: 'What is 2+2?', role: 'user' }, + ], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + }, + connectorUsageCollector + ); expect(response.message).toEqual(mockResponseString); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 180000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }); - - expect(mockRequest).toHaveBeenCalledWith({ - signed: true, - url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, - method: 'post', - responseSchema: RunApiLatestResponseSchema, - data: JSON.stringify({ - ...JSON.parse(DEFAULT_BODY), - messages: [{ content: 'Hello world', role: 'user' }], - max_tokens: DEFAULT_TOKEN_LIMIT, - temperature: 0, - }), - timeout, - signal, - }); + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + signed: true, + url: `${DEFAULT_BEDROCK_URL}/model/${DEFAULT_BEDROCK_MODEL}/invoke`, + method: 'post', + responseSchema: RunApiLatestResponseSchema, + data: JSON.stringify({ + ...JSON.parse(DEFAULT_BODY), + messages: [{ content: 'Hello world', role: 'user' }], + max_tokens: DEFAULT_TOKEN_LIMIT, + temperature: 0, + }), + timeout, + signal, + }, + connectorUsageCollector + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeAI(aiAssistantBody)).rejects.toThrow('API Error'); + await expect(connector.invokeAI(aiAssistantBody, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); describe('getResponseErrorMessage', () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts index 6b981a365b63a..b5ec114a9c456 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/bedrock/bedrock.ts @@ -11,6 +11,7 @@ import { AxiosError, Method } from 'axios'; import { IncomingMessage } from 'http'; import { PassThrough } from 'stream'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { RunActionParamsSchema, @@ -194,16 +195,18 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B } private async runApiRaw( - params: SubActionRequestParams + params: SubActionRequestParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - const response = await this.request(params); + const response = await this.request(params, connectorUsageCollector); return response.data; } private async runApiLatest( - params: SubActionRequestParams + params: SubActionRequestParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - const response = await this.request(params); + const response = await this.request(params, connectorUsageCollector); // keeping the response the same as claude 2 for our APIs // adding the usage object for better token tracking return { @@ -218,13 +221,10 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param body The stringified request body to be sent in the POST request. * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async runApi({ - body, - model: reqModel, - signal, - timeout, - raw, - }: RunActionParams): Promise { + public async runApi( + { body, model: reqModel, signal, timeout, raw }: RunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; const path = `/model/${currentModel}/invoke`; @@ -240,13 +240,22 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B }; if (raw) { - return this.runApiRaw({ ...requestArgs, responseSchema: InvokeAIRawActionResponseSchema }); + return this.runApiRaw( + { ...requestArgs, responseSchema: InvokeAIRawActionResponseSchema }, + connectorUsageCollector + ); } // possible api received deprecated arguments, which will still work with the deprecated Claude 2 models if (usesDeprecatedArguments(body)) { - return this.runApiRaw({ ...requestArgs, responseSchema: RunActionResponseSchema }); + return this.runApiRaw( + { ...requestArgs, responseSchema: RunActionResponseSchema }, + connectorUsageCollector + ); } - return this.runApiLatest({ ...requestArgs, responseSchema: RunApiLatestResponseSchema }); + return this.runApiLatest( + { ...requestArgs, responseSchema: RunApiLatestResponseSchema }, + connectorUsageCollector + ); } /** @@ -257,26 +266,27 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param body The stringified request body to be sent in the POST request. * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - private async streamApi({ - body, - model: reqModel, - signal, - timeout, - }: RunActionParams): Promise { + private async streamApi( + { body, model: reqModel, signal, timeout }: RunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { // set model on per request basis const path = `/model/${reqModel ?? this.model}/invoke-with-response-stream`; const signed = this.signRequest(body, path, true); - const response = await this.request({ - ...signed, - url: `${this.url}${path}`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: body, - responseType: 'stream', - signal, - timeout, - }); + const response = await this.request( + { + ...signed, + url: `${this.url}${path}`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: body, + responseType: 'stream', + signal, + timeout, + }, + connectorUsageCollector + ); return response.data.pipe(new PassThrough()); } @@ -289,24 +299,30 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param messages An array of messages to be sent to the API * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async invokeStream({ - messages, - model, - stopSequences, - system, - temperature, - signal, - timeout, - tools, - }: InvokeAIActionParams | InvokeAIRawActionParams): Promise { - const res = (await this.streamApi({ - body: JSON.stringify( - formatBedrockBody({ messages, stopSequences, system, temperature, tools }) - ), + public async invokeStream( + { + messages, model, + stopSequences, + system, + temperature, signal, timeout, - })) as unknown as IncomingMessage; + tools, + }: InvokeAIActionParams | InvokeAIRawActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = (await this.streamApi( + { + body: JSON.stringify( + formatBedrockBody({ messages, stopSequences, system, temperature, tools }) + ), + model, + signal, + timeout, + }, + connectorUsageCollector + )) as unknown as IncomingMessage; return res; } @@ -318,54 +334,66 @@ The Kibana Connector in use may need to be reconfigured with an updated Amazon B * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. * @returns an object with the response string as a property called message */ - public async invokeAI({ - messages, - model, - stopSequences, - system, - temperature, - maxTokens, - signal, - timeout, - }: InvokeAIActionParams): Promise { - const res = (await this.runApi({ - body: JSON.stringify( - formatBedrockBody({ messages, stopSequences, system, temperature, maxTokens }) - ), + public async invokeAI( + { + messages, model, + stopSequences, + system, + temperature, + maxTokens, signal, timeout, - })) as RunActionResponse; + }: InvokeAIActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = (await this.runApi( + { + body: JSON.stringify( + formatBedrockBody({ messages, stopSequences, system, temperature, maxTokens }) + ), + model, + signal, + timeout, + }, + connectorUsageCollector + )) as RunActionResponse; return { message: res.completion.trim() }; } - public async invokeAIRaw({ - messages, - model, - stopSequences, - system, - temperature, - maxTokens = DEFAULT_TOKEN_LIMIT, - signal, - timeout, - tools, - anthropicVersion, - }: InvokeAIRawActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify({ - messages, - stop_sequences: stopSequences, - system, - temperature, - max_tokens: maxTokens, - tools, - anthropic_version: anthropicVersion, - }), + public async invokeAIRaw( + { + messages, model, + stopSequences, + system, + temperature, + maxTokens = DEFAULT_TOKEN_LIMIT, signal, timeout, - raw: true, - }); + tools, + anthropicVersion, + }: InvokeAIRawActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify({ + messages, + stop_sequences: stopSequences, + system, + temperature, + max_tokens: maxTokens, + tools, + anthropic_version: anthropicVersion, + }), + model, + signal, + timeout, + raw: true, + }, + connectorUsageCollector + ); return res; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts index 62dd881608605..ccd777634ec37 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/index.ts @@ -70,7 +70,7 @@ export async function executor( CasesWebhookActionParamsType > ): Promise> { - const { actionId, configurationUtilities, params, logger } = execOptions; + const { actionId, configurationUtilities, params, logger, connectorUsageCollector } = execOptions; const { subAction, subActionParams } = params; let data: CasesWebhookExecutorResultData | undefined; @@ -81,7 +81,8 @@ export async function executor( secrets: execOptions.secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts index 3a8cf2895e60e..a44b34bf88fce 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.test.ts @@ -14,6 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { AuthType, WebhookMethods, SSLCertType } from '../../../common/auth/constants'; import { CRT_FILE, KEY_FILE } from '../../../common/auth/mocks'; @@ -69,12 +70,17 @@ const sslConfig: CasesWebhookPublicConfigurationType = { hasAuth: true, }; const sslSecrets = { crt: CRT_FILE, key: KEY_FILE, password: 'foobar', user: null, pfx: null }; +let connectorUsageCollector: ConnectorUsageCollector; describe('Cases webhook service', () => { let service: ExternalService; let sslService: ExternalService; beforeAll(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( actionId, { @@ -82,7 +88,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); sslService = createExternalService( @@ -92,7 +99,8 @@ describe('Cases webhook service', () => { secrets: sslSecrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); jest.useFakeTimers(); jest.setSystemTime(mockTime); @@ -121,7 +129,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -135,7 +144,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: '', password: '' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -149,7 +159,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: '', password: '' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).not.toThrow(); }); @@ -162,7 +173,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: 'username', password: 'password' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -182,7 +194,8 @@ describe('Cases webhook service', () => { secrets: { ...secrets, user: 'username', password: 'password' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -225,6 +238,7 @@ describe('Cases webhook service', () => { logger, configurationUtilities, sslOverrides: defaultSSLOverrides, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -238,6 +252,24 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "logger": Object { "context": Array [], "debug": [MockFunction], @@ -481,6 +513,7 @@ describe('Cases webhook service', () => { configurationUtilities, sslOverrides: defaultSSLOverrides, data: `{"fields":{"title":"title","description":"desc","tags":["hello","world"],"project":{"key":"ROC"},"issuetype":{"id":"10024"}}}`, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -510,6 +543,36 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"1234\\": [HTTP 200] OK", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": "{\\"fields\\":{\\"title\\":\\"title\\",\\"description\\":\\"desc\\",\\"tags\\":[\\"hello\\",\\"world\\"],\\"project\\":{\\"key\\":\\"ROC\\"},\\"issuetype\\":{\\"id\\":\\"10024\\"}}}", "logger": Object { "context": Array [], @@ -756,6 +819,7 @@ describe('Cases webhook service', () => { issuetype: { id: '10024' }, }, }), + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -776,6 +840,24 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": "{\\"fields\\":{\\"title\\":\\"title\\",\\"description\\":\\"desc\\",\\"tags\\":[\\"hello\\",\\"world\\"],\\"project\\":{\\"key\\":\\"ROC\\"},\\"issuetype\\":{\\"id\\":\\"10024\\"}}}", "logger": Object { "context": Array [], @@ -984,6 +1066,7 @@ describe('Cases webhook service', () => { sslOverrides: defaultSSLOverrides, url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment"}`, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -1004,6 +1087,24 @@ describe('Cases webhook service', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": [Function], + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction], + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": "{\\"body\\":\\"comment\\"}", "logger": Object { "context": Array [], @@ -1176,7 +1277,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1191,7 +1293,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); const res = await service.createComment(commentReq); expect(requestMock).not.toHaveBeenCalled(); @@ -1217,7 +1320,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); await service.createComment(commentReq); expect(requestMock).toHaveBeenCalledWith({ @@ -1228,6 +1332,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":"1"}`, sslOverrides: defaultSSLOverrides, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); @@ -1257,7 +1362,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); await service.createComment(commentReq2); expect(requestMock).toHaveBeenCalledWith({ @@ -1268,6 +1374,7 @@ describe('Cases webhook service', () => { url: 'https://coolsite.net/issue/1/comment', data: `{"body":"comment","id":1}`, sslOverrides: defaultSSLOverrides, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }); }); @@ -1286,7 +1393,8 @@ describe('Cases webhook service', () => { ensureUriAllowed: jest.fn().mockImplementation(() => { throw new Error('Uri not allowed'); }), - } + }, + connectorUsageCollector ); }); @@ -1360,7 +1468,8 @@ describe('Cases webhook service', () => { secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); }); @@ -1430,7 +1539,8 @@ describe('Cases webhook service', () => { logger, { ...configurationUtilities, - } + }, + connectorUsageCollector ); requestMock.mockImplementation(() => createAxiosResponse({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts index 424fe9b394517..170c63a1d4e5b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/cases_webhook/service.ts @@ -12,6 +12,7 @@ import { renderMustacheStringNoEscape } from '@kbn/actions-plugin/server/lib/mus import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { buildConnectorAuth, validateConnectorAuthConfiguration } from '../../../common/auth/utils'; import { validateAndNormalizeUrl, validateJson } from './validators'; import { @@ -38,7 +39,8 @@ export const createExternalService = ( actionId: string, { config, secrets }: ExternalServiceCredentials, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector ): ExternalService => { const { createCommentJson, @@ -117,6 +119,7 @@ export const createExternalService = ( logger, configurationUtilities, sslOverrides, + connectorUsageCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -162,6 +165,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, + connectorUsageCollector, }); const { status, statusText, data } = res; @@ -246,6 +250,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, + connectorUsageCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ @@ -319,6 +324,7 @@ export const createExternalService = ( data: json, configurationUtilities, sslOverrides, + connectorUsageCollector, }); throwDescriptiveErrorIfResponseIsNotValid({ 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 d53881cae1272..0c3d851981fde 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 @@ -10,27 +10,34 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { CROWDSTRIKE_CONNECTOR_ID } from '../../../public/common'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; 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 logger = loggingSystemMock.createLogger(); const connector = new CrowdstrikeConnector({ configurationUtilities: actionsConfigMock.create(), connector: { id: '1', type: CROWDSTRIKE_CONNECTOR_ID }, config: { url: 'https://api.crowdstrike.com' }, secrets: { clientId: '123', clientSecret: 'secret' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); let mockedRequest: jest.Mock; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { // @ts-expect-error private static - but I still want to reset it CrowdstrikeConnector.token = null; // @ts-expect-error mockedRequest = connector.request = jest.fn() as jest.Mock; + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); afterEach(() => { jest.clearAllMocks(); @@ -43,10 +50,13 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValueOnce(mockResponse); - const result = await connector.executeHostActions({ - command: 'contain', - ids: ['id1', 'id2'], - }); + const result = await connector.executeHostActions( + { + command: 'contain', + ids: ['id1', 'id2'], + }, + connectorUsageCollector + ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, expect.objectContaining({ @@ -58,7 +68,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -69,7 +80,8 @@ describe('CrowdstrikeConnector', () => { data: { ids: ['id1', 'id2'] }, paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), - }) + }), + connectorUsageCollector ); expect(result).toEqual({ id: 'testid', path: 'testpath' }); }); @@ -82,7 +94,10 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValueOnce(mockResponse); - const result = await connector.getAgentDetails({ ids: ['id1', 'id2'] }); + const result = await connector.getAgentDetails( + { ids: ['id1', 'id2'] }, + connectorUsageCollector + ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -95,7 +110,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -108,7 +124,8 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: hostPath, - }) + }), + connectorUsageCollector ); expect(result).toEqual({ resources: [{}] }); }); @@ -121,7 +138,10 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValueOnce(mockResponse); - const result = await connector.getAgentOnlineStatus({ ids: ['id1', 'id2'] }); + const result = await connector.getAgentOnlineStatus( + { ids: ['id1', 'id2'] }, + connectorUsageCollector + ); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -134,7 +154,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -147,7 +168,8 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: onlineStatusPath, - }) + }), + connectorUsageCollector ); expect(result).toEqual({ resources: [{}] }); }); @@ -226,7 +248,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce(mockResponse); // @ts-expect-error private method - but I still want to - const result = await connector.getTokenRequest(); + const result = await connector.getTokenRequest(connectorUsageCollector); expect(mockedRequest).toHaveBeenCalledWith( expect.objectContaining({ @@ -237,7 +259,8 @@ describe('CrowdstrikeConnector', () => { 'Content-Type': 'application/x-www-form-urlencoded', authorization: expect.stringContaining('Basic'), }, - }) + }), + connectorUsageCollector ); expect(result).toEqual('testToken'); }); @@ -247,7 +270,7 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockResolvedValue(mockResponse); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector); expect(mockedRequest).toHaveBeenNthCalledWith( 1, @@ -260,7 +283,8 @@ describe('CrowdstrikeConnector', () => { method: 'post', responseSchema: expect.any(Object), url: tokenPath, - }) + }), + connectorUsageCollector ); expect(mockedRequest).toHaveBeenNthCalledWith( 2, @@ -273,10 +297,11 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: hostPath, - }) + }), + connectorUsageCollector ); expect(mockedRequest).toHaveBeenCalledTimes(2); - await connector.getAgentDetails({ ids: ['id1', 'id2'] }); + await connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector); expect(mockedRequest).toHaveBeenNthCalledWith( 3, expect.objectContaining({ @@ -288,7 +313,8 @@ describe('CrowdstrikeConnector', () => { paramsSerializer: expect.any(Function), responseSchema: expect.any(Object), url: hostPath, - }) + }), + connectorUsageCollector ); expect(mockedRequest).toHaveBeenCalledTimes(3); }); @@ -298,9 +324,9 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockRejectedValueOnce(mockResponse); - await expect(() => connector.getAgentDetails({ ids: ['id1', 'id2'] })).rejects.toThrowError( - 'something goes wrong' - ); + await expect(() => + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector) + ).rejects.toThrowError('something goes wrong'); expect(mockedRequest).toHaveBeenCalledTimes(2); }); it('should repeat the call one time if theres 401 error ', async () => { @@ -309,7 +335,9 @@ describe('CrowdstrikeConnector', () => { mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); mockedRequest.mockRejectedValueOnce(mockResponse); - await expect(() => connector.getAgentDetails({ ids: ['id1', 'id2'] })).rejects.toThrowError(); + await expect(() => + connector.getAgentDetails({ ids: ['id1', 'id2'] }, connectorUsageCollector) + ).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 3d14ae62924c4..a4fc84ae6a49a 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 @@ -9,6 +9,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 { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { isAggregateError, NodeSystemError } from './types'; import type { CrowdstrikeConfig, @@ -96,68 +97,87 @@ export class CrowdstrikeConnector extends SubActionConnector< }); } - public async executeHostActions({ alertIds, ...payload }: CrowdstrikeHostActionsParams) { - return this.crowdstrikeApiRequest({ - url: this.urls.hostAction, - method: 'post', - params: { - action_name: payload.command, - }, - data: { - ids: payload.ids, - ...(payload.actionParameters - ? { - action_parameters: Object.entries(payload.actionParameters).map(([name, value]) => ({ - name, - value, - })), - } - : {}), + public async executeHostActions( + { alertIds, ...payload }: CrowdstrikeHostActionsParams, + connectorUsageCollector: ConnectorUsageCollector + ) { + return this.crowdstrikeApiRequest( + { + url: this.urls.hostAction, + method: 'post', + params: { + action_name: payload.command, + }, + data: { + ids: payload.ids, + ...(payload.actionParameters + ? { + action_parameters: Object.entries(payload.actionParameters).map( + ([name, value]) => ({ + name, + value, + }) + ), + } + : {}), + }, + paramsSerializer, + responseSchema: CrowdstrikeHostActionsResponseSchema, }, - paramsSerializer, - responseSchema: CrowdstrikeHostActionsResponseSchema, - }); + connectorUsageCollector + ); } public async getAgentDetails( - payload: CrowdstrikeGetAgentsParams + payload: CrowdstrikeGetAgentsParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - return this.crowdstrikeApiRequest({ - url: this.urls.agents, - method: 'GET', - params: { - ids: payload.ids, + return this.crowdstrikeApiRequest( + { + url: this.urls.agents, + method: 'GET', + params: { + ids: payload.ids, + }, + paramsSerializer, + responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - paramsSerializer, - responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, - }) as Promise; + connectorUsageCollector + ) as Promise; } public async getAgentOnlineStatus( - payload: CrowdstrikeGetAgentsParams + payload: CrowdstrikeGetAgentsParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - return this.crowdstrikeApiRequest({ - url: this.urls.agentStatus, - method: 'GET', - params: { - ids: payload.ids, + return this.crowdstrikeApiRequest( + { + url: this.urls.agentStatus, + method: 'GET', + params: { + ids: payload.ids, + }, + paramsSerializer, + responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, }, - paramsSerializer, - responseSchema: RelaxedCrowdstrikeBaseApiResponseSchema, - }) as Promise; + connectorUsageCollector + ) as Promise; } - private async getTokenRequest() { - const response = await this.request({ - url: this.urls.getToken, - method: 'post', - headers: { - accept: 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded', - authorization: 'Basic ' + CrowdstrikeConnector.base64encodedToken, + private async getTokenRequest(connectorUsageCollector: ConnectorUsageCollector) { + const response = await this.request( + { + url: this.urls.getToken, + method: 'post', + headers: { + accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + authorization: 'Basic ' + CrowdstrikeConnector.base64encodedToken, + }, + responseSchema: CrowdstrikeGetTokenResponseSchema, }, - responseSchema: CrowdstrikeGetTokenResponseSchema, - }); + connectorUsageCollector + ); const token = response.data?.access_token; if (token) { // Clear any existing timeout @@ -173,28 +193,33 @@ export class CrowdstrikeConnector extends SubActionConnector< private async crowdstrikeApiRequest( req: SubActionRequestParams, + connectorUsageCollector: ConnectorUsageCollector, retried?: boolean ): Promise { try { if (!CrowdstrikeConnector.token) { - CrowdstrikeConnector.token = (await this.getTokenRequest()) as string; + CrowdstrikeConnector.token = (await this.getTokenRequest( + connectorUsageCollector + )) as string; } - const response = await this.request({ - ...req, - headers: { - ...req.headers, - Authorization: `Bearer ${CrowdstrikeConnector.token}`, + const response = await this.request( + { + ...req, + headers: { + ...req.headers, + Authorization: `Bearer ${CrowdstrikeConnector.token}`, + }, }, - }); + connectorUsageCollector + ); return response.data; } catch (error) { if (error.code === 401 && !retried) { CrowdstrikeConnector.token = null; - return this.crowdstrikeApiRequest(req, true); + return this.crowdstrikeApiRequest(req, connectorUsageCollector, true); } - throw new CrowdstrikeError(error.message); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts index 6f1a002cdf1d0..055a7fe7a7dba 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.test.ts @@ -11,6 +11,7 @@ import { D3_SECURITY_CONNECTOR_ID } from '../../../common/d3security/constants'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { D3SecurityRunActionResponseSchema } from '../../../common/d3security/schema'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; describe('D3SecurityConnector', () => { const sampleBody = JSON.stringify({ @@ -28,6 +29,7 @@ describe('D3SecurityConnector', () => { const mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); }); + const logger = loggingSystemMock.createLogger(); describe('D3 Security', () => { const connector = new D3SecurityConnector({ @@ -35,26 +37,35 @@ describe('D3SecurityConnector', () => { connector: { id: '1', type: D3_SECURITY_CONNECTOR_ID }, config: { url: 'https://example.com/api' }, secrets: { token: '123' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); + let connectorUsageCollector: ConnectorUsageCollector; + beforeEach(() => { // @ts-ignore connector.request = mockRequest; jest.clearAllMocks(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); it('the D3 Security API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: sampleBody }); + const response = await connector.runApi({ body: sampleBody }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api', - method: 'post', - responseSchema: D3SecurityRunActionResponseSchema, - data: sampleBodyFormatted, - headers: { - d3key: '123', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api', + method: 'post', + responseSchema: D3SecurityRunActionResponseSchema, + data: sampleBodyFormatted, + headers: { + d3key: '123', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual({ result: 'success' }); }); @@ -62,7 +73,9 @@ describe('D3SecurityConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: sampleBody })).rejects.toThrow('API Error'); + await expect(connector.runApi({ body: sampleBody }, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts index 804590c01b284..0c35766a3ddf3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/d3security/d3security.ts @@ -7,6 +7,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { addSeverityAndEventTypeInBody } from './helpers'; import { D3SecurityRunActionParamsSchema, @@ -57,22 +58,24 @@ export class D3SecurityConnector extends SubActionConnector { - const response = await this.request({ - url: this.url, - method: 'post', - responseSchema: D3SecurityRunActionResponseSchema, - data: addSeverityAndEventTypeInBody( - body ?? '', - severity ?? D3SecuritySeverity.EMPTY, - eventType ?? '' - ), - headers: { d3key: this.token || '' }, - }); + public async runApi( + { body, severity, eventType }: D3SecurityRunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const response = await this.request( + { + url: this.url, + method: 'post', + responseSchema: D3SecurityRunActionResponseSchema, + data: addSeverityAndEventTypeInBody( + body ?? '', + severity ?? D3SecuritySeverity.EMPTY, + eventType ?? '' + ), + headers: { d3key: this.token || '' }, + }, + connectorUsageCollector + ); return response.data; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts index f3787e8d367d9..4ee4b3e4890b7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.test.ts @@ -20,6 +20,8 @@ import { validateParams, validateSecrets, } from '@kbn/actions-plugin/server/lib'; + +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { sendEmail } from './send_email'; import { ActionParamsType, @@ -514,6 +516,10 @@ describe('execute()', () => { text: 'Go to Elastic', }, }; + const connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); const actionId = 'some-id'; const executorOptions: EmailConnectorTypeExecutorOptions = { @@ -524,6 +530,7 @@ describe('execute()', () => { services, configurationUtilities: actionsConfigMock.create(), logger: mockedLogger, + connectorUsageCollector, }; beforeEach(() => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts index 785ace370323f..3a1d01732eb7d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/index.ts @@ -274,8 +274,16 @@ async function executor( }, execOptions: EmailConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, secrets, params, configurationUtilities, services, logger } = - execOptions; + const { + actionId, + config, + secrets, + params, + configurationUtilities, + services, + logger, + connectorUsageCollector, + } = execOptions; const connectorTokenClient = services.connectorTokenClient; const emails = params.to.concat(params.cc).concat(params.bcc); @@ -366,7 +374,12 @@ async function executor( let result; try { - result = await sendEmail(logger, sendEmailOptions, connectorTokenClient); + result = await sendEmail( + logger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.email.errorSendingErrorMessage', { defaultMessage: 'error sending email', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts index 535c3932c04e7..77de60660a975 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.test.ts @@ -10,7 +10,7 @@ import { Logger } from '@kbn/core/server'; import { sendEmail } from './send_email'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import nodemailer from 'nodemailer'; -import { ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; import { sendEmailGraphApi } from './send_email_graph_api'; @@ -39,6 +39,7 @@ const sendMailMock = jest.fn(); const mockLogger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); +let connectorUsageCollector: ConnectorUsageCollector; describe('send_email module', () => { beforeEach(() => { @@ -53,11 +54,21 @@ describe('send_email module', () => { interceptors: mockAxiosInstanceInterceptor, }; }); + + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockLogger, + connectorId: 'test-connector-id', + }); }); test('handles authenticated email using service', async () => { const sendEmailOptions = getSendEmailOptions({ transport: { service: 'other' } }); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -101,7 +112,12 @@ describe('send_email module', () => { content: { hasHTMLMessage: true }, transport: { service: 'other' }, }); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -159,7 +175,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -176,6 +192,7 @@ describe('send_email module', () => { delete sendEmailGraphApiMock.mock.calls[0][0].options.configurationUtilities; sendEmailGraphApiMock.mock.calls[0].pop(); sendEmailGraphApiMock.mock.calls[0].pop(); + sendEmailGraphApiMock.mock.calls[0].pop(); expect(sendEmailGraphApiMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -254,7 +271,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -292,7 +309,7 @@ describe('send_email module', () => { status: 202, }); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(getOAuthClientCredentialsAccessTokenMock).toHaveBeenCalledWith({ configurationUtilities: sendEmailOptions.configurationUtilities, connectorId: '1', @@ -322,7 +339,7 @@ describe('send_email module', () => { getOAuthClientCredentialsAccessTokenMock.mockReturnValueOnce(null); await expect(() => - sendEmail(mockLogger, sendEmailOptions, connectorTokenClient) + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to retrieve access token for connectorId: 1"` ); @@ -362,7 +379,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -412,7 +434,12 @@ describe('send_email module', () => { delete sendEmailOptions.transport.user; // @ts-expect-error delete sendEmailOptions.transport.password; - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -462,7 +489,12 @@ describe('send_email module', () => { // @ts-expect-error delete sendEmailOptions.transport.password; - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -503,9 +535,9 @@ describe('send_email module', () => { sendMailMock.mockReset(); sendMailMock.mockRejectedValue(new Error('wops')); - await expect(sendEmail(mockLogger, sendEmailOptions, connectorTokenClient)).rejects.toThrow( - 'wops' - ); + await expect( + sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector) + ).rejects.toThrow('wops'); }); test('it bypasses with proxyBypassHosts when expected', async () => { @@ -526,7 +558,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -560,7 +597,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -596,7 +638,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -630,7 +677,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -667,7 +719,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); // note in the object below, the rejectUnauthenticated got set to false, @@ -710,7 +767,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); // in this case, rejectUnauthorized is true, as the custom host settings @@ -757,7 +819,12 @@ describe('send_email module', () => { } ); - const result = await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + const result = await sendEmail( + mockLogger, + sendEmailOptions, + connectorTokenClient, + connectorUsageCollector + ); expect(result).toBe(sendMailMockResult); expect(createTransportMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -791,7 +858,7 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); @@ -834,7 +901,7 @@ describe('send_email module', () => { 'Bearer clienttokentokentoken' ); - await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient); + await sendEmail(mockLogger, sendEmailOptions, connectorTokenClient, connectorUsageCollector); expect(createAxiosInstanceMock).toHaveBeenCalledTimes(1); expect(createAxiosInstanceMock).toHaveBeenCalledWith(); expect(mockAxiosInstanceInterceptor.response.use).toHaveBeenCalledTimes(1); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts index f3ab3bfa22c55..199d96f352389 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email.ts @@ -17,7 +17,11 @@ import { getNodeSSLOptions, getSSLSettingsFromConfig, } from '@kbn/actions-plugin/server/lib/get_node_ssl_options'; -import { ConnectorTokenClientContract, ProxySettings } from '@kbn/actions-plugin/server/types'; +import { + ConnectorUsageCollector, + ConnectorTokenClientContract, + ProxySettings, +} from '@kbn/actions-plugin/server/types'; import { getOAuthClientCredentialsAccessToken } from '@kbn/actions-plugin/server/lib/get_oauth_client_credentials_access_token'; import { AdditionalEmailServices } from '../../../common'; import { sendEmailGraphApi } from './send_email_graph_api'; @@ -66,7 +70,8 @@ export interface Content { export async function sendEmail( logger: Logger, options: SendEmailOptions, - connectorTokenClient: ConnectorTokenClientContract + connectorTokenClient: ConnectorTokenClientContract, + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { transport, content } = options; const { message, messageHTML } = content; @@ -74,9 +79,15 @@ export async function sendEmail( const renderedMessage = messageHTML ?? htmlFromMarkdown(logger, message); if (transport.service === AdditionalEmailServices.EXCHANGE) { - return await sendEmailWithExchange(logger, options, renderedMessage, connectorTokenClient); + return await sendEmailWithExchange( + logger, + options, + renderedMessage, + connectorTokenClient, + connectorUsageCollector + ); } else { - return await sendEmailWithNodemailer(logger, options, renderedMessage); + return await sendEmailWithNodemailer(logger, options, renderedMessage, connectorUsageCollector); } } @@ -85,7 +96,8 @@ export async function sendEmailWithExchange( logger: Logger, options: SendEmailOptions, messageHTML: string, - connectorTokenClient: ConnectorTokenClientContract + connectorTokenClient: ConnectorTokenClientContract, + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { transport, configurationUtilities, connectorId } = options; const { clientId, clientSecret, tenantId, oauthTokenUrl } = transport; @@ -155,6 +167,7 @@ export async function sendEmailWithExchange( }, logger, configurationUtilities, + connectorUsageCollector, axiosInstance ); } @@ -163,7 +176,8 @@ export async function sendEmailWithExchange( async function sendEmailWithNodemailer( logger: Logger, options: SendEmailOptions, - messageHTML: string + messageHTML: string, + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { transport, routing, content, configurationUtilities, hasAuth } = options; const { service } = transport; @@ -186,6 +200,7 @@ async function sendEmailWithNodemailer( // some deep properties, so need to use any here. const transportConfig = getTransportConfig(configurationUtilities, logger, transport, hasAuth); const nodemailerTransport = nodemailer.createTransport(transportConfig); + connectorUsageCollector.addRequestBodyBytes(undefined, email); const result = await nodemailerTransport.sendMail(email); if (service === JSON_TRANSPORT_SERVICE) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts index 03289b79c3004..6166082345243 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.test.ts @@ -14,7 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { CustomHostSettings } from '@kbn/actions-plugin/server/config'; -import { ProxySettings } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, ProxySettings } from '@kbn/actions-plugin/server/types'; import { sendEmailGraphApi } from './send_email_graph_api'; const createAxiosInstanceMock = axios.create as jest.Mock; @@ -28,6 +28,11 @@ describe('sendEmailGraphApi', () => { const configurationUtilities = actionsConfigMock.create(); test('email contains the proper message', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -38,7 +43,8 @@ describe('sendEmailGraphApi', () => { headers: {}, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); expect(axiosInstanceMock.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -118,6 +124,10 @@ describe('sendEmailGraphApi', () => { }); test('email was sent on behalf of the user "from" mailbox', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -128,7 +138,8 @@ describe('sendEmailGraphApi', () => { headers: { Authorization: 'Bearer 1234567' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); expect(axiosInstanceMock.mock.calls[1]).toMatchInlineSnapshot(` Array [ @@ -210,6 +221,10 @@ describe('sendEmailGraphApi', () => { }); test('sendMail request was sent to the custom configured Graph API URL', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 202, }); @@ -221,7 +236,8 @@ describe('sendEmailGraphApi', () => { headers: {}, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); expect(axiosInstanceMock.mock.calls[2]).toMatchInlineSnapshot(` Array [ @@ -301,6 +317,10 @@ describe('sendEmailGraphApi', () => { }); test('throw the exception and log the proper error if message was not sent successfuly', async () => { + const connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); axiosInstanceMock.mockReturnValueOnce({ status: 400, data: { @@ -315,7 +335,8 @@ describe('sendEmailGraphApi', () => { sendEmailGraphApi( { options: getSendEmailOptions(), messageHTML: 'test1', headers: {} }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).rejects.toThrowErrorMatchingInlineSnapshot( '"{\\"error\\":{\\"code\\":\\"ErrorMimeContentInvalidBase64String\\",\\"message\\":\\"Invalid base64 string for MIME content.\\"}}"' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts index 79d7af05e041e..ed624299b3535 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/email/send_email_graph_api.ts @@ -11,18 +11,14 @@ import axios, { AxiosInstance, AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { SendEmailOptions } from './send_email'; -interface SendEmailGraphApiOptions { - options: SendEmailOptions; - headers: Record; - messageHTML: string; -} - export async function sendEmailGraphApi( sendEmailOptions: SendEmailGraphApiOptions, logger: Logger, configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector, axiosInstance?: AxiosInstance ): Promise { const { options, headers, messageHTML } = sendEmailOptions; @@ -42,6 +38,7 @@ export async function sendEmailGraphApi( headers, configurationUtilities, validateStatus: () => true, + connectorUsageCollector, }); if (res.status === 202) { return res.data; @@ -53,6 +50,12 @@ export async function sendEmailGraphApi( throw new Error(errString); } +interface SendEmailGraphApiOptions { + options: SendEmailOptions; + headers: Record; + messageHTML: string; +} + function getMessage(emailOptions: SendEmailOptions, messageHTML: string) { const { routing, content } = emailOptions; const { to, cc, bcc } = routing; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts index 2b3fab30432fa..5b7353ef58291 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/es_index/index.test.ts @@ -7,6 +7,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { validateConfig, validateParams } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { ActionParamsType, @@ -27,11 +28,16 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: ESIndexConnectorType; let configurationUtilities: ActionsConfigurationUtilities; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.resetAllMocks(); configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { @@ -185,6 +191,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const scopedClusterClient = elasticsearchClientMock .createClusterClient() @@ -230,6 +237,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; scopedClusterClient.bulk.mockClear(); await connectorType.executor({ @@ -280,6 +288,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; scopedClusterClient.bulk.mockClear(); @@ -324,6 +333,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; scopedClusterClient.bulk.mockClear(); await connectorType.executor({ @@ -656,6 +666,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { @@ -695,6 +706,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { @@ -757,6 +769,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { @@ -824,6 +837,7 @@ describe('execute()', () => { services: { ...services, scopedClusterClient }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }) ).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts index d58cefe12f839..949ae0a6c1bd2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.test.ts @@ -15,6 +15,7 @@ import { RunApiResponseSchema, StreamingResponseSchema } from '../../../common/g import { DEFAULT_GEMINI_MODEL } from '../../../common/gemini/constants'; import { AxiosError } from 'axios'; import { Transform } from 'stream'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); jest.mock('@kbn/actions-plugin/server/sub_action_framework/helpers/validators', () => ({ @@ -61,6 +62,7 @@ describe('GeminiConnector', () => { mockRequest = connector.request = jest.fn().mockResolvedValue(defaultResponse); }); + const logger = loggingSystemMock.createLogger(); const connector = new GeminiConnector({ connector: { id: '1', type: '.gemini' }, configurationUtilities: actionsConfigMock.create(), @@ -84,14 +86,19 @@ describe('GeminiConnector', () => { client_x509_cert_url: '', }), }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); + let connectorUsageCollector: ConnectorUsageCollector; describe('Gemini', () => { beforeEach(() => { // @ts-ignore connector.request = mockRequest; + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('runApi', () => { @@ -101,33 +108,36 @@ describe('GeminiConnector', () => { model: DEFAULT_GEMINI_MODEL, }; - const response = await connector.runApi(runActionParams); + const response = await connector.runApi(runActionParams, connectorUsageCollector); // Assertions expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, - method: 'post', - data: JSON.stringify({ - messages: [ - { - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], - }, - ], - }, - ], - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + data: JSON.stringify({ + messages: [ + { + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + }, + ], + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', + }, + timeout: 60000, + responseSchema: RunApiResponseSchema, + signal: undefined, }, - timeout: 60000, - responseSchema: RunApiResponseSchema, - signal: undefined, - }); + connectorUsageCollector + ); expect(response).toEqual(connectorResponse); }); @@ -144,66 +154,72 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct parameters', async () => { - await connector.invokeAI(aiAssistantBody); + await connector.invokeAI(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, - method: 'post', - responseSchema: RunApiResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + responseSchema: RunApiResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + safety_settings: [ + { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, + ], + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - safety_settings: [ - { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, - ], - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal: undefined, + timeout: 60000, }, - signal: undefined, - timeout: 60000, - }); + connectorUsageCollector + ); }); it('signal and timeout is properly passed to runApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeAI({ ...aiAssistantBody, timeout, signal }); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, - method: 'post', - responseSchema: RunApiResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + await connector.invokeAI({ ...aiAssistantBody, timeout, signal }, connectorUsageCollector); + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:generateContent`, + method: 'post', + responseSchema: RunApiResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + safety_settings: [ + { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, + ], + }), + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - safety_settings: [ - { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, - ], - }), - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal, + timeout: 60000, }, - signal, - timeout: 60000, - }); + connectorUsageCollector + ); }); }); @@ -226,68 +242,77 @@ describe('GeminiConnector', () => { }; it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(aiAssistantBody); + await connector.invokeStream(aiAssistantBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + safety_settings: [ + { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, + ], + }), + responseType: 'stream', + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - safety_settings: [ - { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, - ], - }), - responseType: 'stream', - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal: undefined, + timeout: 60000, }, - signal: undefined, - timeout: 60000, - }); + connectorUsageCollector + ); }); it('signal and timeout is properly passed to streamApi', async () => { const signal = jest.fn(); const timeout = 60000; - await connector.invokeStream({ ...aiAssistantBody, timeout, signal }); - expect(mockRequest).toHaveBeenCalledWith({ - url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - contents: [ - { - role: 'user', - parts: [{ text: 'What is the capital of France?' }], + await connector.invokeStream( + { ...aiAssistantBody, timeout, signal }, + connectorUsageCollector + ); + expect(mockRequest).toHaveBeenCalledWith( + { + url: `https://api.gemini.com/v1/projects/my-project-12345/locations/us-central1/publishers/google/models/${DEFAULT_GEMINI_MODEL}:streamGenerateContent?alt=sse`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + contents: [ + { + role: 'user', + parts: [{ text: 'What is the capital of France?' }], + }, + ], + generation_config: { + temperature: 0, + maxOutputTokens: 8192, }, - ], - generation_config: { - temperature: 0, - maxOutputTokens: 8192, + safety_settings: [ + { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, + ], + }), + responseType: 'stream', + headers: { + Authorization: 'Bearer mock_access_token', + 'Content-Type': 'application/json', }, - safety_settings: [ - { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: 'BLOCK_ONLY_HIGH' }, - ], - }), - responseType: 'stream', - headers: { - Authorization: 'Bearer mock_access_token', - 'Content-Type': 'application/json', + signal, + timeout: 60000, }, - signal, - timeout: 60000, - }); + connectorUsageCollector + ); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts index 6cb4671b7aeeb..75f7458d3d6b3 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/gemini/gemini.ts @@ -11,7 +11,10 @@ import { PassThrough } from 'stream'; import { IncomingMessage } from 'http'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { getGoogleOAuthJwtAccessToken } from '@kbn/actions-plugin/server/lib/get_gcp_oauth_access_token'; -import { ConnectorTokenClientContract } from '@kbn/actions-plugin/server/types'; +import { + ConnectorUsageCollector, + ConnectorTokenClientContract, +} from '@kbn/actions-plugin/server/types'; import { HarmBlockThreshold, HarmCategory } from '@google/generative-ai'; import { @@ -211,13 +214,10 @@ export class GeminiConnector extends SubActionConnector { * @param body The stringified request body to be sent in the POST request. * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async runApi({ - body, - model: reqModel, - signal, - timeout, - raw, - }: RunActionParams): Promise { + public async runApi( + { body, model: reqModel, signal, timeout, raw }: RunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { // set model on per request basis const currentModel = reqModel ?? this.model; const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:generateContent`; @@ -236,7 +236,7 @@ export class GeminiConnector extends SubActionConnector { responseSchema: raw ? RunActionRawResponseSchema : RunApiResponseSchema, } as SubActionRequestParams; - const response = await this.request(requestArgs); + const response = await this.request(requestArgs, connectorUsageCollector); if (raw) { return response.data; @@ -249,65 +249,65 @@ export class GeminiConnector extends SubActionConnector { return { completion: completionText, usageMetadata }; } - private async streamAPI({ - body, - model: reqModel, - signal, - timeout, - }: RunActionParams): Promise { + private async streamAPI( + { body, model: reqModel, signal, timeout }: RunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { const currentModel = reqModel ?? this.model; const path = `/v1/projects/${this.gcpProjectID}/locations/${this.gcpRegion}/publishers/google/models/${currentModel}:streamGenerateContent?alt=sse`; const token = await this.getAccessToken(); - const response = await this.request({ - url: `${this.url}${path}`, - method: 'post', - responseSchema: StreamingResponseSchema, - data: body, - responseType: 'stream', - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', + const response = await this.request( + { + url: `${this.url}${path}`, + method: 'post', + responseSchema: StreamingResponseSchema, + data: body, + responseType: 'stream', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + signal, + timeout: timeout ?? DEFAULT_TIMEOUT_MS, }, - signal, - timeout: timeout ?? DEFAULT_TIMEOUT_MS, - }); + connectorUsageCollector + ); return response.data.pipe(new PassThrough()); } - public async invokeAI({ - messages, - model, - temperature = 0, - signal, - timeout, - }: InvokeAIActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify(formatGeminiPayload(messages, temperature)), - model, - signal, - timeout, - }); + public async invokeAI( + { messages, model, temperature = 0, signal, timeout }: InvokeAIActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify(formatGeminiPayload(messages, temperature)), + model, + signal, + timeout, + }, + connectorUsageCollector + ); return { message: res.completion, usageMetadata: res.usageMetadata }; } - public async invokeAIRaw({ - messages, - model, - temperature = 0, - signal, - timeout, - tools, - }: InvokeAIRawActionParams): Promise { - const res = await this.runApi({ - body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), - model, - signal, - timeout, - raw: true, - }); + public async invokeAIRaw( + { messages, model, temperature = 0, signal, timeout, tools }: InvokeAIRawActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = await this.runApi( + { + body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), + model, + signal, + timeout, + raw: true, + }, + connectorUsageCollector + ); return res; } @@ -320,22 +320,28 @@ export class GeminiConnector extends SubActionConnector { * @param messages An array of messages to be sent to the API * @param model Optional model to be used for the API request. If not provided, the default model from the connector will be used. */ - public async invokeStream({ - messages, - model, - stopSequences, - temperature = 0, - signal, - timeout, - tools, - }: InvokeAIActionParams): Promise { - return (await this.streamAPI({ - body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), + public async invokeStream( + { + messages, model, stopSequences, + temperature = 0, signal, timeout, - })) as unknown as IncomingMessage; + tools, + }: InvokeAIActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + return (await this.streamAPI( + { + body: JSON.stringify({ ...formatGeminiPayload(messages, temperature), tools }), + model, + stopSequences, + signal, + timeout, + }, + connectorUsageCollector + )) as unknown as IncomingMessage; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts index 630c0973935cd..1481ab8601fa6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/index.ts @@ -95,7 +95,15 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, configurationUtilities, logger } = execOptions; + const { + actionId, + config, + params, + secrets, + configurationUtilities, + logger, + connectorUsageCollector, + } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: JiraExecutorResultData | null = null; @@ -105,7 +113,8 @@ async function executor( secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts index 34e0f1f799ce5..5e98bdc96c0ee 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.test.ts @@ -14,6 +14,7 @@ import { Logger } from '@kbn/core/server'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; interface ResponseError extends Error { @@ -135,8 +136,13 @@ const mockOldAPI = () => describe('Jira service', () => { let service: ExternalService; + let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( { // The trailing slash at the end of the url is intended. @@ -145,7 +151,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); }); @@ -162,7 +169,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -175,7 +183,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -188,7 +197,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -201,7 +211,8 @@ describe('Jira service', () => { secrets: { email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -213,7 +224,8 @@ describe('Jira service', () => { secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); expect(axios.create).toHaveBeenCalledWith({ @@ -258,6 +270,7 @@ describe('Jira service', () => { url: 'https://coolsite.net/rest/api/2/issue/1', logger, configurationUtilities, + connectorUsageCollector, }); }); @@ -401,6 +414,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, + connectorUsageCollector, }); }); @@ -459,6 +473,7 @@ describe('Jira service', () => { priority: { name: 'High' }, }, }, + connectorUsageCollector, }); }); @@ -492,6 +507,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, + connectorUsageCollector, }); }); @@ -561,6 +577,7 @@ describe('Jira service', () => { ...otherFields, }, }, + connectorUsageCollector, }); }); }); @@ -631,6 +648,7 @@ describe('Jira service', () => { parent: { key: 'RJ-107' }, }, }, + connectorUsageCollector, }); }); @@ -693,6 +711,7 @@ describe('Jira service', () => { ...otherFields, }, }, + connectorUsageCollector, }); }); }); @@ -746,6 +765,7 @@ describe('Jira service', () => { configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/1/comment', data: { body: 'comment' }, + connectorUsageCollector, }); }); @@ -802,6 +822,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/capabilities', + connectorUsageCollector, }); }); @@ -883,6 +904,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields', + connectorUsageCollector, }); }); @@ -957,6 +979,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta/CK/issuetypes', + connectorUsageCollector, }); }); @@ -1032,6 +1055,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: 'https://coolsite.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields', + connectorUsageCollector, }); }); @@ -1240,6 +1264,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22Test%20title%22`, + connectorUsageCollector, }); }); @@ -1266,6 +1291,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/search?jql=project%3D%22CK%22%20and%20summary%20~%22%5C%5C%5Bth%5C%5C!s%5C%5C%5Eis%5C%5C(%5C%5C)a%5C%5C-te%5C%5C%2Bst%5C%5C-%5C%5C%7B%5C%5C~is%5C%5C*s%5C%5C%26ue%5C%5C%3For%5C%5C%7Cand%5C%5Cbye%5C%5C%3A%5C%5C%7D%5C%5C%5D%5C%5C%7D%5C%5C%5D%22`, + connectorUsageCollector, }); }); @@ -1344,6 +1370,7 @@ describe('Jira service', () => { method: 'get', configurationUtilities, url: `https://coolsite.net/rest/api/2/issue/RJ-107`, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts index 3cd5115234da1..064667558b37e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/jira/service.ts @@ -16,6 +16,7 @@ import { } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { getBasicAuthHeader } from '@kbn/actions-plugin/server'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { CreateCommentParams, CreateIncidentParams, @@ -47,7 +48,8 @@ const createMetaCapabilities = ['list-project-issuetypes', 'list-issuetype-field export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector ): ExternalService => { const { apiUrl: url, projectKey } = config as JiraPublicConfigurationType; const { apiToken, email } = secrets as JiraSecretConfigurationType; @@ -189,6 +191,7 @@ export const createExternalService = ( url: `${incidentUrl}/${id}`, logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -242,6 +245,7 @@ export const createExternalService = ( fields, }, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -288,6 +292,7 @@ export const createExternalService = ( logger, data: { fields }, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -326,6 +331,7 @@ export const createExternalService = ( logger, data: { body: comment.comment }, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -358,6 +364,7 @@ export const createExternalService = ( url: capabilitiesUrl, logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -389,6 +396,7 @@ export const createExternalService = ( url: getIssueTypesOldAPIURL, logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -404,6 +412,7 @@ export const createExternalService = ( url: getIssueTypesUrl, logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -436,6 +445,7 @@ export const createExternalService = ( url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsOldAPIURL, issueTypeId), logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -515,6 +525,7 @@ export const createExternalService = ( url: query, logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -543,6 +554,7 @@ export const createExternalService = ( url: getIssueUrl, logger, configurationUtilities, + connectorUsageCollector, }); throwIfResponseIsNotValid({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts index 311de65eb4abe..4f6133891c431 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.test.ts @@ -12,6 +12,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { connectorTokenClientMock } from '@kbn/actions-plugin/server/lib/connector_token_client.mock'; import { snExternalServiceConfig } from './config'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; const connectorTokenClient = connectorTokenClientMock.create(); @@ -19,10 +20,15 @@ const configurationUtilities = actionsConfigMock.create(); jest.mock('axios'); axios.create = jest.fn(() => axios); +let connectorUsageCollector: ConnectorUsageCollector; describe('createServiceWrapper', () => { beforeEach(() => { jest.clearAllMocks(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); test('creates axios instance with apiUrl', () => { @@ -45,6 +51,7 @@ describe('createServiceWrapper', () => { serviceConfig, connectorTokenClient, createServiceFn, + connectorUsageCollector, }); expect(createServiceFn).toHaveBeenCalledWith({ @@ -53,6 +60,7 @@ describe('createServiceWrapper', () => { configurationUtilities, serviceConfig, axiosInstance: axios, + connectorUsageCollector, }); }); @@ -76,6 +84,7 @@ describe('createServiceWrapper', () => { serviceConfig, connectorTokenClient, createServiceFn, + connectorUsageCollector, }); expect(createServiceFn).toHaveBeenCalledWith({ @@ -84,6 +93,7 @@ describe('createServiceWrapper', () => { configurationUtilities, serviceConfig, axiosInstance: axios, + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts index f2de6e3787f70..dbadbf66f8d5f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/create_service_wrapper.ts @@ -6,7 +6,10 @@ */ import { Logger } from '@kbn/core/server'; -import type { ConnectorTokenClientContract } from '@kbn/actions-plugin/server/types'; +import { + ConnectorUsageCollector, + ConnectorTokenClientContract, +} from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { ExternalService, ExternalServiceCredentials, SNProductsConfigValue } from './types'; @@ -21,6 +24,7 @@ interface CreateServiceWrapperOpts { serviceConfig: SNProductsConfigValue; connectorTokenClient: ConnectorTokenClientContract; createServiceFn: ServiceFactory; + connectorUsageCollector: ConnectorUsageCollector; } export function createServiceWrapper({ @@ -31,6 +35,7 @@ export function createServiceWrapper({ serviceConfig, connectorTokenClient, createServiceFn, + connectorUsageCollector, }: CreateServiceWrapperOpts): T { const { config } = credentials; const { apiUrl: url } = config as ServiceNowPublicConfigurationType; @@ -50,5 +55,6 @@ export function createServiceWrapper({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts index ce6f33e1cc0d1..aa8d248566d9a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from './mocks'; import { snExternalServiceConfig } from './config'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -178,6 +179,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -191,6 +193,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -199,14 +202,21 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }; describe('ServiceNow service', () => { let service: ExternalService; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.clearAllMocks(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); + service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. @@ -218,6 +228,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }); }); @@ -233,6 +244,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }) ).toThrow(); }); @@ -273,6 +285,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }) ).toThrow(); }); @@ -437,6 +450,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }) ).toThrow(); }); @@ -464,6 +478,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector, }); }); @@ -477,6 +492,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -490,6 +506,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); }); @@ -535,6 +552,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', + connectorUsageCollector, }); }); @@ -559,6 +577,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -572,6 +591,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', + connectorUsageCollector, }); }); @@ -625,6 +645,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorUsageCollector, }); const res = await createIncident(service); @@ -635,6 +656,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -644,6 +666,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -652,6 +675,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -707,6 +731,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_inc_int_elastic_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', foo: 'test' }, + connectorUsageCollector, }); }); }); @@ -723,6 +748,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); }); @@ -749,6 +775,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); }); @@ -762,6 +789,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -778,6 +806,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -826,6 +855,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorUsageCollector, }); const res = await updateIncident(service); @@ -835,6 +865,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -844,6 +875,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -852,6 +884,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -915,6 +948,7 @@ describe('ServiceNow service', () => { elastic_incident_id: '1', foo: 'test', }, + connectorUsageCollector, }); }); }); @@ -931,6 +965,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); }); @@ -958,6 +993,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); }); @@ -971,6 +1007,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -988,6 +1025,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -1032,6 +1070,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1040,6 +1079,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1054,6 +1094,7 @@ describe('ServiceNow service', () => { u_state: '7', u_close_notes: 'Closed by Caller', }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(4, { @@ -1062,6 +1103,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); @@ -1097,6 +1139,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident?sysparm_query=ORDERBYDESCsys_created_on^correlation_id=custom_correlation_id', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1105,6 +1148,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1119,6 +1163,7 @@ describe('ServiceNow service', () => { u_state: '7', u_close_notes: 'Closed by Caller', }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(4, { @@ -1127,6 +1172,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=incident.do?sys_id=1'); @@ -1237,6 +1283,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); }); @@ -1268,6 +1315,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -1285,6 +1333,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -1298,6 +1347,7 @@ describe('ServiceNow service', () => { state: '7', close_notes: 'Closed by Caller', }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -1306,6 +1356,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); expect(res?.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -1325,6 +1376,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorUsageCollector, }); }); @@ -1346,6 +1398,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -1358,6 +1411,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorUsageCollector, }); }); @@ -1394,6 +1448,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorUsageCollector, }); }); @@ -1415,6 +1470,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -1428,6 +1484,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorUsageCollector, }); }); @@ -1520,6 +1577,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts index 42aed9dcf8466..84a8592aaa832 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/service.ts @@ -37,6 +37,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }): ExternalService => { const { config, secrets } = credentials; const { table, importSetTable, useImportAPI, appScope } = serviceConfig; @@ -132,6 +133,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', + connectorUsageCollector, // TODO check if this is internal }); checkInstance(res); @@ -160,6 +162,7 @@ export const createExternalService: ServiceFactory = ({ logger, configurationUtilities, method: 'get', + connectorUsageCollector, }); checkInstance(res); @@ -178,6 +181,7 @@ export const createExternalService: ServiceFactory = ({ logger, params, configurationUtilities, + connectorUsageCollector, }); checkInstance(res); @@ -201,6 +205,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: prepareIncident(useTableApi, incident), configurationUtilities, + connectorUsageCollector, }); checkInstance(res); @@ -240,6 +245,7 @@ export const createExternalService: ServiceFactory = ({ ...(useTableApi ? {} : { elastic_incident_id: incidentId }), }, configurationUtilities, + connectorUsageCollector, }); checkInstance(res); @@ -272,6 +278,7 @@ export const createExternalService: ServiceFactory = ({ method: 'get', logger, configurationUtilities, + connectorUsageCollector, }); checkInstance(res); @@ -350,6 +357,7 @@ export const createExternalService: ServiceFactory = ({ url: fieldsUrl, logger, configurationUtilities, + connectorUsageCollector, }); checkInstance(res); @@ -367,6 +375,7 @@ export const createExternalService: ServiceFactory = ({ url: getChoicesURL(fields), logger, configurationUtilities, + connectorUsageCollector, }); checkInstance(res); return res.data.result; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts index 86d037c324e41..7cecf0bcddb46 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/lib/servicenow/types.ts @@ -11,7 +11,7 @@ import { AxiosError, AxiosInstance, AxiosResponse } from 'axios'; import { TypeOf } from '@kbn/config-schema'; import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; -import { ValidatorServices } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, ValidatorServices } from '@kbn/actions-plugin/server/types'; import { ExecutorParamsSchemaITSM, ExecutorSubActionCommonFieldsParamsSchema, @@ -305,6 +305,7 @@ interface ServiceFactoryOpts { configurationUtilities: ActionsConfigurationUtilities; serviceConfig: SNProductsConfigValue; axiosInstance: AxiosInstance; + connectorUsageCollector: ConnectorUsageCollector; } export type ServiceFactory = ({ @@ -313,6 +314,7 @@ export type ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }: ServiceFactoryOpts) => T; /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts index 6f0974fe1796d..87dacaf4e6f17 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/openai/openai.test.ts @@ -19,6 +19,7 @@ import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RunActionResponseSchema, StreamingResponseSchema } from '../../../common/openai/schema'; import { initDashboard } from '../lib/gen_ai/create_gen_ai_dashboard'; import { PassThrough, Transform } from 'stream'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('../lib/gen_ai/create_gen_ai_dashboard'); const mockTee = jest.fn(); @@ -46,6 +47,9 @@ jest.mock('openai', () => ({ describe('OpenAIConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; + let connectorUsageCollector: ConnectorUsageCollector; + + const logger = loggingSystemMock.createLogger(); const mockResponseString = 'Hello! How can I assist you today?'; const mockResponse = { headers: {}, @@ -72,6 +76,10 @@ describe('OpenAIConnector', () => { }, }; beforeEach(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); mockRequest = jest.fn().mockResolvedValue(mockResponse); mockError = jest.fn().mockImplementation(() => { throw new Error('API Error'); @@ -92,7 +100,7 @@ describe('OpenAIConnector', () => { }, }, secrets: { apiKey: '123' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); @@ -113,48 +121,74 @@ describe('OpenAIConnector', () => { describe('runApi', () => { it('uses the default model if none is supplied', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); it('overrides the default model with the default model specified in the body', async () => { const requestBody = { model: 'gpt-3.5-turbo', ...sampleOpenAiBody }; - const response = await connector.runApi({ body: JSON.stringify(requestBody) }); + const response = await connector.runApi( + { body: JSON.stringify(requestBody) }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...requestBody, stream: false }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ ...requestBody, stream: false }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); it('the OpenAI API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); @@ -168,25 +202,31 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.runApi({ - body: JSON.stringify({ - ...body, - stream: true, - }), - }); + const response = await connector.runApi( + { + body: JSON.stringify({ + ...body, + stream: true, + }), + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ - ...body, - stream: false, - }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...body, + stream: false, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); @@ -194,51 +234,71 @@ describe('OpenAIConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: JSON.stringify(sampleOpenAiBody) })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); }); describe('streamApi', () => { it('the OpenAI API call is successful with correct parameters when stream = false', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleOpenAiBody), - stream: false, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleOpenAiBody), + stream: false, + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: RunActionResponseSchema, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); it('the OpenAI API call is successful with correct parameters when stream = true', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleOpenAiBody), - stream: true, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleOpenAiBody), + stream: true, + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -255,29 +315,35 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.streamApi({ - body: JSON.stringify({ - ...body, - stream: false, - }), - stream: true, - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - ...body, + const response = await connector.streamApi( + { + body: JSON.stringify({ + ...body, + stream: false, + }), stream: true, - }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', }, - }); + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...body, + stream: true, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -289,7 +355,10 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.streamApi({ body: JSON.stringify(sampleOpenAiBody), stream: true }) + connector.streamApi( + { body: JSON.stringify(sampleOpenAiBody), stream: true }, + connectorUsageCollector + ) ).rejects.toThrow('API Error'); }); }); @@ -314,135 +383,181 @@ describe('OpenAIConnector', () => { }); it('the API call is successful with correct request parameters', async () => { - await connector.invokeStream(sampleOpenAiBody); + await connector.invokeStream(sampleOpenAiBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); }); it('signal is properly passed to streamApi', async () => { const signal = jest.fn(); - await connector.invokeStream({ ...sampleOpenAiBody, signal }); - - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', - }, - signal, - }); + await connector.invokeStream({ ...sampleOpenAiBody, signal }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + signal, + }, + connectorUsageCollector + ); }); it('timeout is properly passed to streamApi', async () => { const timeout = 180000; - await connector.invokeStream({ ...sampleOpenAiBody, timeout }); - - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://api.openai.com/v1/chat/completions', - method: 'post', - responseSchema: StreamingResponseSchema, - responseType: 'stream', - data: JSON.stringify({ ...sampleOpenAiBody, stream: true, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', - }, - timeout, - }); + await connector.invokeStream({ ...sampleOpenAiBody, timeout }, connectorUsageCollector); + + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://api.openai.com/v1/chat/completions', + method: 'post', + responseSchema: StreamingResponseSchema, + responseType: 'stream', + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: true, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + timeout, + }, + connectorUsageCollector + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeStream(sampleOpenAiBody)).rejects.toThrow('API Error'); + await expect( + connector.invokeStream(sampleOpenAiBody, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); it('responds with a readable stream', async () => { // @ts-ignore connector.request = mockStream(); - const response = await connector.invokeStream(sampleOpenAiBody); + const response = await connector.invokeStream(sampleOpenAiBody, connectorUsageCollector); expect(response instanceof PassThrough).toEqual(true); }); }); describe('invokeAI', () => { it('the API call is successful with correct parameters', async () => { - const response = await connector.invokeAI(sampleOpenAiBody); + const response = await connector.invokeAI(sampleOpenAiBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response.message).toEqual(mockResponseString); expect(response.usage.total_tokens).toEqual(9); }); it('signal is properly passed to runApi', async () => { const signal = jest.fn(); - await connector.invokeAI({ ...sampleOpenAiBody, signal }); + await connector.invokeAI({ ...sampleOpenAiBody, signal }, connectorUsageCollector); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + signal, }, - signal, - }); + connectorUsageCollector + ); }); it('timeout is properly passed to runApi', async () => { const timeout = 180000; - await connector.invokeAI({ ...sampleOpenAiBody, timeout }); + await connector.invokeAI({ ...sampleOpenAiBody, timeout }, connectorUsageCollector); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'X-My-Custom-Header': 'foo', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'X-My-Custom-Header': 'foo', + 'content-type': 'application/json', + }, + timeout, }, - timeout, - }); + connectorUsageCollector + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.invokeAI(sampleOpenAiBody)).rejects.toThrow('API Error'); + await expect(connector.invokeAI(sampleOpenAiBody, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); describe('invokeAsyncIterator', () => { it('the API call is successful with correct request parameters', async () => { - await connector.invokeAsyncIterator(sampleOpenAiBody); + await connector.invokeAsyncIterator(sampleOpenAiBody, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( { @@ -457,7 +572,10 @@ describe('OpenAIConnector', () => { it('signal and timeout is properly passed', async () => { const timeout = 180000; const signal = jest.fn(); - await connector.invokeAsyncIterator({ ...sampleOpenAiBody, signal, timeout }); + await connector.invokeAsyncIterator( + { ...sampleOpenAiBody, signal, timeout }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(0); expect(mockCreate).toHaveBeenCalledWith( { @@ -478,7 +596,9 @@ describe('OpenAIConnector', () => { throw new Error('API Error'); }); - await expect(connector.invokeAsyncIterator(sampleOpenAiBody)).rejects.toThrow('API Error'); + await expect( + connector.invokeAsyncIterator(sampleOpenAiBody, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); }); describe('getResponseErrorMessage', () => { @@ -568,16 +688,26 @@ describe('OpenAIConnector', () => { describe('runApi', () => { it('uses the default model if none is supplied', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleOpenAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleOpenAiBody) }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - data: JSON.stringify({ ...sampleOpenAiBody, stream: false, model: DEFAULT_OPENAI_MODEL }), - headers: { - Authorization: 'Bearer 123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + data: JSON.stringify({ + ...sampleOpenAiBody, + stream: false, + model: DEFAULT_OPENAI_MODEL, + }), + headers: { + Authorization: 'Bearer 123', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); }); @@ -614,17 +744,23 @@ describe('OpenAIConnector', () => { describe('runApi', () => { it('test the AzureAI API call is successful with correct parameters', async () => { - const response = await connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }); + const response = await connector.runApi( + { body: JSON.stringify(sampleAzureAiBody) }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); @@ -637,19 +773,25 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.runApi({ - body: JSON.stringify({ ...body, stream: true }), - }); + const response = await connector.runApi( + { + body: JSON.stringify({ ...body, stream: true }), + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - ...mockDefaults, - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + ...mockDefaults, + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); @@ -657,49 +799,61 @@ describe('OpenAIConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.runApi({ body: JSON.stringify(sampleAzureAiBody) })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.runApi({ body: JSON.stringify(sampleAzureAiBody) }, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); }); describe('streamApi', () => { it('the AzureAI API call is successful with correct parameters when stream = false', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleAzureAiBody), - stream: false, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleAzureAiBody), + stream: false, + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - method: 'post', - responseSchema: RunActionResponseSchema, - data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + method: 'post', + responseSchema: RunActionResponseSchema, + data: JSON.stringify({ ...sampleAzureAiBody, stream: false }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); it('the AzureAI API call is successful with correct parameters when stream = true', async () => { - const response = await connector.streamApi({ - body: JSON.stringify(sampleAzureAiBody), - stream: true, - }); + const response = await connector.streamApi( + { + body: JSON.stringify(sampleAzureAiBody), + stream: true, + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ ...sampleAzureAiBody, stream: true }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ ...sampleAzureAiBody, stream: true }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -715,25 +869,31 @@ describe('OpenAIConnector', () => { }, ], }; - const response = await connector.streamApi({ - body: JSON.stringify({ ...body, stream: false }), - stream: true, - }); - expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - responseType: 'stream', - url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', - method: 'post', - responseSchema: StreamingResponseSchema, - data: JSON.stringify({ - ...body, + const response = await connector.streamApi( + { + body: JSON.stringify({ ...body, stream: false }), stream: true, - }), - headers: { - 'api-key': '123', - 'content-type': 'application/json', }, - }); + connectorUsageCollector + ); + expect(mockRequest).toBeCalledTimes(1); + expect(mockRequest).toHaveBeenCalledWith( + { + responseType: 'stream', + url: 'https://My-test-resource-123.openai.azure.com/openai/deployments/NEW-DEPLOYMENT-321/chat/completions?api-version=2023-05-15', + method: 'post', + responseSchema: StreamingResponseSchema, + data: JSON.stringify({ + ...body, + stream: true, + }), + headers: { + 'api-key': '123', + 'content-type': 'application/json', + }, + }, + connectorUsageCollector + ); expect(response).toEqual({ headers: { 'Content-Type': 'dont-compress-this' }, ...mockResponse.data, @@ -745,7 +905,10 @@ describe('OpenAIConnector', () => { connector.request = mockError; await expect( - connector.streamApi({ body: JSON.stringify(sampleAzureAiBody), stream: true }) + connector.streamApi( + { body: JSON.stringify(sampleAzureAiBody), stream: true }, + connectorUsageCollector + ) ).rejects.toThrow('API Error'); }); }); 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 544b6bf7092c2..6cadc322a3d78 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 @@ -16,6 +16,7 @@ import { ChatCompletionMessageParam, } from 'openai/resources/chat/completions'; import { Stream } from 'openai/streaming'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { removeEndpointFromUrl } from './lib/openai_utils'; import { RunActionParamsSchema, @@ -156,7 +157,11 @@ export class OpenAIConnector extends SubActionConnector { * responsible for making a POST request to the external API endpoint and returning the response data * @param body The stringified request body to be sent in the POST request. */ - public async runApi({ body, signal, timeout }: RunActionParams): Promise { + + public async runApi( + { body, signal, timeout }: RunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { const sanitizedBody = sanitizeRequest( this.provider, this.url, @@ -164,20 +169,23 @@ export class OpenAIConnector extends SubActionConnector { ...('defaultModel' in this.config ? [this.config.defaultModel] : []) ); const axiosOptions = getAxiosOptions(this.provider, this.key, false); - const response = await this.request({ - url: this.url, - method: 'post', - responseSchema: RunActionResponseSchema, - data: sanitizedBody, - signal, - // give up to 2 minutes for response - timeout: timeout ?? DEFAULT_TIMEOUT_MS, - ...axiosOptions, - headers: { - ...this.config.headers, - ...axiosOptions.headers, + const response = await this.request( + { + url: this.url, + method: 'post', + responseSchema: RunActionResponseSchema, + data: sanitizedBody, + signal, + // give up to 2 minutes for response + timeout: timeout ?? DEFAULT_TIMEOUT_MS, + ...axiosOptions, + headers: { + ...this.config.headers, + ...axiosOptions.headers, + }, }, - }); + connectorUsageCollector + ); return response.data; } @@ -189,12 +197,10 @@ export class OpenAIConnector extends SubActionConnector { * @param body request body for the API request * @param stream flag indicating whether it is a streaming request or not */ - public async streamApi({ - body, - stream, - signal, - timeout, - }: StreamActionParams): Promise { + public async streamApi( + { body, stream, signal, timeout }: StreamActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { const executeBody = getRequestWithStreamOption( this.provider, this.url, @@ -205,19 +211,22 @@ export class OpenAIConnector extends SubActionConnector { const axiosOptions = getAxiosOptions(this.provider, this.key, stream); - const response = await this.request({ - url: this.url, - method: 'post', - responseSchema: stream ? StreamingResponseSchema : RunActionResponseSchema, - data: executeBody, - signal, - ...axiosOptions, - headers: { - ...this.config.headers, - ...axiosOptions.headers, + const response = await this.request( + { + url: this.url, + method: 'post', + responseSchema: stream ? StreamingResponseSchema : RunActionResponseSchema, + data: executeBody, + signal, + ...axiosOptions, + headers: { + ...this.config.headers, + ...axiosOptions.headers, + }, + timeout, }, - timeout, - }); + connectorUsageCollector + ); return stream ? pipeStreamingResponse(response) : response.data; } @@ -264,15 +273,21 @@ export class OpenAIConnector extends SubActionConnector { * returned directly to the client for streaming * @param body - the OpenAI Invoke request body */ - public async invokeStream(body: InvokeAIActionParams): Promise { + public async invokeStream( + body: InvokeAIActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { const { signal, timeout, ...rest } = body; - const res = (await this.streamApi({ - body: JSON.stringify(rest), - stream: true, - signal, - timeout, // do not default if not provided - })) as unknown as IncomingMessage; + const res = (await this.streamApi( + { + body: JSON.stringify(rest), + stream: true, + signal, + timeout, // do not default if not provided + }, + connectorUsageCollector + )) as unknown as IncomingMessage; return res.pipe(new PassThrough()); } @@ -286,7 +301,10 @@ export class OpenAIConnector extends SubActionConnector { * tokenCountStream: Stream; the result for token counting stream * } */ - public async invokeAsyncIterator(body: InvokeAIActionParams): Promise<{ + public async invokeAsyncIterator( + body: InvokeAIActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise<{ consumerStream: Stream; tokenCountStream: Stream; }> { @@ -301,6 +319,8 @@ export class OpenAIConnector extends SubActionConnector { rest.model ?? ('defaultModel' in this.config ? this.config.defaultModel : DEFAULT_OPENAI_MODEL), }; + + connectorUsageCollector.addRequestBodyBytes(undefined, requestBody); const stream = await this.openAI.chat.completions.create(requestBody, { signal, timeout, // do not default if not provided @@ -323,9 +343,15 @@ export class OpenAIConnector extends SubActionConnector { * @param body - the OpenAI chat completion request body * @returns an object with the response string and the usage object */ - public async invokeAI(body: InvokeAIActionParams): Promise { + public async invokeAI( + body: InvokeAIActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { const { signal, timeout, ...rest } = body; - const res = await this.runApi({ body: JSON.stringify(rest), signal, timeout }); + const res = await this.runApi( + { body: JSON.stringify(rest), signal, timeout }, + connectorUsageCollector + ); if (res.choices && res.choices.length > 0 && res.choices[0].message?.content) { const result = res.choices[0].message.content.trim(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts index fb11174e20ba5..821f2b3032661 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.test.ts @@ -15,6 +15,7 @@ import { MockedLogger } from '@kbn/logging-mocks'; import { OpsgenieConnectorTypeId } from '../../../common'; import { OpsgenieConnector } from './connector'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('axios'); @@ -36,6 +37,7 @@ describe('OpsgenieConnector', () => { let mockedActionsConfig: jest.Mocked; let logger: MockedLogger; let services: ReturnType; + let connectorUsageCollector: ConnectorUsageCollector; const defaultCreateAlertExpect = { method: 'post', @@ -75,36 +77,43 @@ describe('OpsgenieConnector', () => { logger, services, }); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); it('calls request with the correct arguments for creating an alert', async () => { - await connector.createAlert({ message: 'hello' }); + await connector.createAlert({ message: 'hello' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ data: { message: 'hello' }, ...ignoredRequestFields, ...defaultCreateAlertExpect, + connectorUsageCollector, }); }); it('calls request without modifying the alias when it is less than 512 characters when creating an alert', async () => { - await connector.createAlert({ message: 'hello', alias: '111' }); + await connector.createAlert({ message: 'hello', alias: '111' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: '111' }, + connectorUsageCollector, }); }); it('calls request without modifying the alias when it is equal to 512 characters when creating an alert', async () => { const alias = 'a'.repeat(512); - await connector.createAlert({ message: 'hello', alias }); + await connector.createAlert({ message: 'hello', alias }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias }, + connectorUsageCollector, }); }); @@ -114,12 +123,13 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.createAlert({ message: 'hello', alias }); + await connector.createAlert({ message: 'hello', alias }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...defaultCreateAlertExpect, data: { message: 'hello', alias: `sha-${sha256Hash.digest('hex')}` }, + connectorUsageCollector, }); }); @@ -129,22 +139,24 @@ describe('OpsgenieConnector', () => { const hasher = crypto.createHash('sha256'); const sha256Hash = hasher.update(alias); - await connector.closeAlert({ alias }); + await connector.closeAlert({ alias }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect(`sha-${sha256Hash.digest('hex')}`), data: {}, + connectorUsageCollector, }); }); it('calls request with the correct arguments for closing an alert', async () => { - await connector.closeAlert({ user: 'sam', alias: '111' }); + await connector.closeAlert({ user: 'sam', alias: '111' }, connectorUsageCollector); expect(requestMock.mock.calls[0][0]).toEqual({ ...ignoredRequestFields, ...createCloseAlertExpect('111'), data: { user: 'sam' }, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts index cd86a8ac7542a..0963ac720c80a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/connector.ts @@ -9,6 +9,7 @@ import crypto from 'crypto'; import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import { AxiosError } from 'axios'; import { isEmpty } from 'lodash'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { OpsgenieSubActions } from '../../../common'; import { CreateAlertParamsSchema, CloseAlertParamsSchema, Response } from './schema'; import { CloseAlertParams, Config, CreateAlertParams, FailureResponseType, Secrets } from './types'; @@ -67,14 +68,20 @@ export class OpsgenieConnector extends SubActionConnector { } } - public async createAlert(params: CreateAlertParams) { - const res = await this.request({ - method: 'post', - url: this.concatPathToURL('v2/alerts').toString(), - data: { ...params, ...OpsgenieConnector.createAliasObj(params.alias) }, - headers: this.createHeaders(), - responseSchema: Response, - }); + public async createAlert( + params: CreateAlertParams, + connectorUsageCollector: ConnectorUsageCollector + ) { + const res = await this.request( + { + method: 'post', + url: this.concatPathToURL('v2/alerts').toString(), + data: { ...params, ...OpsgenieConnector.createAliasObj(params.alias) }, + headers: this.createHeaders(), + responseSchema: Response, + }, + connectorUsageCollector + ); return res.data; } @@ -107,7 +114,10 @@ export class OpsgenieConnector extends SubActionConnector { return { Authorization: `GenieKey ${this.secrets.apiKey}` }; } - public async closeAlert(params: CloseAlertParams) { + public async closeAlert( + params: CloseAlertParams, + connectorUsageCollector: ConnectorUsageCollector + ) { const newAlias = OpsgenieConnector.createAlias(params.alias); const fullURL = this.concatPathToURL(`v2/alerts/${newAlias}/close`); @@ -115,13 +125,16 @@ export class OpsgenieConnector extends SubActionConnector { const { alias, ...paramsWithoutAlias } = params; - const res = await this.request({ - method: 'post', - url: fullURL.toString(), - data: paramsWithoutAlias, - headers: this.createHeaders(), - responseSchema: Response, - }); + const res = await this.request( + { + method: 'post', + url: fullURL.toString(), + data: paramsWithoutAlias, + headers: this.createHeaders(), + responseSchema: Response, + }, + connectorUsageCollector + ); return res.data; } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts index 86cdca4740f6d..38446eefe44f1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.test.ts @@ -10,7 +10,7 @@ import moment from 'moment'; jest.mock('./post_pagerduty', () => ({ postPagerduty: jest.fn(), })); -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateSecrets, validateParams } from '@kbn/actions-plugin/server/lib'; import { postPagerduty } from './post_pagerduty'; import { Logger } from '@kbn/core/server'; @@ -31,10 +31,15 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: PagerDutyConnectorType; let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('get()', () => { @@ -269,6 +274,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -350,6 +356,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -458,6 +465,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -535,6 +543,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -578,6 +587,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -608,6 +618,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -638,6 +649,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -668,6 +680,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); expect(actionResponse).toMatchInlineSnapshot(` @@ -708,6 +721,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -771,6 +785,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -837,6 +852,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; @@ -902,6 +918,7 @@ describe('execute()', () => { services, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }; const actionResponse = await connectorType.executor(executorOptions); const { apiUrl, data, headers } = postPagerdutyMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts index cfd11d6803df8..c4d2444540cad 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/index.ts @@ -198,8 +198,16 @@ function getPagerDutyApiUrl(config: ConnectorTypeConfigType): string { async function executor( execOptions: PagerDutyConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, secrets, params, services, configurationUtilities, logger } = - execOptions; + const { + actionId, + config, + secrets, + params, + services, + configurationUtilities, + logger, + connectorUsageCollector, + } = execOptions; const apiUrl = getPagerDutyApiUrl(config); const headers = { @@ -213,7 +221,8 @@ async function executor( response = await postPagerduty( { apiUrl, data, headers, services }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.pagerduty.postingErrorMessage', { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts index 0ef41637967d2..8b0937f9d857b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/pagerduty/post_pagerduty.ts @@ -7,7 +7,7 @@ import axios, { AxiosResponse } from 'axios'; import { Logger } from '@kbn/core/server'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; @@ -22,7 +22,8 @@ interface PostPagerdutyOptions { export async function postPagerduty( options: PostPagerdutyOptions, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { apiUrl, data, headers } = options; const axiosInstance = axios.create(); @@ -36,5 +37,6 @@ export async function postPagerduty( headers, configurationUtilities, validateStatus: () => true, + connectorUsageCollector, }); } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts index 4e031bdaafeea..6f3999dc70df7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.test.ts @@ -13,6 +13,7 @@ import { ResilientConnector } from './resilient'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { RESILIENT_CONNECTOR_ID } from './constants'; import { PushToServiceIncidentSchema } from './schema'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('axios'); jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { @@ -83,13 +84,15 @@ const mockIncidentUpdate = (withUpdateError = false) => { }) ); }; +let connectorUsageCollector: ConnectorUsageCollector; describe('IBM Resilient connector', () => { + const logger = loggingSystemMock.createLogger(); const connector = new ResilientConnector( { connector: { id: '1', type: RESILIENT_CONNECTOR_ID }, configurationUtilities: actionsConfigMock.create(), - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), config: { orgId, apiUrl }, secrets: { apiKeyId, apiKeySecret }, @@ -107,6 +110,10 @@ describe('IBM Resilient connector', () => { beforeEach(() => { jest.resetAllMocks(); jest.setSystemTime(TIMESTAMP); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('getIncident', () => { @@ -129,12 +136,12 @@ describe('IBM Resilient connector', () => { }); it('returns the incident correctly', async () => { - const res = await connector.getIncident({ id: '1' }); + const res = await connector.getIncident({ id: '1' }, connectorUsageCollector); expect(res).toEqual(incidentMock); }); it('should call request with correct arguments', async () => { - await connector.getIncident({ id: '1' }); + await connector.getIncident({ id: '1' }, connectorUsageCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, method: 'GET', @@ -147,6 +154,7 @@ describe('IBM Resilient connector', () => { params: { text_content_output_format: 'objects_convert', }, + connectorUsageCollector, }); }); @@ -154,7 +162,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getIncident({ id: '1' })).rejects.toThrow( + await expect(connector.getIncident({ id: '1' }, connectorUsageCollector)).rejects.toThrow( 'Unable to get incident with id 1. Error: An error has occurred' ); }); @@ -183,7 +191,7 @@ describe('IBM Resilient connector', () => { }); it('creates the incident correctly', async () => { - const res = await connector.createIncident(incidentMock); + const res = await connector.createIncident(incidentMock, connectorUsageCollector); expect(res).toEqual({ title: '1', @@ -194,7 +202,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.createIncident(incidentMock); + await connector.createIncident(incidentMock, connectorUsageCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -214,6 +222,7 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorUsageCollector, }); }); @@ -223,12 +232,15 @@ describe('IBM Resilient connector', () => { }); await expect( - connector.createIncident({ - name: 'title', - description: 'desc', - incidentTypes: [1001], - severityCode: 6, - }) + connector.createIncident( + { + name: 'title', + description: 'desc', + incidentTypes: [1001], + severityCode: 6, + }, + connectorUsageCollector + ) ).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: An error has occurred' ); @@ -237,7 +249,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.createIncident(incidentMock)).rejects.toThrow( + await expect(connector.createIncident(incidentMock, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create incident. Error: Response validation failed (Error: [id]: expected value of type [number] but got [undefined]).' ); }); @@ -255,7 +267,7 @@ describe('IBM Resilient connector', () => { }; it('updates the incident correctly', async () => { mockIncidentUpdate(); - const res = await connector.updateIncident(req); + const res = await connector.updateIncident(req, connectorUsageCollector); expect(res).toEqual({ title: '1', @@ -268,15 +280,18 @@ describe('IBM Resilient connector', () => { it('should call request with correct arguments', async () => { mockIncidentUpdate(); - await connector.updateIncident({ - incidentId: '1', - incident: { - name: 'title_updated', - description: 'desc_updated', - incidentTypes: [1001], - severityCode: 5, + await connector.updateIncident( + { + incidentId: '1', + incident: { + name: 'title_updated', + description: 'desc_updated', + incidentTypes: [1001], + severityCode: 5, + }, }, - }); + connectorUsageCollector + ); expect(requestMock.mock.calls[1][0]).toEqual({ ...ignoredRequestFields, @@ -332,13 +347,14 @@ describe('IBM Resilient connector', () => { }, ], }, + connectorUsageCollector, }); }); it('it should throw an error', async () => { mockIncidentUpdate(true); - await expect(connector.updateIncident(req)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: An error has occurred' ); }); @@ -361,7 +377,7 @@ describe('IBM Resilient connector', () => { ); requestMock.mockImplementation(() => createAxiosResponse({ data: { notRequired: 'test' } })); - await expect(connector.updateIncident(req)).rejects.toThrow( + await expect(connector.updateIncident(req, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to update incident with id 1. Error: Response validation failed (Error: [success]: expected value of type [boolean] but got [undefined]).' ); }); @@ -388,7 +404,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.addComment(req); + await connector.addComment(req, connectorUsageCollector); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -404,6 +420,7 @@ describe('IBM Resilient connector', () => { format: 'text', }, }, + connectorUsageCollector, }); }); @@ -412,7 +429,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.addComment(req)).rejects.toThrow( + await expect(connector.addComment(req, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to create comment at incident with id 1. Error: An error has occurred.' ); }); @@ -428,7 +445,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getIncidentTypes(); + await connector.getIncidentTypes(undefined, connectorUsageCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -439,11 +456,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorUsageCollector, }); }); it('returns incident types correctly', async () => { - const res = await connector.getIncidentTypes(); + const res = await connector.getIncidentTypes(undefined, connectorUsageCollector); expect(res).toEqual([ { id: '17', name: 'Communication error (fax; email)' }, @@ -456,7 +474,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getIncidentTypes()).rejects.toThrow( + await expect(connector.getIncidentTypes(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: An error has occurred.' ); }); @@ -466,7 +484,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '1001', name: 'Custom type' } }) ); - await expect(connector.getIncidentTypes()).rejects.toThrow( + await expect(connector.getIncidentTypes(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get incident types. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -484,7 +502,7 @@ describe('IBM Resilient connector', () => { }); it('should call request with correct arguments', async () => { - await connector.getSeverity(); + await connector.getSeverity(undefined, connectorUsageCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ ...ignoredRequestFields, @@ -495,11 +513,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorUsageCollector, }); }); it('returns severity correctly', async () => { - const res = await connector.getSeverity(); + const res = await connector.getSeverity(undefined, connectorUsageCollector); expect(res).toEqual([ { @@ -522,7 +541,7 @@ describe('IBM Resilient connector', () => { throw new Error('An error has occurred'); }); - await expect(connector.getSeverity()).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: An error has occurred.' ); }); @@ -532,7 +551,7 @@ describe('IBM Resilient connector', () => { createAxiosResponse({ data: { id: '10', name: 'Critical' } }) ); - await expect(connector.getSeverity()).rejects.toThrow( + await expect(connector.getSeverity(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get severity. Error: Response validation failed (Error: [values]: expected value of type [array] but got [undefined]).' ); }); @@ -547,7 +566,7 @@ describe('IBM Resilient connector', () => { ); }); it('should call request with correct arguments', async () => { - await connector.getFields(); + await connector.getFields(undefined, connectorUsageCollector); expect(requestMock).toBeCalledTimes(1); expect(requestMock).toHaveBeenCalledWith({ @@ -559,11 +578,12 @@ describe('IBM Resilient connector', () => { Authorization: `Basic ${token}`, 'Content-Type': 'application/json', }, + connectorUsageCollector, }); }); it('returns common fields correctly', async () => { - const res = await connector.getFields(); + const res = await connector.getFields(undefined, connectorUsageCollector); expect(res).toEqual(resilientFields); }); @@ -571,7 +591,7 @@ describe('IBM Resilient connector', () => { requestMock.mockImplementation(() => { throw new Error('An error has occurred'); }); - await expect(connector.getFields()).rejects.toThrow( + await expect(connector.getFields(undefined, connectorUsageCollector)).rejects.toThrow( 'Unable to get fields. Error: An error has occurred' ); }); @@ -579,7 +599,7 @@ describe('IBM Resilient connector', () => { it('should throw if the required attributes are not received in response', async () => { requestMock.mockImplementation(() => createAxiosResponse({ data: { someField: 'test' } })); - await expect(connector.getFields()).rejects.toThrow( + await expect(connector.getFields(undefined, connectorUsageCollector)).rejects.toThrow( '[Action][IBM Resilient]: Unable to get fields. Error: Response validation failed (Error: expected value of type [array] but got [Object]).' ); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts index 1351488dbf892..da297369ae024 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/resilient/resilient.ts @@ -10,6 +10,7 @@ import { omitBy, isNil } from 'lodash/fp'; import { CaseConnector, getBasicAuthHeader, ServiceParams } from '@kbn/actions-plugin/server'; import { schema, Type } from '@kbn/config-schema'; import { getErrorMessage } from '@kbn/actions-plugin/server/lib/axios_utils'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { CreateIncidentData, ExternalServiceIncidentResponse, @@ -117,7 +118,10 @@ export class ResilientConnector extends CaseConnector< return `${urlWithoutTrailingSlash}/${VIEW_INCIDENT_URL}/${key}`; } - public async createIncident(incident: Incident): Promise { + public async createIncident( + incident: Incident, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { try { let data: CreateIncidentData = { name: incident.name, @@ -150,19 +154,22 @@ export class ResilientConnector extends CaseConnector< }; } - const res = await this.request({ - url: `${this.urls.incident}?text_content_output_format=objects_convert`, - method: 'POST', - data, - headers: this.getAuthHeaders(), - responseSchema: schema.object( - { - id: schema.number(), - create_date: schema.number(), - }, - { unknowns: 'allow' } - ), - }); + const res = await this.request( + { + url: `${this.urls.incident}?text_content_output_format=objects_convert`, + method: 'POST', + data, + headers: this.getAuthHeaders(), + responseSchema: schema.object( + { + id: schema.number(), + create_date: schema.number(), + }, + { unknowns: 'allow' } + ), + }, + connectorUsageCollector + ); const { id, create_date: createDate } = res.data; @@ -179,30 +186,33 @@ export class ResilientConnector extends CaseConnector< } } - public async updateIncident({ - incidentId, - incident, - }: UpdateIncidentParams): Promise { + public async updateIncident( + { incidentId, incident }: UpdateIncidentParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { try { - const latestIncident = await this.getIncident({ id: incidentId }); + const latestIncident = await this.getIncident({ id: incidentId }, connectorUsageCollector); // Remove null or undefined values. Allowing null values sets the field in IBM Resilient to empty. const newIncident = omitBy(isNil, incident); const data = formatUpdateRequest({ oldIncident: latestIncident, newIncident }); - const res = await this.request({ - method: 'PATCH', - url: `${this.urls.incident}/${incidentId}`, - data, - headers: this.getAuthHeaders(), - responseSchema: schema.object({ success: schema.boolean() }, { unknowns: 'allow' }), - }); + const res = await this.request( + { + method: 'PATCH', + url: `${this.urls.incident}/${incidentId}`, + data, + headers: this.getAuthHeaders(), + responseSchema: schema.object({ success: schema.boolean() }, { unknowns: 'allow' }), + }, + connectorUsageCollector + ); if (!res.data.success) { throw new Error('Error while updating incident'); } - const updatedIncident = await this.getIncident({ id: incidentId }); + const updatedIncident = await this.getIncident({ id: incidentId }, connectorUsageCollector); return { title: `${updatedIncident.id}`, @@ -220,15 +230,21 @@ export class ResilientConnector extends CaseConnector< } } - public async addComment({ incidentId, comment }: { incidentId: string; comment: string }) { + public async addComment( + { incidentId, comment }: { incidentId: string; comment: string }, + connectorUsageCollector: ConnectorUsageCollector + ) { try { - await this.request({ - method: 'POST', - url: this.urls.comment.replace('{inc_id}', incidentId), - data: { text: { format: 'text', content: comment } }, - headers: this.getAuthHeaders(), - responseSchema: schema.object({}, { unknowns: 'allow' }), - }); + await this.request( + { + method: 'POST', + url: this.urls.comment.replace('{inc_id}', incidentId), + data: { text: { format: 'text', content: comment } }, + headers: this.getAuthHeaders(), + responseSchema: schema.object({}, { unknowns: 'allow' }), + }, + connectorUsageCollector + ); } catch (error) { throw new Error( getErrorMessage( @@ -239,17 +255,23 @@ export class ResilientConnector extends CaseConnector< } } - public async getIncident({ id }: { id: string }): Promise { + public async getIncident( + { id }: { id: string }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { try { - const res = await this.request({ - method: 'GET', - url: `${this.urls.incident}/${id}`, - params: { - text_content_output_format: 'objects_convert', + const res = await this.request( + { + method: 'GET', + url: `${this.urls.incident}/${id}`, + params: { + text_content_output_format: 'objects_convert', + }, + headers: this.getAuthHeaders(), + responseSchema: GetIncidentResponseSchema, }, - headers: this.getAuthHeaders(), - responseSchema: GetIncidentResponseSchema, - }); + connectorUsageCollector + ); return res.data; } catch (error) { @@ -259,14 +281,20 @@ export class ResilientConnector extends CaseConnector< } } - public async getIncidentTypes(): Promise { + public async getIncidentTypes( + params: unknown, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { try { - const res = await this.request({ - method: 'GET', - url: this.urls.incidentTypes, - headers: this.getAuthHeaders(), - responseSchema: GetIncidentTypesResponseSchema, - }); + const res = await this.request( + { + method: 'GET', + url: this.urls.incidentTypes, + headers: this.getAuthHeaders(), + responseSchema: GetIncidentTypesResponseSchema, + }, + connectorUsageCollector + ); const incidentTypes = res.data?.values ?? []; @@ -281,14 +309,20 @@ export class ResilientConnector extends CaseConnector< } } - public async getSeverity(): Promise { + public async getSeverity( + params: unknown, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { try { - const res = await this.request({ - method: 'GET', - url: this.urls.severity, - headers: this.getAuthHeaders(), - responseSchema: GetSeverityResponseSchema, - }); + const res = await this.request( + { + method: 'GET', + url: this.urls.severity, + headers: this.getAuthHeaders(), + responseSchema: GetSeverityResponseSchema, + }, + connectorUsageCollector + ); const severities = res.data?.values ?? []; return severities.map((type: { value: number; label: string }) => ({ @@ -302,14 +336,17 @@ export class ResilientConnector extends CaseConnector< } } - public async getFields() { + public async getFields(params: unknown, connectorUsageCollector: ConnectorUsageCollector) { try { - const res = await this.request({ - method: 'GET', - url: this.getIncidentFieldsUrl(), - headers: this.getAuthHeaders(), - responseSchema: GetCommonFieldsResponseSchema, - }); + const res = await this.request( + { + method: 'GET', + url: this.getIncidentFieldsUrl(), + headers: this.getAuthHeaders(), + responseSchema: GetCommonFieldsResponseSchema, + }, + connectorUsageCollector + ); const fields = res.data.map((field) => { return { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts index ced2784f057a6..8a13a48e47be1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.test.ts @@ -13,12 +13,20 @@ import { } from '../../../common/sentinelone/types'; import { API_PATH } from './sentinelone'; import { SentinelOneGetActivitiesResponseSchema } from '../../../common/sentinelone/schema'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; describe('SentinelOne Connector', () => { let connectorInstance: ReturnType; + let connectorUsageCollector: ConnectorUsageCollector; + const logger = loggingSystemMock.createLogger(); beforeEach(() => { connectorInstance = sentinelOneConnectorMocks.create(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('#fetchAgentFiles()', () => { @@ -35,15 +43,17 @@ describe('SentinelOne Connector', () => { it('should error if no agent id provided', async () => { fetchAgentFilesParams.agentId = ''; - await expect(connectorInstance.fetchAgentFiles(fetchAgentFilesParams)).rejects.toHaveProperty( - 'message', - "'agentId' parameter is required" - ); + await expect( + connectorInstance.fetchAgentFiles(fetchAgentFilesParams, connectorUsageCollector) + ).rejects.toHaveProperty('message', "'agentId' parameter is required"); }); it('should call SentinelOne fetch-files API with expected data', async () => { const fetchFilesUrl = `${connectorInstance.constructorParams.config.url}${API_PATH}/agents/${fetchAgentFilesParams.agentId}/actions/fetch-files`; - const response = await connectorInstance.fetchAgentFiles(fetchAgentFilesParams); + const response = await connectorInstance.fetchAgentFiles( + fetchAgentFilesParams, + connectorUsageCollector + ); expect(response).toEqual({ data: { success: true }, errors: null }); expect(connectorInstance.requestSpy).toHaveBeenLastCalledWith({ @@ -76,14 +86,14 @@ describe('SentinelOne Connector', () => { it('should error if called with invalid agent id', async () => { downloadAgentFileParams.agentId = ''; await expect( - connectorInstance.downloadAgentFile(downloadAgentFileParams) + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorUsageCollector) ).rejects.toHaveProperty('message', "'agentId' parameter is required"); }); it('should call SentinelOne api with expected url', async () => { - await expect(connectorInstance.downloadAgentFile(downloadAgentFileParams)).resolves.toEqual( - connectorInstance.mockResponses.downloadAgentFileApiResponse - ); + await expect( + connectorInstance.downloadAgentFile(downloadAgentFileParams, connectorUsageCollector) + ).resolves.toEqual(connectorInstance.mockResponses.downloadAgentFileApiResponse); }); }); @@ -122,7 +132,10 @@ describe('SentinelOne Connector', () => { describe('#downloadRemoteScriptResults()', () => { it('should call SentinelOne api to retrieve task results', async () => { - await connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }); + await connectorInstance.downloadRemoteScriptResults( + { taskId: 'task-123' }, + connectorUsageCollector + ); expect(connectorInstance.requestSpy).toHaveBeenCalledWith( expect.objectContaining({ @@ -136,13 +149,19 @@ describe('SentinelOne Connector', () => { connectorInstance.mockResponses.getRemoteScriptResults.data.download_links = []; await expect( - connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }) + connectorInstance.downloadRemoteScriptResults( + { taskId: 'task-123' }, + connectorUsageCollector + ) ).rejects.toThrow('Download URL for script results of task id [task-123] not found'); }); it('should return a Stream for downloading the file', async () => { await expect( - connectorInstance.downloadRemoteScriptResults({ taskId: 'task-123' }) + connectorInstance.downloadRemoteScriptResults( + { taskId: 'task-123' }, + connectorUsageCollector + ) ).resolves.toEqual(connectorInstance.mockResponses.downloadRemoteScriptResults); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index 99f486b44a087..dd73bafae8d2f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -8,6 +8,7 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { Stream } from 'stream'; import type { SentinelOneConfig, @@ -157,67 +158,94 @@ export class SentinelOneConnector extends SubActionConnector< }); } - public async fetchAgentFiles({ files, agentId, zipPassCode }: SentinelOneFetchAgentFilesParams) { + public async fetchAgentFiles( + { files, agentId, zipPassCode }: SentinelOneFetchAgentFilesParams, + connectorUsageCollector: ConnectorUsageCollector + ) { if (!agentId) { throw new Error(`'agentId' parameter is required`); } - return this.sentinelOneApiRequest({ - url: `${this.urls.agents}/${agentId}/actions/fetch-files`, - method: 'post', - data: { + return this.sentinelOneApiRequest( + { + url: `${this.urls.agents}/${agentId}/actions/fetch-files`, + method: 'post', data: { - password: zipPassCode, - files, + data: { + password: zipPassCode, + files, + }, }, + responseSchema: SentinelOneFetchAgentFilesResponseSchema, }, - responseSchema: SentinelOneFetchAgentFilesResponseSchema, - }); + connectorUsageCollector + ); } - public async downloadAgentFile({ agentId, activityId }: SentinelOneDownloadAgentFileParams) { + public async downloadAgentFile( + { agentId, activityId }: SentinelOneDownloadAgentFileParams, + connectorUsageCollector: ConnectorUsageCollector + ) { if (!agentId) { throw new Error(`'agentId' parameter is required`); } - return this.sentinelOneApiRequest({ - url: `${this.urls.agents}/${agentId}/uploads/${activityId}`, - method: 'get', - responseType: 'stream', - responseSchema: SentinelOneDownloadAgentFileResponseSchema, - }); + return this.sentinelOneApiRequest( + { + url: `${this.urls.agents}/${agentId}/uploads/${activityId}`, + method: 'get', + responseType: 'stream', + responseSchema: SentinelOneDownloadAgentFileResponseSchema, + }, + connectorUsageCollector + ); } - public async getActivities(queryParams?: SentinelOneGetActivitiesParams) { - return this.sentinelOneApiRequest({ - url: this.urls.activities, - method: 'get', - params: queryParams, - responseSchema: SentinelOneGetActivitiesResponseSchema, - }); + public async getActivities( + queryParams?: SentinelOneGetActivitiesParams, + connectorUsageCollector?: ConnectorUsageCollector + ) { + return this.sentinelOneApiRequest( + { + url: this.urls.activities, + method: 'get', + params: queryParams, + responseSchema: SentinelOneGetActivitiesResponseSchema, + }, + connectorUsageCollector! + ); } - public async executeScript({ filter, script }: SentinelOneExecuteScriptParams) { + public async executeScript( + { filter, script }: SentinelOneExecuteScriptParams, + connectorUsageCollector: ConnectorUsageCollector + ) { if (!filter.ids && !filter.uuids) { throw new Error(`A filter must be defined; either 'ids' or 'uuids'`); } - return this.sentinelOneApiRequest({ - url: this.urls.remoteScriptsExecute, - method: 'post', - data: { + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScriptsExecute, + method: 'post', data: { - outputDestination: 'SentinelCloud', - ...script, + data: { + outputDestination: 'SentinelCloud', + ...script, + }, + filter, }, - filter, + responseSchema: SentinelOneExecuteScriptResponseSchema, }, - responseSchema: SentinelOneExecuteScriptResponseSchema, - }); + connectorUsageCollector + ); } - public async isolateHost({ alertIds, ...payload }: SentinelOneIsolateHostParams) { - const response = await this.getAgents(payload); + public async isolateHost( + { alertIds, ...payload }: SentinelOneIsolateHostParams, + connectorUsageCollector: ConnectorUsageCollector + ) { + const response = await this.getAgents(payload, connectorUsageCollector); if (response.data.length === 0) { const errorMessage = 'No agents found'; @@ -233,20 +261,26 @@ export class SentinelOneConnector extends SubActionConnector< const agentId = response.data[0].id; - return this.sentinelOneApiRequest({ - url: this.urls.isolateHost, - method: 'post', - data: { - filter: { - ids: agentId, + return this.sentinelOneApiRequest( + { + url: this.urls.isolateHost, + method: 'post', + data: { + filter: { + ids: agentId, + }, }, + responseSchema: SentinelOneIsolateHostResponseSchema, }, - responseSchema: SentinelOneIsolateHostResponseSchema, - }); + connectorUsageCollector + ); } - public async releaseHost({ alertIds, ...payload }: SentinelOneIsolateHostParams) { - const response = await this.getAgents(payload); + public async releaseHost( + { alertIds, ...payload }: SentinelOneIsolateHostParams, + connectorUsageCollector: ConnectorUsageCollector + ) { + const response = await this.getAgents(payload, connectorUsageCollector); if (response.data.length === 0) { throw new Error('No agents found'); @@ -258,57 +292,76 @@ export class SentinelOneConnector extends SubActionConnector< const agentId = response.data[0].id; - return this.sentinelOneApiRequest({ - url: this.urls.releaseHost, - method: 'post', - data: { - filter: { - ids: agentId, + return this.sentinelOneApiRequest( + { + url: this.urls.releaseHost, + method: 'post', + data: { + filter: { + ids: agentId, + }, }, + responseSchema: SentinelOneIsolateHostResponseSchema, }, - responseSchema: SentinelOneIsolateHostResponseSchema, - }); + connectorUsageCollector + ); } public async getAgents( - payload: SentinelOneGetAgentsParams + payload: SentinelOneGetAgentsParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - return this.sentinelOneApiRequest({ - url: this.urls.agents, - params: { - ...payload, + return this.sentinelOneApiRequest( + { + url: this.urls.agents, + params: { + ...payload, + }, + responseSchema: SentinelOneGetAgentsResponseSchema, }, - responseSchema: SentinelOneGetAgentsResponseSchema, - }); + connectorUsageCollector + ); } public async getRemoteScriptStatus( - payload: SentinelOneGetRemoteScriptStatusParams + payload: SentinelOneGetRemoteScriptStatusParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - return this.sentinelOneApiRequest({ - url: this.urls.remoteScriptStatus, - params: { - parent_task_id: payload.parentTaskId, + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScriptStatus, + params: { + parent_task_id: payload.parentTaskId, + }, + responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, }, - responseSchema: SentinelOneGetRemoteScriptStatusResponseSchema, - }) as unknown as SentinelOneGetRemoteScriptStatusApiResponse; + connectorUsageCollector + ) as unknown as SentinelOneGetRemoteScriptStatusApiResponse; } - public async getRemoteScriptResults({ - taskIds, - }: SentinelOneGetRemoteScriptResultsParams): Promise { - return this.sentinelOneApiRequest({ - url: this.urls.remoteScriptsResults, - method: 'post', - data: { data: { taskIds } }, - responseSchema: SentinelOneGetRemoteScriptResultsResponseSchema, - }) as unknown as SentinelOneGetRemoteScriptResultsApiResponse; + public async getRemoteScriptResults( + { taskIds }: SentinelOneGetRemoteScriptResultsParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScriptsResults, + method: 'post', + data: { data: { taskIds } }, + responseSchema: SentinelOneGetRemoteScriptResultsResponseSchema, + }, + connectorUsageCollector + ) as unknown as SentinelOneGetRemoteScriptResultsApiResponse; } - public async downloadRemoteScriptResults({ - taskId, - }: SentinelOneDownloadRemoteScriptResultsParams): Promise { - const scriptResultsInfo = await this.getRemoteScriptResults({ taskIds: [taskId] }); + public async downloadRemoteScriptResults( + { taskId }: SentinelOneDownloadRemoteScriptResultsParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const scriptResultsInfo = await this.getRemoteScriptResults( + { taskIds: [taskId] }, + connectorUsageCollector + ); this.logger.debug( () => `script results for taskId [${taskId}]:\n${JSON.stringify(scriptResultsInfo)}` @@ -327,26 +380,33 @@ export class SentinelOneConnector extends SubActionConnector< throw new Error(`Download URL for script results of task id [${taskId}] not found`); } - const downloadConnection = await this.request({ - url: fileUrl, - method: 'get', - responseType: 'stream', - responseSchema: SentinelOneDownloadRemoteScriptResultsResponseSchema, - }); + const downloadConnection = await this.request( + { + url: fileUrl, + method: 'get', + responseType: 'stream', + responseSchema: SentinelOneDownloadRemoteScriptResultsResponseSchema, + }, + connectorUsageCollector + ); return downloadConnection.data; } private async sentinelOneApiRequest( - req: SubActionRequestParams + req: SubActionRequestParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - const response = await this.request({ - ...req, - params: { - ...req.params, - APIToken: this.secrets.token, + const response = await this.request( + { + ...req, + params: { + ...req.params, + APIToken: this.secrets.token, + }, }, - }); + connectorUsageCollector + ); return response.data; } @@ -374,15 +434,19 @@ export class SentinelOneConnector extends SubActionConnector< } public async getRemoteScripts( - payload: SentinelOneGetRemoteScriptsParams + payload: SentinelOneGetRemoteScriptsParams, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - return this.sentinelOneApiRequest({ - url: this.urls.remoteScripts, - params: { - limit: API_MAX_RESULTS, - ...payload, + return this.sentinelOneApiRequest( + { + url: this.urls.remoteScripts, + params: { + limit: API_MAX_RESULTS, + ...payload, + }, + responseSchema: SentinelOneGetRemoteScriptsResponseSchema, }, - responseSchema: SentinelOneGetRemoteScriptsResponseSchema, - }); + connectorUsageCollector + ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts index 082098023fc3f..29fd5d41adc26 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/server_log/index.test.ts @@ -6,6 +6,7 @@ */ import { validateParams } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { Logger } from '@kbn/core/server'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { getConnectorType, ServerLogConnectorType, ServerLogConnectorTypeExecutorOptions } from '.'; @@ -107,6 +108,10 @@ describe('execute()', () => { secrets: {}, configurationUtilities, logger: mockedLogger, + connectorUsageCollector: new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }), }; await connectorType.executor(executorOptions); expect(mockedLogger.info).toHaveBeenCalledWith('Server log: message text here'); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts index bbfaf902ba671..d32f52cd698ee 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/index.ts @@ -102,7 +102,15 @@ async function executorITOM( ExecutorParamsITOM > ): Promise> { - const { actionId, config, params, secrets, configurationUtilities, logger } = execOptions; + const { + actionId, + config, + params, + secrets, + configurationUtilities, + logger, + connectorUsageCollector, + } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = execOptions.services.connectorTokenClient; const externalServiceConfig = snExternalServiceConfig[actionTypeId]; @@ -119,6 +127,7 @@ async function executorITOM( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, + connectorUsageCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts index 01d8ed53478ca..951c2731b526d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { snExternalServiceConfig } from '../lib/servicenow/config'; import { itomEventParams, serviceNowChoices } from '../lib/servicenow/mocks'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -33,8 +34,13 @@ const configurationUtilities = actionsConfigMock.create(); describe('ServiceNow SIR service', () => { let service: ExternalServiceITOM; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, @@ -44,6 +50,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-itom'], axiosInstance: axios, + connectorUsageCollector, }) as ExternalServiceITOM; }); @@ -69,6 +76,7 @@ describe('ServiceNow SIR service', () => { url: 'https://example.com/api/global/em/jsonv2', method: 'post', data: { records: [itomEventParams] }, + connectorUsageCollector, }); }); }); @@ -85,6 +93,7 @@ describe('ServiceNow SIR service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=em_event^element=severity^language=en&sysparm_fields=label,value,dependent_value,element', + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts index e096b67de7ef4..a6ed020461194 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itom/service.ts @@ -23,6 +23,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }): ExternalServiceITOM => { const snService = createExternalServiceCommon({ credentials, @@ -30,6 +31,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }); const addEvent = async (params: ExecutorSubActionAddEventParams) => { @@ -41,6 +43,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data: { records: [params] }, configurationUtilities, + connectorUsageCollector, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts index 0322b0e341844..6ab6bc389ac7a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/index.ts @@ -125,8 +125,16 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, services, configurationUtilities, logger } = - execOptions; + const { + actionId, + config, + params, + secrets, + services, + configurationUtilities, + logger, + connectorUsageCollector, + } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; const externalServiceConfig = snExternalServiceConfig[actionTypeId]; @@ -143,6 +151,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, + connectorUsageCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts index 1c068dc60489d..5590da4cbfbd6 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_itsm/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { serviceNowCommonFields, serviceNowChoices } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; jest.mock('axios', () => ({ @@ -122,6 +123,7 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_inc_int/elastic_api/health', method: 'get', + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -135,6 +137,7 @@ const expectImportedIncident = (update: boolean) => { u_description: 'desc', ...(update ? { elastic_incident_id: '1' } : {}), }, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -143,14 +146,20 @@ const expectImportedIncident = (update: boolean) => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }; describe('ServiceNow service', () => { let service: ExternalService; + let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { jest.clearAllMocks(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { // The trailing slash at the end of the url is intended. @@ -162,6 +171,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }); }); @@ -177,6 +187,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }) ).toThrow(); }); @@ -217,6 +228,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }) ).toThrow(); }); @@ -381,6 +393,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow'], axiosInstance: axios, + connectorUsageCollector, }) ).toThrow(); }); @@ -408,6 +421,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/incident/1', method: 'get', + connectorUsageCollector, }); }); @@ -421,6 +435,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -434,6 +449,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); }); @@ -487,6 +503,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorUsageCollector, }); const res = await createIncident(service); @@ -497,6 +514,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -506,6 +524,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc' }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -514,6 +533,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -572,6 +592,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); }); @@ -596,6 +617,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); }); @@ -609,6 +631,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -624,6 +647,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident', method: 'post', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -660,6 +684,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorUsageCollector, }); const res = await updateIncident(service); @@ -669,6 +694,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(2, { @@ -678,6 +704,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/import/x_elas2_sir_int_elastic_si_incident', method: 'post', data: { u_short_description: 'title', u_description: 'desc', elastic_incident_id: '1' }, + connectorUsageCollector, }); expect(requestMock).toHaveBeenNthCalledWith(3, { @@ -686,6 +713,7 @@ describe('ServiceNow service', () => { configurationUtilities, url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'get', + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -747,6 +775,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); }); @@ -772,6 +801,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); }); @@ -785,6 +815,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow-sir'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); mockIncidentResponse(false); @@ -801,6 +832,7 @@ describe('ServiceNow service', () => { url: 'https://example.com/api/now/v2/table/sn_si_incident/1', method: 'patch', data: { short_description: 'title', description: 'desc' }, + connectorUsageCollector, }); expect(res.url).toEqual('https://example.com/nav_to.do?uri=sn_si_incident.do?sys_id=1'); @@ -820,6 +852,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorUsageCollector, }); }); @@ -841,6 +874,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -853,6 +887,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_dictionary?sysparm_query=name=task^ORname=sn_si_incident^internal_type=string&active=true&array=false&read_only=false&sysparm_fields=max_length,element,column_label,mandatory', + connectorUsageCollector, }); }); @@ -889,6 +924,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorUsageCollector, }); }); @@ -910,6 +946,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], table: 'sn_si_incident' }, axiosInstance: axios, + connectorUsageCollector, }); requestMock.mockImplementation(() => ({ @@ -923,6 +960,7 @@ describe('ServiceNow service', () => { logger, configurationUtilities, url: 'https://example.com/api/now/table/sys_choice?sysparm_query=name=task^ORname=sn_si_incident^element=priority^ORelement=category^language=en&sysparm_fields=label,value,dependent_value,element', + connectorUsageCollector, }); }); @@ -1015,6 +1053,7 @@ describe('ServiceNow service', () => { configurationUtilities, serviceConfig: { ...snExternalServiceConfig['.servicenow'], useImportAPI: false }, axiosInstance: axios, + connectorUsageCollector, }); await service.checkIfApplicationIsInstalled(); expect(requestMock).not.toHaveBeenCalled(); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts index d564d6bc79d62..8d842c6e6fccf 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/index.ts @@ -116,8 +116,16 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, services, configurationUtilities, logger } = - execOptions; + const { + actionId, + config, + params, + secrets, + services, + configurationUtilities, + logger, + connectorUsageCollector, + } = execOptions; const { subAction, subActionParams } = params; const connectorTokenClient = services.connectorTokenClient; const externalServiceConfig = snExternalServiceConfig[actionTypeId]; @@ -134,6 +142,7 @@ async function executor( serviceConfig: externalServiceConfig, connectorTokenClient, createServiceFn: createService, + connectorUsageCollector, }); const apiAsRecord = api as unknown as Record; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts index 97a0570eb50db..91eb7e4dcd7af 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.test.ts @@ -15,6 +15,7 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { observables } from '../lib/servicenow/mocks'; import { snExternalServiceConfig } from '../lib/servicenow/config'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -31,6 +32,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = utils.request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); +let connectorUsageCollector: ConnectorUsageCollector; const mockApplicationVersion = () => requestMock.mockImplementationOnce(() => ({ @@ -70,6 +72,7 @@ const expectAddObservables = (single: boolean) => { configurationUtilities, url: 'https://example.com/api/x_elas2_sir_int/elastic_api/health', method: 'get', + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); const url = single @@ -85,6 +88,7 @@ const expectAddObservables = (single: boolean) => { url, method: 'post', data, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }); }; @@ -92,6 +96,10 @@ describe('ServiceNow SIR service', () => { let service: ExternalServiceSIR; beforeEach(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService({ credentials: { config: { apiUrl: 'https://example.com/', isOAuth: false }, @@ -101,6 +109,7 @@ describe('ServiceNow SIR service', () => { configurationUtilities, serviceConfig: snExternalServiceConfig['.servicenow-sir'], axiosInstance: axios, + connectorUsageCollector, }) as ExternalServiceSIR; }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts index 69836a5b95e29..8fc7249c1d6a1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/servicenow_sir/service.ts @@ -28,6 +28,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }): ExternalServiceSIR => { const snService = createExternalServiceCommon({ credentials, @@ -35,6 +36,7 @@ export const createExternalService: ServiceFactory = ({ configurationUtilities, serviceConfig, axiosInstance, + connectorUsageCollector, }); const _addObservable = async (data: Observable | Observable[], url: string) => { @@ -47,6 +49,7 @@ export const createExternalService: ServiceFactory = ({ method: 'post', data, configurationUtilities, + connectorUsageCollector, }); snService.checkInstance(res); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts index 3f6203b725913..7d897ce5a3b77 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.test.ts @@ -9,6 +9,7 @@ import { Logger } from '@kbn/core/server'; import { Services, ActionTypeExecutorResult as ConnectorTypeExecutorResult, + ConnectorUsageCollector, } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { @@ -35,6 +36,7 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: SlackConnectorType; let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); @@ -43,6 +45,10 @@ beforeEach(() => { return { status: 'ok', actionId: options.actionId }; }, }); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { @@ -181,6 +187,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(response).toMatchInlineSnapshot(` Object { @@ -201,6 +208,7 @@ describe('execute()', () => { params: { message: 'failure: this invocation should fail' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"slack mockExecutor failure: this invocation should fail"` @@ -226,6 +234,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -252,6 +261,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -278,6 +288,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -304,6 +315,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.debug).toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' @@ -330,6 +342,7 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities: configUtils, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.debug).not.toHaveBeenCalledWith( 'IncomingWebhook was called with proxyUrl https://someproxyhost' diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts index 98573f98f2aa8..489d7c22b0286 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack/index.ts @@ -139,7 +139,8 @@ function validateConnectorTypeConfig( async function slackExecutor( execOptions: SlackConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger } = execOptions; + const { actionId, secrets, params, configurationUtilities, logger, connectorUsageCollector } = + execOptions; let result: IncomingWebhookResult; const { webhookUrl } = secrets; @@ -163,6 +164,7 @@ async function slackExecutor( const webhook = new IncomingWebhook(webhookUrl, { agent, }); + connectorUsageCollector.addRequestBodyBytes(undefined, { text: message }); result = await webhook.send(message); } catch (err) { if (err.original == null || err.original.response == null) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts index 59030a71aaa05..84e5b68a41c7e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.test.ts @@ -7,7 +7,7 @@ import axios from 'axios'; import { Logger } from '@kbn/core/server'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { getConnectorType } from '.'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; @@ -39,10 +39,15 @@ const headers = { let connectorType: SlackApiConnectorType; let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { @@ -198,6 +203,7 @@ describe('execute', () => { params: {} as PostMessageParams, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"[Action][ExternalService] -> [Slack API] Unsupported subAction type undefined."` @@ -296,6 +302,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -306,6 +313,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'some text' }, + connectorUsageCollector, }); expect(response).toEqual({ @@ -386,6 +394,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -396,6 +405,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'LKJHGF345', text: 'some text' }, + connectorUsageCollector, }); expect(response).toEqual({ @@ -476,6 +486,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -486,6 +497,7 @@ describe('execute', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'LKJHGF345', blocks: testBlock.blocks }, + connectorUsageCollector, }); expect(response).toEqual({ @@ -525,6 +537,7 @@ describe('execute', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(requestMock).toHaveBeenCalledWith({ @@ -534,6 +547,7 @@ describe('execute', () => { logger: mockedLogger, method: 'get', url: 'https://slack.com/api/conversations.info?channel=ZXCVBNM567', + connectorUsageCollector, }); expect(response).toEqual({ diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts index 35e85e98e6645..b816a1b014678 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/index.ts @@ -107,6 +107,7 @@ const slackApiExecutor = async ({ secrets, configurationUtilities, logger, + connectorUsageCollector, }: SlackApiExecutorOptions): Promise> => { const subAction = params.subAction; @@ -128,7 +129,8 @@ const slackApiExecutor = async ({ secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); if (subAction === 'validChannelId') { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts index 1389d4a98e9ec..936d4006006d1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.test.ts @@ -13,6 +13,7 @@ import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.moc import { createExternalService } from './service'; import { SlackApiService } from '../../../common/slack_api/types'; import { SLACK_API_CONNECTOR_ID } from '../../../common/slack_api/constants'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -28,6 +29,7 @@ jest.mock('@kbn/actions-plugin/server/lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = request as jest.Mock; const configurationUtilities = actionsConfigMock.create(); +let connectorUsageCollector: ConnectorUsageCollector; const channel = { id: 'channel_id_1', @@ -117,12 +119,17 @@ describe('Slack API service', () => { let service: SlackApiService; beforeAll(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( { secrets: { token: 'token' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); }); @@ -138,7 +145,8 @@ describe('Slack API service', () => { secrets: { token: '' }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrowErrorMatchingInlineSnapshot(`"[Action][Slack API]: Wrong configuration."`); }); @@ -172,6 +180,7 @@ describe('Slack API service', () => { configurationUtilities, method: 'get', url: 'https://slack.com/api/conversations.info?channel=channel_id_1', + connectorUsageCollector, }); }); @@ -207,6 +216,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', text: 'a message' }, + connectorUsageCollector, }); }); @@ -231,6 +241,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, + connectorUsageCollector, }); }); @@ -251,6 +262,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', text: 'a message' }, + connectorUsageCollector, }); }); @@ -291,6 +303,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'general', blocks: testBlock.blocks }, + connectorUsageCollector, }); }); @@ -315,6 +328,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, + connectorUsageCollector, }); }); @@ -338,6 +352,7 @@ describe('Slack API service', () => { method: 'post', url: 'https://slack.com/api/chat.postMessage', data: { channel: 'QWEERTYU987', blocks: testBlock.blocks }, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts index 28e9ee8be4b5d..7180b0982d92c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/slack_api/service.ts @@ -13,6 +13,7 @@ import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, getOrElse } from 'fp-ts/lib/Option'; import type { ActionTypeExecutorResult as ConnectorTypeExecutorResult } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { SLACK_CONNECTOR_NAME } from './translations'; import type { PostMessageSubActionParams, @@ -111,7 +112,8 @@ export const createExternalService = ( secrets: { token: string }; }, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector ): SlackApiService => { const { token } = secrets; const { allowedChannels } = config || { allowedChannels: [] }; @@ -139,6 +141,7 @@ export const createExternalService = ( method: 'get', headers, url: `${SLACK_URL}conversations.info?channel=${channelId}`, + connectorUsageCollector, }); }; if (channelId.length === 0) { @@ -207,6 +210,7 @@ export const createExternalService = ( data: { channel: channelToUse, text }, headers, configurationUtilities, + connectorUsageCollector, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); @@ -232,6 +236,7 @@ export const createExternalService = ( data: { channel: channelToUse, blocks: blockJson.blocks }, headers, configurationUtilities, + connectorUsageCollector, }); return buildSlackExecutorSuccessResponse({ slackApiResponseData: result.data }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts index d24febcccaad3..bbe53e86e068e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/index.ts @@ -76,7 +76,15 @@ async function executor( ExecutorParams > ): Promise> { - const { actionId, config, params, secrets, configurationUtilities, logger } = execOptions; + const { + actionId, + config, + params, + secrets, + configurationUtilities, + logger, + connectorUsageCollector, + } = execOptions; const { subAction, subActionParams } = params as ExecutorParams; let data: SwimlaneExecutorResultData | null = null; @@ -86,7 +94,8 @@ async function executor( secrets, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); if (!api[subAction]) { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts index 1aeee9c586fd5..5c04d60bed9c1 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.test.ts @@ -14,6 +14,7 @@ import { request, createAxiosResponse } from '@kbn/actions-plugin/server/lib/axi import { createExternalService } from './service'; import { mappings } from './mocks'; import { ExternalService } from './types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const logger = loggingSystemMock.create().get() as jest.Mocked; @@ -56,8 +57,13 @@ describe('Swimlane Service', () => { }; const url = config.apiUrl.slice(0, -1); + let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); service = createExternalService( { // The trailing slash at the end of the url is intended. @@ -66,7 +72,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); }); beforeEach(() => { @@ -87,7 +94,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -104,7 +112,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -122,7 +131,8 @@ describe('Swimlane Service', () => { secrets: { apiToken }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ) ).toThrow(); }); @@ -138,7 +148,8 @@ describe('Swimlane Service', () => { }, }, logger, - configurationUtilities + configurationUtilities, + connectorUsageCollector ); }).toThrow(); }); @@ -191,6 +202,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record`, method: 'post', configurationUtilities, + connectorUsageCollector, }); }); @@ -274,6 +286,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}`, method: 'patch', configurationUtilities, + connectorUsageCollector, }); }); @@ -353,6 +366,7 @@ describe('Swimlane Service', () => { url: `${url}/api/app/${config.appId}/record/${incidentId}/${mappings.commentsConfig.id}/comment`, method: 'post', configurationUtilities, + connectorUsageCollector, }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts index 42c4b65408f21..4abe7f08de5c5 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/swimlane/service.ts @@ -14,6 +14,7 @@ import { throwIfResponseIsNotValid, } from '@kbn/actions-plugin/server/lib/axios_utils'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { getBodyForEventAction } from './helpers'; import { CreateCommentParams, @@ -42,7 +43,8 @@ const createErrorMessage = (errorResponse: ResponseError | null | undefined): st export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector ): ExternalService => { const { apiUrl: url, appId, mappings } = config as SwimlanePublicConfigurationType; const { apiToken } = secrets as SwimlaneSecretConfigurationType; @@ -92,6 +94,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostRecordUrl(appId), + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -132,6 +135,7 @@ export const createExternalService = ( logger, method: 'patch', url: getPostRecordIdUrl(appId, params.incidentId), + connectorUsageCollector, }); throwIfResponseIsNotValid({ @@ -181,6 +185,7 @@ export const createExternalService = ( logger, method: 'post', url: getPostCommentUrl(appId, incidentId, fieldId), + connectorUsageCollector, }); /** diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts index 0b144bceb05c7..6b1b0cf105d9d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.test.ts @@ -6,7 +6,7 @@ */ import { Logger } from '@kbn/core/server'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import axios from 'axios'; import { getConnectorType, TeamsConnectorType, ConnectorTypeId } from '.'; @@ -34,10 +34,15 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: TeamsConnectorType; let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connector registration', () => { @@ -167,11 +172,42 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from teams action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": Object { "text": "this invocation should succeed", }, @@ -223,11 +259,42 @@ describe('execute()', () => { params: { message: 'this invocation should succeed' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from teams action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": Object { "text": "this invocation should succeed", }, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts index 84aa7449725c8..9ab0fe4d428d7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/teams/index.ts @@ -119,7 +119,8 @@ function validateConnectorTypeConfig( async function teamsExecutor( execOptions: TeamsConnectorTypeExecutorOptions ): Promise> { - const { actionId, secrets, params, configurationUtilities, logger } = execOptions; + const { actionId, secrets, params, configurationUtilities, logger, connectorUsageCollector } = + execOptions; const { webhookUrl } = secrets; const { message } = params; const data = { text: message }; @@ -134,6 +135,7 @@ async function teamsExecutor( logger, data, configurationUtilities, + connectorUsageCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts index 6218d48ae33fa..5972d5da570ef 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.test.ts @@ -18,17 +18,20 @@ import { PushToServiceIncidentSchema, } from '../../../common/thehive/schema'; import type { ExecutorSubActionCreateAlertParams, Incident } from '../../../common/thehive/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const mockTime = new Date('2024-04-03T09:10:30.000'); describe('TheHiveConnector', () => { + const logger = loggingSystemMock.createLogger(); + const connector = new TheHiveConnector( { configurationUtilities: actionsConfigMock.create(), connector: { id: '1', type: THEHIVE_CONNECTOR_ID }, config: { url: 'https://example.com', organisation: null }, secrets: { apiKey: 'test123' }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }, PushToServiceIncidentSchema @@ -36,6 +39,7 @@ describe('TheHiveConnector', () => { let mockRequest: jest.Mock; let mockError: jest.Mock; + let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { jest.useFakeTimers(); @@ -51,6 +55,10 @@ describe('TheHiveConnector', () => { throw new Error('API Error'); }); jest.clearAllMocks(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('createIncident', () => { @@ -124,18 +132,21 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.createIncident(incident); + const response = await connector.createIncident(incident, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case', - method: 'post', - responseSchema: TheHiveIncidentResponseSchema, - data: incident, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case', + method: 'post', + responseSchema: TheHiveIncidentResponseSchema, + data: incident, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual({ id: '~172064', url: 'https://example.com/cases/~172064/details', @@ -148,7 +159,9 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.createIncident(incident)).rejects.toThrow('API Error'); + await expect(connector.createIncident(incident, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); @@ -173,18 +186,24 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.updateIncident({ incidentId: '~172064', incident }); + const response = await connector.updateIncident( + { incidentId: '~172064', incident }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case/~172064', - method: 'patch', - responseSchema: TheHiveUpdateIncidentResponseSchema, - data: incident, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case/~172064', + method: 'patch', + responseSchema: TheHiveUpdateIncidentResponseSchema, + data: incident, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual({ id: '~172064', url: 'https://example.com/cases/~172064/details', @@ -197,9 +216,9 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.updateIncident({ incidentId: '~172064', incident })).rejects.toThrow( - 'API Error' - ); + await expect( + connector.updateIncident({ incidentId: '~172064', incident }, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); }); @@ -224,21 +243,27 @@ describe('TheHiveConnector', () => { }); it('TheHive API call is successful with correct parameters', async () => { - await connector.addComment({ - incidentId: '~172064', - comment: 'test comment', - }); + await connector.addComment( + { + incidentId: '~172064', + comment: 'test comment', + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case/~172064/comment', - method: 'post', - responseSchema: TheHiveAddCommentResponseSchema, - data: { message: 'test comment' }, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case/~172064/comment', + method: 'post', + responseSchema: TheHiveAddCommentResponseSchema, + data: { message: 'test comment' }, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorUsageCollector + ); }); it('errors during API calls are properly handled', async () => { @@ -246,7 +271,10 @@ describe('TheHiveConnector', () => { connector.request = mockError; await expect( - connector.addComment({ incidentId: '~172064', comment: 'test comment' }) + connector.addComment( + { incidentId: '~172064', comment: 'test comment' }, + connectorUsageCollector + ) ).rejects.toThrow('API Error'); }); }); @@ -314,16 +342,19 @@ describe('TheHiveConnector', () => { }); it('TheHive API call is successful with correct parameters', async () => { - const response = await connector.getIncident({ id: '~172064' }); + const response = await connector.getIncident({ id: '~172064' }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/case/~172064', - responseSchema: TheHiveIncidentResponseSchema, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/case/~172064', + responseSchema: TheHiveIncidentResponseSchema, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorUsageCollector + ); expect(response).toEqual(mockResponse.data); }); @@ -331,7 +362,9 @@ describe('TheHiveConnector', () => { // @ts-ignore connector.request = mockError; - await expect(connector.getIncident({ id: '~172064' })).rejects.toThrow('API Error'); + await expect( + connector.getIncident({ id: '~172064' }, connectorUsageCollector) + ).rejects.toThrow('API Error'); }); }); @@ -385,25 +418,30 @@ describe('TheHiveConnector', () => { }; it('TheHive API call is successful with correct parameters', async () => { - await connector.createAlert(alert); + await connector.createAlert(alert, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); - expect(mockRequest).toHaveBeenCalledWith({ - url: 'https://example.com/api/v1/alert', - method: 'post', - responseSchema: TheHiveCreateAlertResponseSchema, - data: alert, - headers: { - Authorization: 'Bearer test123', - 'X-Organisation': null, + expect(mockRequest).toHaveBeenCalledWith( + { + url: 'https://example.com/api/v1/alert', + method: 'post', + responseSchema: TheHiveCreateAlertResponseSchema, + data: alert, + headers: { + Authorization: 'Bearer test123', + 'X-Organisation': null, + }, }, - }); + connectorUsageCollector + ); }); it('errors during API calls are properly handled', async () => { // @ts-ignore connector.request = mockError; - await expect(connector.createAlert(alert)).rejects.toThrow('API Error'); + await expect(connector.createAlert(alert, connectorUsageCollector)).rejects.toThrow( + 'API Error' + ); }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts index fe0caf8788f28..623a9b8ee73d7 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/thehive/thehive.ts @@ -8,6 +8,7 @@ import { ServiceParams, CaseConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { Type } from '@kbn/config-schema'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { SUB_ACTION } from '../../../common/thehive/constants'; import { TheHiveIncidentResponseSchema, @@ -68,14 +69,20 @@ export class TheHiveConnector extends CaseConnector< return `API Error: ${error.response?.data?.type} - ${error.response?.data?.message}`; } - public async createIncident(incident: Incident): Promise { - const res = await this.request({ - method: 'post', - url: `${this.url}/api/${API_VERSION}/case`, - data: incident, - headers: this.getAuthHeaders(), - responseSchema: TheHiveIncidentResponseSchema, - }); + public async createIncident( + incident: Incident, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = await this.request( + { + method: 'post', + url: `${this.url}/api/${API_VERSION}/case`, + data: incident, + headers: this.getAuthHeaders(), + responseSchema: TheHiveIncidentResponseSchema, + }, + connectorUsageCollector + ); return { id: res.data._id, @@ -85,30 +92,42 @@ export class TheHiveConnector extends CaseConnector< }; } - public async addComment({ incidentId, comment }: { incidentId: string; comment: string }) { - await this.request({ - method: 'post', - url: `${this.url}/api/${API_VERSION}/case/${incidentId}/comment`, - data: { message: comment }, - headers: this.getAuthHeaders(), - responseSchema: TheHiveAddCommentResponseSchema, - }); + public async addComment( + { incidentId, comment }: { incidentId: string; comment: string }, + connectorUsageCollector: ConnectorUsageCollector + ) { + await this.request( + { + method: 'post', + url: `${this.url}/api/${API_VERSION}/case/${incidentId}/comment`, + data: { message: comment }, + headers: this.getAuthHeaders(), + responseSchema: TheHiveAddCommentResponseSchema, + }, + connectorUsageCollector + ); } - public async updateIncident({ - incidentId, - incident, - }: { - incidentId: string; - incident: Incident; - }): Promise { - await this.request({ - method: 'patch', - url: `${this.url}/api/${API_VERSION}/case/${incidentId}`, - data: incident, - headers: this.getAuthHeaders(), - responseSchema: TheHiveUpdateIncidentResponseSchema, - }); + public async updateIncident( + { + incidentId, + incident, + }: { + incidentId: string; + incident: Incident; + }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + await this.request( + { + method: 'patch', + url: `${this.url}/api/${API_VERSION}/case/${incidentId}`, + data: incident, + headers: this.getAuthHeaders(), + responseSchema: TheHiveUpdateIncidentResponseSchema, + }, + connectorUsageCollector + ); return { id: incidentId, @@ -118,23 +137,35 @@ export class TheHiveConnector extends CaseConnector< }; } - public async getIncident({ id }: { id: string }): Promise { - const res = await this.request({ - url: `${this.url}/api/${API_VERSION}/case/${id}`, - headers: this.getAuthHeaders(), - responseSchema: TheHiveIncidentResponseSchema, - }); + public async getIncident( + { id }: { id: string }, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + const res = await this.request( + { + url: `${this.url}/api/${API_VERSION}/case/${id}`, + headers: this.getAuthHeaders(), + responseSchema: TheHiveIncidentResponseSchema, + }, + connectorUsageCollector + ); return res.data; } - public async createAlert(alert: ExecutorSubActionCreateAlertParams) { - await this.request({ - method: 'post', - url: `${this.url}/api/${API_VERSION}/alert`, - data: alert, - headers: this.getAuthHeaders(), - responseSchema: TheHiveCreateAlertResponseSchema, - }); + public async createAlert( + alert: ExecutorSubActionCreateAlertParams, + connectorUsageCollector: ConnectorUsageCollector + ) { + await this.request( + { + method: 'post', + url: `${this.url}/api/${API_VERSION}/alert`, + data: alert, + headers: this.getAuthHeaders(), + responseSchema: TheHiveCreateAlertResponseSchema, + }, + connectorUsageCollector + ); } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts index b30a888f27998..6bbaad9b86a0c 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.test.ts @@ -12,6 +12,7 @@ import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { TinesConnector } from './tines'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { API_MAX_RESULTS, TINES_CONNECTOR_ID } from '../../../common/tines/constants'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; jest.mock('axios'); (axios as jest.Mocked).create.mockImplementation( @@ -78,6 +79,7 @@ const storiesGetRequestExpected = { 'Content-Type': 'application/json', }, params: { per_page: API_MAX_RESULTS }, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }; const agentsGetRequestExpected = { @@ -91,20 +93,28 @@ const agentsGetRequestExpected = { 'Content-Type': 'application/json', }, params: { story_id: story.id, per_page: API_MAX_RESULTS }, + connectorUsageCollector: expect.any(ConnectorUsageCollector), }; +let connectorUsageCollector: ConnectorUsageCollector; + describe('TinesConnector', () => { + const logger = loggingSystemMock.createLogger(); const connector = new TinesConnector({ configurationUtilities: actionsConfigMock.create(), config: { url }, connector: { id: '1', type: TINES_CONNECTOR_ID }, secrets: { email, token }, - logger: loggingSystemMock.createLogger(), + logger, services: actionsMock.createServices(), }); beforeEach(() => { jest.clearAllMocks(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger, + connectorId: 'test-connector-id', + }); }); describe('getStories', () => { @@ -113,13 +123,13 @@ describe('TinesConnector', () => { }); it('should request Tines stories', async () => { - await connector.getStories(); + await connector.getStories(undefined, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(storiesGetRequestExpected); }); it('should return the Tines stories reduced array', async () => { - const { stories } = await connector.getStories(); + const { stories } = await connector.getStories(undefined, connectorUsageCollector); expect(stories).toEqual([storyResult]); }); @@ -127,7 +137,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 1 } }, }); - const response = await connector.getStories(); + const response = await connector.getStories(undefined, connectorUsageCollector); expect(response.incompleteResponse).toEqual(false); }); @@ -135,7 +145,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { stories: [story], meta: { pages: 2 } }, }); - const response = await connector.getStories(); + const response = await connector.getStories(undefined, connectorUsageCollector); expect(response.incompleteResponse).toEqual(true); }); }); @@ -146,14 +156,17 @@ describe('TinesConnector', () => { }); it('should request Tines webhook actions', async () => { - await connector.getWebhooks({ storyId: story.id }); + await connector.getWebhooks({ storyId: story.id }, connectorUsageCollector); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith(agentsGetRequestExpected); }); it('should return the Tines webhooks reduced array', async () => { - const { webhooks } = await connector.getWebhooks({ storyId: story.id }); + const { webhooks } = await connector.getWebhooks( + { storyId: story.id }, + connectorUsageCollector + ); expect(webhooks).toEqual([webhookResult]); }); @@ -161,7 +174,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 1 } }, }); - const response = await connector.getWebhooks({ storyId: story.id }); + const response = await connector.getWebhooks({ storyId: story.id }, connectorUsageCollector); expect(response.incompleteResponse).toEqual(false); }); @@ -169,7 +182,7 @@ describe('TinesConnector', () => { mockRequest.mockReturnValueOnce({ data: { agents: [webhookAgent], meta: { pages: 2 } }, }); - const response = await connector.getWebhooks({ storyId: story.id }); + const response = await connector.getWebhooks({ storyId: story.id }, connectorUsageCollector); expect(response.incompleteResponse).toEqual(true); }); }); @@ -180,10 +193,13 @@ describe('TinesConnector', () => { }); it('should send data to Tines webhook using selected webhook parameter', async () => { - await connector.runWebhook({ - webhook: webhookResult, - body: '[]', - }); + await connector.runWebhook( + { + webhook: webhookResult, + body: '[]', + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith({ @@ -194,14 +210,18 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, + connectorUsageCollector, }); }); it('should send data to Tines webhook using webhook url parameter', async () => { - await connector.runWebhook({ - webhookUrl, - body: '[]', - }); + await connector.runWebhook( + { + webhookUrl, + body: '[]', + }, + connectorUsageCollector + ); expect(mockRequest).toBeCalledTimes(1); expect(mockRequest).toHaveBeenCalledWith({ @@ -212,6 +232,7 @@ describe('TinesConnector', () => { headers: { 'Content-Type': 'application/json', }, + connectorUsageCollector, }); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts index cb46a9abea3cc..ed98ec382af86 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/tines/tines.ts @@ -6,6 +6,7 @@ */ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { @@ -108,12 +109,16 @@ export class TinesConnector extends SubActionConnector( req: SubActionRequestParams, - reducer: (response: R) => T + reducer: (response: R) => T, + connectorUsageCollector: ConnectorUsageCollector ): Promise { - const response = await this.request({ - ...req, - params: { ...req.params, per_page: API_MAX_RESULTS }, - }); + const response = await this.request( + { + ...req, + params: { ...req.params, per_page: API_MAX_RESULTS }, + }, + connectorUsageCollector + ); return { ...reducer(response.data), incompleteResponse: response.data.meta.pages > 1, @@ -130,20 +135,25 @@ export class TinesConnector extends SubActionConnector { + public async getStories( + params: unknown, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { return this.tinesApiRequest( { url: this.urls.stories, headers: this.getAuthHeaders(), responseSchema: TinesStoriesApiResponseSchema, }, - storiesReducer + storiesReducer, + connectorUsageCollector ); } - public async getWebhooks({ - storyId, - }: TinesWebhooksActionParams): Promise { + public async getWebhooks( + { storyId }: TinesWebhooksActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { return this.tinesApiRequest( { url: this.urls.agents, @@ -151,24 +161,27 @@ export class TinesConnector extends SubActionConnector { + public async runWebhook( + { webhook, webhookUrl, body }: TinesRunActionParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { if (!webhook && !webhookUrl) { throw Error('Invalid subActionsParams: [webhook] or [webhookUrl] expected but got none'); } - const response = await this.request({ - url: webhookUrl ? webhookUrl : this.urls.getRunWebhookURL(webhook!), - method: 'post', - responseSchema: TinesRunApiResponseSchema, - data: body, - }); + const response = await this.request( + { + url: webhookUrl ? webhookUrl : this.urls.getRunWebhookURL(webhook!), + method: 'post', + responseSchema: TinesRunApiResponseSchema, + data: body, + }, + connectorUsageCollector + ); return response.data; } } diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap new file mode 100644 index 0000000000000..e8260c86f3e00 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/__snapshots__/index.test.ts.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`execute Torq action execute with token happy flow 1`] = ` +Object { + "axios": Any, + "connectorUsageCollector": Object { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from Torq action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, + "data": Object { + "msg": "some data", + }, + "headers": Object { + "Content-Type": "application/json", + "X-Torq-Token": "1234", + }, + "logger": Any, + "method": "post", + "url": "https://hooks.torq.io/v1/test", + "validateStatus": Any, +} +`; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts index 4bf60d10eb789..39bbdd44a918d 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.test.ts @@ -12,6 +12,7 @@ import { ActionTypeConfigType, getActionType, TorqActionType } from '.'; import * as utils from '@kbn/actions-plugin/server/lib/axios_utils'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; import { Services } from '@kbn/actions-plugin/server/types'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; @@ -37,10 +38,15 @@ const services: Services = actionsMock.createServices(); let actionType: TorqActionType; const mockedLogger: jest.Mocked = loggerMock.create(); let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeAll(() => { actionType = getActionType(); configurationUtilities = actionsConfigMock.create(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('actionType', () => { @@ -171,48 +177,29 @@ describe('execute Torq action', () => { params: { body: '{"msg": "some data"}' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; - expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` - Object { - "axios": [MockFunction], - "data": Object { - "msg": "some data", - }, - "headers": Object { - "Content-Type": "application/json", - "X-Torq-Token": "1234", + expect(requestMock.mock.calls[0][0]).toMatchSnapshot({ + axios: expect.any(Function), + connectorUsageCollector: { + usage: { + requestBodyBytes: 0, }, - "logger": Object { - "context": Array [], - "debug": [MockFunction] { - "calls": Array [ - Array [ - "response from Torq action \\"some-id\\": [HTTP 200] ", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], - }, - "method": "post", - "url": "https://hooks.torq.io/v1/test", - "validateStatus": [Function], - } - `); + }, + data: { + msg: 'some data', + }, + headers: { + 'Content-Type': 'application/json', + 'X-Torq-Token': '1234', + }, + logger: expect.any(Object), + method: 'post', + url: 'https://hooks.torq.io/v1/test', + validateStatus: expect.any(Function), + }); }); test('renders parameter templates as expected', async () => { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts index c3e7dc4f1533c..b60237dd7991e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/torq/index.ts @@ -146,6 +146,7 @@ export async function executor( const { webhookIntegrationUrl } = execOptions.config; const { body: data } = execOptions.params; const configurationUtilities = execOptions.configurationUtilities; + const connectorUsageCollector = execOptions.connectorUsageCollector; const secrets: ActionTypeSecretsType = execOptions.secrets; const token = secrets.token; @@ -171,6 +172,7 @@ export async function executor( configurationUtilities, logger: execOptions.logger, validateStatus: (status: number) => status >= 200 && status < 300, + connectorUsageCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap b/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap new file mode 100644 index 0000000000000..f52e34d90dbf0 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/__snapshots__/index.test.ts.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`execute() execute with username/password sends request with basic auth 1`] = ` +Object { + "axios": undefined, + "connectorUsageCollector": Object { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, + "data": "some data", + "headers": Object { + "Authorization": "Basic YWJjOjEyMw==", + "aheader": "a value", + }, + "logger": Any, + "method": "post", + "sslOverrides": Object {}, + "url": "https://abc.def/my-webhook", +} +`; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts index 6c51fe11e97de..724daa852019f 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateParams, validateSecrets } from '@kbn/actions-plugin/server/lib'; import { actionsConfigMock } from '@kbn/actions-plugin/server/actions_config.mock'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; @@ -41,10 +41,15 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: WebhookConnectorType; let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connectorType', () => { @@ -339,46 +344,27 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; - expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` - Object { - "axios": undefined, - "data": "some data", - "headers": Object { - "Authorization": "Basic YWJjOjEyMw==", - "aheader": "a value", - }, - "logger": Object { - "context": Array [], - "debug": [MockFunction] { - "calls": Array [ - Array [ - "response from webhook action \\"some-id\\": [HTTP 200] ", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "error": [MockFunction], - "fatal": [MockFunction], - "get": [MockFunction], - "info": [MockFunction], - "isLevelEnabled": [MockFunction], - "log": [MockFunction], - "trace": [MockFunction], - "warn": [MockFunction], + expect(requestMock.mock.calls[0][0]).toMatchSnapshot({ + axios: undefined, + connectorUsageCollector: { + usage: { + requestBodyBytes: 0, }, - "method": "post", - "sslOverrides": Object {}, - "url": "https://abc.def/my-webhook", - } - `); + }, + data: 'some data', + headers: { + Authorization: 'Basic YWJjOjEyMw==', + aheader: 'a value', + }, + logger: expect.any(Object), + method: 'post', + sslOverrides: {}, + url: 'https://abc.def/my-webhook', + }); }); test('execute with ssl adds ssl settings to sslOverrides', async () => { @@ -400,6 +386,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; @@ -407,6 +394,36 @@ describe('execute()', () => { expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": "some data", "headers": Object { "aheader": "a value", @@ -588,6 +605,7 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.error).toBeCalledWith( 'error on some-id webhook event: maxContentLength size of 1000000 exceeded' @@ -618,12 +636,43 @@ describe('execute()', () => { params: { body: 'some data' }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); delete requestMock.mock.calls[0][0].configurationUtilities; expect(requestMock.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "axios": undefined, + "connectorUsageCollector": ConnectorUsageCollector { + "connectorId": "test-connector-id", + "logger": Object { + "context": Array [], + "debug": [MockFunction] { + "calls": Array [ + Array [ + "response from webhook action \\"some-id\\": [HTTP 200] ", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "error": [MockFunction], + "fatal": [MockFunction], + "get": [MockFunction], + "info": [MockFunction], + "isLevelEnabled": [MockFunction], + "log": [MockFunction], + "trace": [MockFunction], + "warn": [MockFunction], + }, + "usage": Object { + "requestBodyBytes": 0, + }, + }, "data": "some data", "headers": Object { "aheader": "a value", diff --git a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts index 78f02d24b9b87..f7c7fd4f6d61e 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/webhook/index.ts @@ -128,7 +128,8 @@ function validateConnectorTypeConfig( export async function executor( execOptions: WebhookConnectorTypeExecutorOptions ): Promise> { - const { actionId, config, params, configurationUtilities, logger } = execOptions; + const { actionId, config, params, configurationUtilities, logger, connectorUsageCollector } = + execOptions; const { method, url, headers = {}, hasAuth, authType, ca, verificationMode } = config; const { body: data } = params; @@ -159,6 +160,7 @@ export async function executor( data, configurationUtilities, sslOverrides, + connectorUsageCollector, }) ); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts index 9205c3fef91c9..b357faffc8a0b 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.test.ts @@ -14,7 +14,7 @@ import { XmattersConnectorType, } from '.'; import { actionsMock } from '@kbn/actions-plugin/server/mocks'; -import { Services } from '@kbn/actions-plugin/server/types'; +import { ConnectorUsageCollector, Services } from '@kbn/actions-plugin/server/types'; import { validateConfig, validateConnector, @@ -45,10 +45,15 @@ const mockedLogger: jest.Mocked = loggerMock.create(); let connectorType: XmattersConnectorType; let configurationUtilities: jest.Mocked; +let connectorUsageCollector: ConnectorUsageCollector; beforeEach(() => { configurationUtilities = actionsConfigMock.create(); connectorType = getConnectorType(); + connectorUsageCollector = new ConnectorUsageCollector({ + logger: mockedLogger, + connectorId: 'test-connector-id', + }); }); describe('connectorType', () => { @@ -423,6 +428,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; @@ -472,6 +478,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); expect(mockedLogger.warn).toBeCalledWith( 'Error thrown triggering xMatters workflow: maxContentLength size of 1000000 exceeded' @@ -504,6 +511,7 @@ describe('execute()', () => { }, configurationUtilities, logger: mockedLogger, + connectorUsageCollector, }); const { method, url, headers, data } = requestMock.mock.calls[0][0]; diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts index 880c2278ca923..ad189bda9defb 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/index.ts @@ -8,7 +8,7 @@ import { isString } from 'lodash'; import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; -import type { +import { ActionType as ConnectorType, ActionTypeExecutorOptions as ConnectorTypeExecutorOptions, ActionTypeExecutorResult as ConnectorTypeExecutorResult, @@ -247,7 +247,8 @@ function validateConnectorTypeSecrets( export async function executor( execOptions: XmattersConnectorTypeExecutorOptions ): Promise> { - const { actionId, configurationUtilities, config, params, logger } = execOptions; + const { actionId, configurationUtilities, config, params, logger, connectorUsageCollector } = + execOptions; const { configUrl, usesBasic } = config; const data = getPayloadForRequest(params); @@ -263,7 +264,12 @@ export async function executor( if (!url) { throw new Error('Error: no url provided'); } - result = await postXmatters({ url, data, basicAuth }, logger, configurationUtilities); + result = await postXmatters( + { url, data, basicAuth }, + logger, + configurationUtilities, + connectorUsageCollector + ); } catch (err) { const message = i18n.translate('xpack.stackConnectors.xmatters.postingErrorMessage', { defaultMessage: 'Error triggering xMatters workflow', diff --git a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts index 2c2a08901cec3..215d1942c6e8a 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/xmatters/post_xmatters.ts @@ -10,6 +10,7 @@ import { Logger } from '@kbn/core/server'; import { ActionsConfigurationUtilities } from '@kbn/actions-plugin/server/actions_config'; import { request } from '@kbn/actions-plugin/server/lib/axios_utils'; import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; interface PostXmattersOptions { url: string; @@ -34,7 +35,8 @@ interface PostXmattersOptions { export async function postXmatters( options: PostXmattersOptions, logger: Logger, - configurationUtilities: ActionsConfigurationUtilities + configurationUtilities: ActionsConfigurationUtilities, + connectorUsageCollector: ConnectorUsageCollector ): Promise { const { url, data, basicAuth } = options; const axiosInstance = axios.create(); @@ -50,5 +52,6 @@ export async function postXmatters( data, configurationUtilities, validateStatus: () => true, + connectorUsageCollector, }); } diff --git a/x-pack/plugins/task_manager/server/config.test.ts b/x-pack/plugins/task_manager/server/config.test.ts index 59cd5c32cef4a..fa8c18207a692 100644 --- a/x-pack/plugins/task_manager/server/config.test.ts +++ b/x-pack/plugins/task_manager/server/config.test.ts @@ -14,6 +14,10 @@ describe('config validation', () => { Object { "allow_reading_invalid_state": true, "claim_strategy": "update_by_query", + "discovery": Object { + "active_nodes_lookback": "30s", + "interval": 10000, + }, "ephemeral_tasks": Object { "enabled": false, "request_capacity": 10, @@ -22,6 +26,7 @@ describe('config validation', () => { "monitor": true, "warn_threshold": 5000, }, + "kibanas_per_partition": 2, "max_attempts": 3, "metrics_reset_interval": 30000, "monitored_aggregated_stats_refresh_rate": 60000, @@ -71,6 +76,10 @@ describe('config validation', () => { Object { "allow_reading_invalid_state": true, "claim_strategy": "update_by_query", + "discovery": Object { + "active_nodes_lookback": "30s", + "interval": 10000, + }, "ephemeral_tasks": Object { "enabled": false, "request_capacity": 10, @@ -79,6 +88,7 @@ describe('config validation', () => { "monitor": true, "warn_threshold": 5000, }, + "kibanas_per_partition": 2, "max_attempts": 3, "metrics_reset_interval": 30000, "monitored_aggregated_stats_refresh_rate": 60000, @@ -126,6 +136,10 @@ describe('config validation', () => { Object { "allow_reading_invalid_state": true, "claim_strategy": "update_by_query", + "discovery": Object { + "active_nodes_lookback": "30s", + "interval": 10000, + }, "ephemeral_tasks": Object { "enabled": false, "request_capacity": 10, @@ -134,6 +148,7 @@ describe('config validation', () => { "monitor": true, "warn_threshold": 5000, }, + "kibanas_per_partition": 2, "max_attempts": 3, "metrics_reset_interval": 30000, "monitored_aggregated_stats_refresh_rate": 60000, @@ -252,4 +267,30 @@ describe('config validation', () => { const result = configSchema.validate({ claim_strategy: CLAIM_STRATEGY_MGET }); expect(result.poll_interval).toEqual(500); }); + + test('discovery active_nodes_lookback must be a valid duration', () => { + const config: Record = { + discovery: { + active_nodes_lookback: 'foo', + }, + }; + expect(() => { + configSchema.validate(config); + }).toThrowErrorMatchingInlineSnapshot( + `"[discovery.active_nodes_lookback]: active node lookback duration must be a valid duration string"` + ); + }); + + test('discovery active_nodes_lookback must be less than 5m', () => { + const config: Record = { + discovery: { + active_nodes_lookback: '301s', + }, + }; + expect(() => { + configSchema.validate(config); + }).toThrowErrorMatchingInlineSnapshot( + `"[discovery.active_nodes_lookback]: active node lookback duration cannot exceed five minutes"` + ); + }); }); diff --git a/x-pack/plugins/task_manager/server/config.ts b/x-pack/plugins/task_manager/server/config.ts index a1e210efa671d..db07494ef4f06 100644 --- a/x-pack/plugins/task_manager/server/config.ts +++ b/x-pack/plugins/task_manager/server/config.ts @@ -6,6 +6,7 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { parseIntervalAsMillisecond } from './lib/intervals'; export const MAX_WORKERS_LIMIT = 100; export const DEFAULT_CAPACITY = 10; @@ -32,6 +33,15 @@ export const DEFAULT_WORKER_UTILIZATION_RUNNING_AVERAGE_WINDOW = 5; export const CLAIM_STRATEGY_UPDATE_BY_QUERY = 'update_by_query'; export const CLAIM_STRATEGY_MGET = 'mget'; +export const DEFAULT_DISCOVERY_INTERVAL_MS = 1000 * 10; // 10 seconds +const MIN_DISCOVERY_INTERVAL_MS = 1000; // 1 second +const MAX_DISCOVERY_INTERVAL_MS = 1000 * 60 * 5; // 5 minutes + +export const DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION = '30s'; +const FIVE_MIN_IN_MS = 5 * 60 * 1000; + +export const DEFAULT_KIBANAS_PER_PARTITION = 2; + export const taskExecutionFailureThresholdSchema = schema.object( { error_threshold: schema.number({ @@ -70,6 +80,26 @@ export const configSchema = schema.object( allow_reading_invalid_state: schema.boolean({ defaultValue: true }), /* The number of normal cost tasks that this Kibana instance will run simultaneously */ capacity: schema.maybe(schema.number({ min: MIN_CAPACITY, max: MAX_CAPACITY })), + discovery: schema.object({ + active_nodes_lookback: schema.string({ + defaultValue: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + validate: (duration) => { + try { + const parsedDurationMs = parseIntervalAsMillisecond(duration); + if (parsedDurationMs > FIVE_MIN_IN_MS) { + return 'active node lookback duration cannot exceed five minutes'; + } + } catch (err) { + return 'active node lookback duration must be a valid duration string'; + } + }, + }), + interval: schema.number({ + defaultValue: DEFAULT_DISCOVERY_INTERVAL_MS, + min: MIN_DISCOVERY_INTERVAL_MS, + max: MAX_DISCOVERY_INTERVAL_MS, + }), + }), ephemeral_tasks: schema.object({ enabled: schema.boolean({ defaultValue: false }), /* How many requests can Task Manager buffer before it rejects new requests. */ @@ -81,6 +111,10 @@ export const configSchema = schema.object( }), }), event_loop_delay: eventLoopDelaySchema, + kibanas_per_partition: schema.number({ + defaultValue: DEFAULT_KIBANAS_PER_PARTITION, + min: 1, + }), /* The maximum number of times a task will be attempted before being abandoned as failed */ max_attempts: schema.number({ defaultValue: 3, diff --git a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts index 2a6f1bf8c33b8..100555e9ead4c 100644 --- a/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/ephemeral_task_lifecycle.test.ts @@ -45,6 +45,11 @@ describe('EphemeralTaskLifecycle', () => { definitions: new TaskTypeDictionary(taskManagerLogger), executionContext, config: { + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, max_attempts: 9, poll_interval: 6000000, version_conflict_threshold: 80, diff --git a/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts b/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts index a44584970e7b5..7e626c5853820 100644 --- a/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts +++ b/x-pack/plugins/task_manager/server/integration_tests/managed_configuration.test.ts @@ -43,6 +43,11 @@ describe('managed configuration', () => { clock = sinon.useFakeTimers(); const context = coreMock.createPluginInitializerContext({ + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, capacity: 10, max_attempts: 9, poll_interval: 3000, @@ -160,6 +165,11 @@ describe('managed configuration', () => { clock = sinon.useFakeTimers(); const context = coreMock.createPluginInitializerContext({ + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, capacity: 10, max_attempts: 9, poll_interval: 3000, @@ -280,6 +290,11 @@ describe('managed configuration', () => { clock = sinon.useFakeTimers(); const context = coreMock.createPluginInitializerContext({ + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, capacity: 10, max_attempts: 9, poll_interval: 3000, diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts index 2fe4684b10e90..7a0d9f0b11ce5 100644 --- a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.test.ts @@ -5,15 +5,12 @@ * 2.0. */ import { savedObjectsRepositoryMock, loggingSystemMock } from '@kbn/core/server/mocks'; -import { - KibanaDiscoveryService, - DISCOVERY_INTERVAL, - ACTIVE_NODES_LOOK_BACK, -} from './kibana_discovery_service'; +import { KibanaDiscoveryService } from './kibana_discovery_service'; import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; import { SavedObjectsBulkDeleteResponse, SavedObjectsUpdateResponse } from '@kbn/core/server'; import { createFindResponse, createFindSO } from './mock_kibana_discovery_service'; +import { DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, DEFAULT_DISCOVERY_INTERVAL_MS } from '../config'; const currentNode = 'current-node-id'; const now = '2024-08-10T10:00:00.000Z'; @@ -43,6 +40,10 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); await kibanaDiscoveryService.start(); @@ -68,6 +69,10 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); await kibanaDiscoveryService.start(); await kibanaDiscoveryService.start(); @@ -84,13 +89,21 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); await kibanaDiscoveryService.start(); expect(savedObjectsRepository.update).toHaveBeenCalledTimes(1); expect(setTimeout).toHaveBeenCalledTimes(1); - expect(setTimeout).toHaveBeenNthCalledWith(1, expect.any(Function), DISCOVERY_INTERVAL); + expect(setTimeout).toHaveBeenNthCalledWith( + 1, + expect.any(Function), + DEFAULT_DISCOVERY_INTERVAL_MS + ); jest.runOnlyPendingTimers(); @@ -104,6 +117,10 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); await kibanaDiscoveryService.start(); @@ -113,7 +130,11 @@ describe('KibanaDiscoveryService', () => { ); expect(logger.info).not.toHaveBeenCalled(); expect(setTimeout).toHaveBeenCalledTimes(1); - expect(setTimeout).toHaveBeenNthCalledWith(1, expect.any(Function), DISCOVERY_INTERVAL); + expect(setTimeout).toHaveBeenNthCalledWith( + 1, + expect.any(Function), + DEFAULT_DISCOVERY_INTERVAL_MS + ); }); it('reschedules when upsert fails after start', async () => { @@ -125,6 +146,10 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); await kibanaDiscoveryService.start(); @@ -133,7 +158,11 @@ describe('KibanaDiscoveryService', () => { expect(logger.info).toHaveBeenCalledWith('Kibana Discovery Service has been started'); expect(kibanaDiscoveryService.isStarted()).toBe(true); expect(setTimeout).toHaveBeenCalledTimes(1); - expect(setTimeout).toHaveBeenNthCalledWith(1, expect.any(Function), DISCOVERY_INTERVAL); + expect(setTimeout).toHaveBeenNthCalledWith( + 1, + expect.any(Function), + DEFAULT_DISCOVERY_INTERVAL_MS + ); savedObjectsRepository.update.mockRejectedValueOnce(new Error('foo')); @@ -141,7 +170,11 @@ describe('KibanaDiscoveryService', () => { expect(savedObjectsRepository.update).toHaveBeenCalledTimes(2); expect(setTimeout).toHaveBeenCalledTimes(2); - expect(setTimeout).toHaveBeenNthCalledWith(2, expect.any(Function), DISCOVERY_INTERVAL); + expect(setTimeout).toHaveBeenNthCalledWith( + 2, + expect.any(Function), + DEFAULT_DISCOVERY_INTERVAL_MS + ); expect(logger.error).toHaveBeenCalledTimes(1); expect(logger.error).toHaveBeenCalledWith( "Kibana Discovery Service couldn't update this node's last_seen timestamp. id: current-node-id, last_seen: 2024-08-10T10:00:10.000Z, error:foo" @@ -158,12 +191,16 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); const activeNodes = await kibanaDiscoveryService.getActiveKibanaNodes(); expect(savedObjectsRepository.find).toHaveBeenCalledWith({ - filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen > now-${ACTIVE_NODES_LOOK_BACK}`, + filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen > now-${DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION}`, page: 1, perPage: 10000, type: BACKGROUND_TASK_NODE_SO_NAME, @@ -180,6 +217,10 @@ describe('KibanaDiscoveryService', () => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); await kibanaDiscoveryService.deleteCurrentNode(); diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts index cde499122ab11..c532cb755f7d9 100644 --- a/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/kibana_discovery_service.ts @@ -9,8 +9,10 @@ import type { ISavedObjectsRepository } from '@kbn/core/server'; import { Logger } from '@kbn/core/server'; import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; import { BackgroundTaskNode } from '../saved_objects/schemas/background_task_node'; +import { TaskManagerConfig } from '../config'; interface DiscoveryServiceParams { + config: TaskManagerConfig['discovery']; currentNode: string; savedObjectsRepository: ISavedObjectsRepository; logger: Logger; @@ -21,16 +23,17 @@ interface DiscoveryServiceUpsertParams { lastSeen: string; } -export const DISCOVERY_INTERVAL = 1000 * 10; -export const ACTIVE_NODES_LOOK_BACK = '30s'; - export class KibanaDiscoveryService { + private readonly activeNodesLookBack: string; + private readonly discoveryInterval: number; private currentNode: string; private started = false; private savedObjectsRepository: ISavedObjectsRepository; private logger: Logger; - constructor({ currentNode, savedObjectsRepository, logger }: DiscoveryServiceParams) { + constructor({ config, currentNode, savedObjectsRepository, logger }: DiscoveryServiceParams) { + this.activeNodesLookBack = config.active_nodes_lookback; + this.discoveryInterval = config.interval; this.savedObjectsRepository = savedObjectsRepository; this.logger = logger; this.currentNode = currentNode; @@ -60,7 +63,7 @@ export class KibanaDiscoveryService { } catch (e) { if (!this.started) { this.logger.error( - `Kibana Discovery Service couldn't be started and will be retried in ${DISCOVERY_INTERVAL}ms, error:${e.message}` + `Kibana Discovery Service couldn't be started and will be retried in ${this.discoveryInterval}ms, error:${e.message}` ); } else { this.logger.error( @@ -70,7 +73,7 @@ export class KibanaDiscoveryService { } finally { setTimeout( async () => await this.scheduleUpsertCurrentNode(), - DISCOVERY_INTERVAL - (Date.now() - lastSeenDate.getTime()) + this.discoveryInterval - (Date.now() - lastSeenDate.getTime()) ); } } @@ -93,7 +96,7 @@ export class KibanaDiscoveryService { type: BACKGROUND_TASK_NODE_SO_NAME, perPage: 10000, page: 1, - filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen > now-${ACTIVE_NODES_LOOK_BACK}`, + filter: `${BACKGROUND_TASK_NODE_SO_NAME}.attributes.last_seen > now-${this.activeNodesLookBack}`, }); return activeNodes; diff --git a/x-pack/plugins/task_manager/server/kibana_discovery_service/mock_kibana_discovery_service.ts b/x-pack/plugins/task_manager/server/kibana_discovery_service/mock_kibana_discovery_service.ts index 39b98d29a149e..eb5956c6c5173 100644 --- a/x-pack/plugins/task_manager/server/kibana_discovery_service/mock_kibana_discovery_service.ts +++ b/x-pack/plugins/task_manager/server/kibana_discovery_service/mock_kibana_discovery_service.ts @@ -10,6 +10,7 @@ import { SavedObjectsFindResponse, SavedObjectsFindResult } from '@kbn/core/serv import { BackgroundTaskNode } from '../saved_objects/schemas/background_task_node'; import { BACKGROUND_TASK_NODE_SO_NAME } from '../saved_objects'; import { KibanaDiscoveryService } from './kibana_discovery_service'; +import { DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, DEFAULT_DISCOVERY_INTERVAL_MS } from '../config'; export const createDiscoveryServiceMock = (currentNode: string) => { const savedObjectsRepository = savedObjectsRepositoryMock.create(); @@ -18,6 +19,10 @@ export const createDiscoveryServiceMock = (currentNode: string) => { savedObjectsRepository, logger, currentNode, + config: { + active_nodes_lookback: DEFAULT_ACTIVE_NODES_LOOK_BACK_DURATION, + interval: DEFAULT_DISCOVERY_INTERVAL_MS, + }, }); for (const method of ['getActiveKibanaNodes'] as Array) { diff --git a/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.test.ts b/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.test.ts index f7bb5413fc0cd..953db750e7c4b 100644 --- a/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.test.ts +++ b/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.test.ts @@ -5,12 +5,17 @@ * 2.0. */ -import { assignPodPartitions, getParitionMap } from './assign_pod_partitions'; +import { DEFAULT_KIBANAS_PER_PARTITION } from '../config'; +import { assignPodPartitions, getPartitionMap } from './assign_pod_partitions'; describe('assignPodPartitions', () => { test('two pods', () => { const allPods = ['foo', 'bar']; const allPartitions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - const map = getParitionMap(allPods, allPartitions); + const map = getPartitionMap({ + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + podNames: allPods, + partitions: allPartitions, + }); expect(map).toMatchInlineSnapshot(` Object { "1": Array [ @@ -60,7 +65,11 @@ describe('assignPodPartitions', () => { test('three pods', () => { const allPods = ['foo', 'bar', 'quz']; const allPartitions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - const map = getParitionMap(allPods, allPartitions); + const map = getPartitionMap({ + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + podNames: allPods, + partitions: allPartitions, + }); expect(map).toMatchInlineSnapshot(` Object { "1": Array [ @@ -105,7 +114,12 @@ describe('assignPodPartitions', () => { ], } `); - const fooPartitions = assignPodPartitions('foo', allPods, allPartitions); + const fooPartitions = assignPodPartitions({ + podName: 'foo', + podNames: allPods, + partitions: allPartitions, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + }); expect(fooPartitions).toMatchInlineSnapshot(` Array [ 1, @@ -117,7 +131,12 @@ describe('assignPodPartitions', () => { 10, ] `); - const barPartitions = assignPodPartitions('bar', allPods, allPartitions); + const barPartitions = assignPodPartitions({ + podName: 'bar', + podNames: allPods, + partitions: allPartitions, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + }); expect(barPartitions).toMatchInlineSnapshot(` Array [ 1, @@ -129,7 +148,12 @@ describe('assignPodPartitions', () => { 10, ] `); - const quzPartitions = assignPodPartitions('quz', allPods, allPartitions); + const quzPartitions = assignPodPartitions({ + podName: 'quz', + podNames: allPods, + partitions: allPartitions, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + }); expect(quzPartitions).toMatchInlineSnapshot(` Array [ 2, diff --git a/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts b/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts index c2d5554b01f1b..8639edd048336 100644 --- a/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts +++ b/x-pack/plugins/task_manager/server/lib/assign_pod_partitions.ts @@ -5,26 +5,42 @@ * 2.0. */ -const KIBANAS_PER_PARTITION = 2; +interface GetPartitionMapOpts { + kibanasPerPartition: number; + partitions: number[]; + podNames: string[]; +} -export function getParitionMap(podNames: string[], partitions: number[]): Record { +export function getPartitionMap({ + kibanasPerPartition, + podNames, + partitions, +}: GetPartitionMapOpts): Record { const map: Record = {}; let counter = 0; - for (const parition of partitions) { - map[parition] = []; - for (let i = 0; i < KIBANAS_PER_PARTITION; i++) { - map[parition].push(podNames.sort()[counter++ % podNames.length]); + for (const partition of partitions) { + map[partition] = []; + for (let i = 0; i < kibanasPerPartition; i++) { + map[partition].push(podNames.sort()[counter++ % podNames.length]); } } return map; } -export function assignPodPartitions( - podName: string, - podNames: string[], - partitions: number[] -): number[] { - const map = getParitionMap(podNames, partitions); +interface AssignPodPartitionsOpts { + kibanasPerPartition: number; + podName: string; + podNames: string[]; + partitions: number[]; +} + +export function assignPodPartitions({ + kibanasPerPartition, + podName, + podNames, + partitions, +}: AssignPodPartitionsOpts): number[] { + const map = getPartitionMap({ kibanasPerPartition, podNames, partitions }); const podPartitions: number[] = []; for (const partition of Object.keys(map)) { if (map[Number(partition)].indexOf(podName) !== -1) { diff --git a/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts b/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts index 49c68459982ba..3943e94bdb8b3 100644 --- a/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts +++ b/x-pack/plugins/task_manager/server/lib/calculate_health_status.test.ts @@ -15,6 +15,11 @@ Date.now = jest.fn().mockReturnValue(new Date(now)); const logger = loggingSystemMock.create().get(); const config = { + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, enabled: true, index: 'foo', max_attempts: 9, diff --git a/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts b/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts index 8bab96f85dee5..891a55a4d2e52 100644 --- a/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts +++ b/x-pack/plugins/task_manager/server/lib/task_partitioner.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { DEFAULT_KIBANAS_PER_PARTITION } from '../config'; import { createDiscoveryServiceMock, createFindSO, @@ -16,7 +17,11 @@ const POD_NAME = 'test-pod'; describe('getAllPartitions()', () => { const discoveryServiceMock = createDiscoveryServiceMock(POD_NAME); test('correctly sets allPartitions in constructor', () => { - const taskPartitioner = new TaskPartitioner(POD_NAME, discoveryServiceMock); + const taskPartitioner = new TaskPartitioner({ + podName: POD_NAME, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + kibanaDiscoveryService: discoveryServiceMock, + }); expect(taskPartitioner.getAllPartitions()).toEqual([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, @@ -39,7 +44,11 @@ describe('getPodName()', () => { const discoveryServiceMock = createDiscoveryServiceMock(POD_NAME); test('correctly sets podName in constructor', () => { - const taskPartitioner = new TaskPartitioner(POD_NAME, discoveryServiceMock); + const taskPartitioner = new TaskPartitioner({ + podName: POD_NAME, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + kibanaDiscoveryService: discoveryServiceMock, + }); expect(taskPartitioner.getPodName()).toEqual('test-pod'); }); }); @@ -74,12 +83,20 @@ describe('getPartitions()', () => { }); test('correctly gets the partitons for this pod', async () => { - const taskPartitioner = new TaskPartitioner(POD_NAME, discoveryServiceMock); + const taskPartitioner = new TaskPartitioner({ + podName: POD_NAME, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + kibanaDiscoveryService: discoveryServiceMock, + }); expect(await taskPartitioner.getPartitions()).toEqual(expectedPartitions); }); test('correctly caches the partitions on 10 second interval', async () => { - const taskPartitioner = new TaskPartitioner(POD_NAME, discoveryServiceMock); + const taskPartitioner = new TaskPartitioner({ + podName: POD_NAME, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + kibanaDiscoveryService: discoveryServiceMock, + }); const shorterInterval = CACHE_INTERVAL / 2; await taskPartitioner.getPartitions(); @@ -94,8 +111,11 @@ describe('getPartitions()', () => { }); test('correctly catches the error from the discovery service and returns the cached value', async () => { - const taskPartitioner = new TaskPartitioner(POD_NAME, discoveryServiceMock); - + const taskPartitioner = new TaskPartitioner({ + podName: POD_NAME, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + kibanaDiscoveryService: discoveryServiceMock, + }); await taskPartitioner.getPartitions(); expect(taskPartitioner.getPodPartitions()).toEqual(expectedPartitions); diff --git a/x-pack/plugins/task_manager/server/lib/task_partitioner.ts b/x-pack/plugins/task_manager/server/lib/task_partitioner.ts index f0388ce19d966..ff1633911f62d 100644 --- a/x-pack/plugins/task_manager/server/lib/task_partitioner.ts +++ b/x-pack/plugins/task_manager/server/lib/task_partitioner.ts @@ -19,17 +19,24 @@ function range(start: number, end: number) { export const MAX_PARTITIONS = 256; export const CACHE_INTERVAL = 10000; +export interface TaskPartitionerConstructorOpts { + kibanaDiscoveryService: KibanaDiscoveryService; + kibanasPerPartition: number; + podName: string; +} export class TaskPartitioner { private readonly allPartitions: number[]; private readonly podName: string; + private readonly kibanasPerPartition: number; private kibanaDiscoveryService: KibanaDiscoveryService; private podPartitions: number[]; private podPartitionsLastUpdated: number; - constructor(podName: string, kibanaDiscoveryService: KibanaDiscoveryService) { + constructor(opts: TaskPartitionerConstructorOpts) { this.allPartitions = range(0, MAX_PARTITIONS); - this.podName = podName; - this.kibanaDiscoveryService = kibanaDiscoveryService; + this.podName = opts.podName; + this.kibanasPerPartition = opts.kibanasPerPartition; + this.kibanaDiscoveryService = opts.kibanaDiscoveryService; this.podPartitions = []; this.podPartitionsLastUpdated = Date.now() - CACHE_INTERVAL; } @@ -54,7 +61,12 @@ export class TaskPartitioner { if (now - lastUpdated >= CACHE_INTERVAL) { try { const allPodNames = await this.getAllPodNames(); - this.podPartitions = assignPodPartitions(this.podName, allPodNames, this.allPartitions); + this.podPartitions = assignPodPartitions({ + kibanasPerPartition: this.kibanasPerPartition, + podName: this.podName, + podNames: allPodNames, + partitions: this.allPartitions, + }); this.podPartitionsLastUpdated = now; } catch (error) { // return the cached value diff --git a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts index b1cf9a90b6cb6..b39e1b3168731 100644 --- a/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts +++ b/x-pack/plugins/task_manager/server/metrics/create_aggregator.test.ts @@ -35,6 +35,11 @@ import { TaskOverdueMetric, TaskOverdueMetricsAggregator } from './task_overdue_ const logger = loggingSystemMock.createLogger(); const mockMetricsAggregator = metricsAggregatorMock.create(); const config: TaskManagerConfig = { + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, allow_reading_invalid_state: false, ephemeral_tasks: { enabled: true, diff --git a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts index 0b5387b66dece..a169c9dad8fe5 100644 --- a/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/configuration_statistics.test.ts @@ -13,6 +13,11 @@ import { TaskManagerConfig } from '../config'; describe('Configuration Statistics Aggregator', () => { test('merges the static config with the merged configs', async () => { const configuration: TaskManagerConfig = { + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, max_attempts: 9, poll_interval: 6000000, allow_reading_invalid_state: false, diff --git a/x-pack/plugins/task_manager/server/plugin.test.ts b/x-pack/plugins/task_manager/server/plugin.test.ts index acad060106112..96269f58158df 100644 --- a/x-pack/plugins/task_manager/server/plugin.test.ts +++ b/x-pack/plugins/task_manager/server/plugin.test.ts @@ -49,6 +49,11 @@ const pluginInitializerContextParams = { version_conflict_threshold: 80, request_capacity: 1000, allow_reading_invalid_state: false, + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, monitored_aggregated_stats_refresh_rate: 5000, monitored_stats_health_verbose_log: { enabled: false, diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index 44e750b17d9d6..a746d8a9c3580 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -259,6 +259,7 @@ export class TaskManagerPlugin savedObjectsRepository, logger: this.logger, currentNode: this.taskManagerId!, + config: this.config.discovery, }); if (this.shouldRunBackgroundTasks) { @@ -315,7 +316,12 @@ export class TaskManagerPlugin excludedTypes: new Set(this.config.unsafe.exclude_task_types), }); - const taskPartitioner = new TaskPartitioner(this.taskManagerId!, this.kibanaDiscoveryService); + const taskPartitioner = new TaskPartitioner({ + podName: this.taskManagerId!, + kibanaDiscoveryService: this.kibanaDiscoveryService, + kibanasPerPartition: this.config.kibanas_per_partition, + }); + this.taskPollingLifecycle = new TaskPollingLifecycle({ config: this.config!, definitions: this.definitions, diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts index 77e29749c97a2..db1e5277ce37f 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.test.ts @@ -21,7 +21,7 @@ import { FillPoolResult } from './lib/fill_pool'; import { ElasticsearchResponseError } from './lib/identify_es_error'; import { executionContextServiceMock } from '@kbn/core/server/mocks'; import { TaskCost } from './task'; -import { CLAIM_STRATEGY_MGET } from './config'; +import { CLAIM_STRATEGY_MGET, DEFAULT_KIBANAS_PER_PARTITION } from './config'; import { TaskPartitioner } from './lib/task_partitioner'; import { KibanaDiscoveryService } from './kibana_discovery_service'; @@ -45,6 +45,11 @@ describe('TaskPollingLifecycle', () => { const mockTaskStore = taskStoreMock.create({}); const taskManagerOpts = { config: { + discovery: { + active_nodes_lookback: '30s', + interval: 10000, + }, + kibanas_per_partition: 2, enabled: true, index: 'foo', max_attempts: 9, @@ -95,7 +100,11 @@ describe('TaskPollingLifecycle', () => { capacityConfiguration$: of(20), pollIntervalConfiguration$: of(100), executionContext, - taskPartitioner: new TaskPartitioner('test', {} as KibanaDiscoveryService), + taskPartitioner: new TaskPartitioner({ + podName: 'test', + kibanaDiscoveryService: {} as KibanaDiscoveryService, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, + }), }; beforeEach(() => { diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts index 103bc17004ef0..76df8b7ae5584 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts @@ -18,8 +18,11 @@ import { RecognizedTask, OneOfTaskTypes, tasksWithPartitions, + claimSort, } from './mark_available_tasks_as_claimed'; +import { TaskStatus, TaskPriority, ConcreteTaskInstance } from '../task'; + import { TaskTypeDictionary } from '../task_type_dictionary'; import { mockLogger } from '../test_utils'; @@ -304,4 +307,129 @@ if (doc['task.runAt'].size()!=0) { } `); }); + + // Tests sorting 3 tasks with different priorities, runAt/retryAt values + // running the sort over all permutations of them. + describe('claimSort', () => { + const definitions = new TaskTypeDictionary(mockLogger()); + definitions.registerTaskDefinitions({ + normalPriorityTask: { + title: 'normal priority', + createTaskRunner: () => ({ run: () => Promise.resolve() }), + priority: TaskPriority.Normal, // 50 + }, + noPriorityTask: { + title: 'no priority', + createTaskRunner: () => ({ run: () => Promise.resolve() }), + priority: undefined, // 50 + }, + lowPriorityTask: { + title: 'low priority', + createTaskRunner: () => ({ run: () => Promise.resolve() }), + priority: TaskPriority.Low, // 1 + }, + }); + + // possible ordering of tasks before sort + const permutations = [ + [0, 1, 2], + [0, 2, 1], + [1, 0, 2], + [1, 2, 0], + [2, 0, 1], + [2, 1, 0], + ]; + + test('works correctly with same dates, different priorities', () => { + const date = new Date(); + const baseTasks: ConcreteTaskInstance[] = []; + + // push in reverse order + baseTasks.push(buildTaskInstance({ taskType: 'lowPriorityTask', runAt: date })); + baseTasks.push(buildTaskInstance({ taskType: 'noPriorityTask', runAt: date })); + baseTasks.push(buildTaskInstance({ taskType: 'normalPriorityTask', runAt: date })); + + for (const perm of permutations) { + const tasks = [baseTasks[perm[0]], baseTasks[perm[1]], baseTasks[perm[2]]]; + const sorted = claimSort(definitions, tasks); + // all we know is low should be last + expect(sorted[2]).toBe(baseTasks[0]); + } + }); + + test('works correctly with same priorities, different dates', () => { + const baseDate = new Date('2024-07-29T00:00:00Z').valueOf(); + const baseTasks: ConcreteTaskInstance[] = []; + + // push in reverse order + baseTasks.push( + buildTaskInstance({ taskType: 'noPriorityTask', runAt: new Date(baseDate + 1000) }) + ); + baseTasks.push(buildTaskInstance({ taskType: 'noPriorityTask', runAt: new Date(baseDate) })); + baseTasks.push( + buildTaskInstance({ taskType: 'noPriorityTask', runAt: new Date(baseDate - 1000) }) + ); + + for (const perm of permutations) { + const tasks = [baseTasks[perm[0]], baseTasks[perm[1]], baseTasks[perm[2]]]; + const sorted = claimSort(definitions, tasks); + expect(sorted[0]).toBe(baseTasks[2]); + expect(sorted[1]).toBe(baseTasks[1]); + expect(sorted[2]).toBe(baseTasks[0]); + } + }); + + test('works correctly with mixed of runAt and retryAt values', () => { + const baseDate = new Date('2024-07-29T00:00:00Z').valueOf(); + const baseTasks: ConcreteTaskInstance[] = []; + + // push in reverse order + baseTasks.push( + buildTaskInstance({ taskType: 'noPriorityTask', runAt: new Date(baseDate + 1000) }) + ); + baseTasks.push( + buildTaskInstance({ + taskType: 'noPriorityTask', + runAt: new Date(baseDate - 2000), + retryAt: new Date(baseDate), // should use this value + }) + ); + baseTasks.push( + buildTaskInstance({ taskType: 'noPriorityTask', runAt: new Date(baseDate - 1000) }) + ); + + for (const perm of permutations) { + const tasks = [baseTasks[perm[0]], baseTasks[perm[1]], baseTasks[perm[2]]]; + const sorted = claimSort(definitions, tasks); + expect(sorted[0]).toBe(baseTasks[2]); + expect(sorted[1]).toBe(baseTasks[1]); + expect(sorted[2]).toBe(baseTasks[0]); + } + }); + }); }); + +interface BuildTaskOpts { + taskType: string; + runAt: Date; + retryAt?: Date; +} + +let id = 1; + +function buildTaskInstance(opts: BuildTaskOpts): ConcreteTaskInstance { + const { taskType, runAt, retryAt } = opts; + return { + taskType, + id: `${id++}`, + runAt, + retryAt: retryAt || null, + scheduledAt: runAt, + attempts: 0, + status: TaskStatus.Idle, + startedAt: null, + state: {}, + params: {}, + ownerId: null, + }; +} diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts index 107a3f4466637..4e138545aec25 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts @@ -6,7 +6,7 @@ */ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { TaskTypeDictionary } from '../task_type_dictionary'; -import { TaskStatus, TaskPriority } from '../task'; +import { TaskStatus, TaskPriority, ConcreteTaskInstance } from '../task'; import { ScriptBasedSortClause, ScriptClause, @@ -15,23 +15,6 @@ import { MustNotCondition, } from './query_clauses'; -export function taskWithLessThanMaxAttempts(type: string, maxAttempts: number): MustCondition { - return { - bool: { - must: [ - { term: { 'task.taskType': type } }, - { - range: { - 'task.attempts': { - lt: maxAttempts, - }, - }, - }, - ], - }, - }; -} - export function tasksOfType(taskTypes: string[]): estypes.QueryDslQueryContainer { return { bool: { @@ -166,12 +149,53 @@ function getSortByPriority(definitions: TaskTypeDictionary): estypes.SortCombina }; } +// getClaimSort() is used to generate sort bits for the ES query +// should align with claimSort() below export function getClaimSort(definitions: TaskTypeDictionary): estypes.SortCombinations[] { const sortByPriority = getSortByPriority(definitions); if (!sortByPriority) return [SortByRunAtAndRetryAt]; return [sortByPriority, SortByRunAtAndRetryAt]; } +// claimSort() is used to sort tasks returned from a claimer by priority and date. +// Kept here so it should align with getClaimSort() above. +// Returns a copy of the tasks passed in. +export function claimSort( + definitions: TaskTypeDictionary, + tasks: ConcreteTaskInstance[] +): ConcreteTaskInstance[] { + const priorityMap: Record = {}; + tasks.forEach((task) => { + const taskType = task.taskType; + const priority = getPriority(definitions, taskType); + priorityMap[taskType] = priority; + }); + + return tasks.slice().sort(compare); + + function compare(a: ConcreteTaskInstance, b: ConcreteTaskInstance) { + // sort by priority, descending + const priorityA = priorityMap[a.taskType] ?? TaskPriority.Normal; + const priorityB = priorityMap[b.taskType] ?? TaskPriority.Normal; + + if (priorityA > priorityB) return -1; + if (priorityA < priorityB) return 1; + + // then sort by retry/runAt, ascending + const runA = a.retryAt?.valueOf() ?? a.runAt.valueOf() ?? 0; + const runB = b.retryAt?.valueOf() ?? b.runAt.valueOf() ?? 0; + + if (runA < runB) return -1; + if (runA > runB) return 1; + + return 0; + } +} + +function getPriority(definitions: TaskTypeDictionary, taskType: string): TaskPriority { + return definitions.get(taskType)?.priority ?? TaskPriority.Normal; +} + export interface UpdateFieldsAndMarkAsFailedOpts { fieldUpdates: { [field: string]: string | number | Date; diff --git a/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts b/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts index 4528575d29ad0..903f6601c7b9c 100644 --- a/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts +++ b/x-pack/plugins/task_manager/server/queries/task_claiming.test.ts @@ -12,6 +12,7 @@ import { taskStoreMock } from '../task_store.mock'; import apm from 'elastic-apm-node'; import { TaskPartitioner } from '../lib/task_partitioner'; import { KibanaDiscoveryService } from '../kibana_discovery_service'; +import { DEFAULT_KIBANAS_PER_PARTITION } from '../config'; jest.mock('../constants', () => ({ CONCURRENCY_ALLOW_LIST_BY_TASK_TYPE: [ @@ -25,7 +26,11 @@ jest.mock('../constants', () => ({ })); const taskManagerLogger = mockLogger(); -const taskPartitioner = new TaskPartitioner('test', {} as KibanaDiscoveryService); +const taskPartitioner = new TaskPartitioner({ + podName: 'test', + kibanaDiscoveryService: {} as KibanaDiscoveryService, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, +}); beforeEach(() => jest.clearAllMocks()); diff --git a/x-pack/plugins/task_manager/server/task_claimers/index.ts b/x-pack/plugins/task_manager/server/task_claimers/index.ts index ff4f9f6131120..fdbe9e94aa6a9 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/index.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/index.ts @@ -83,3 +83,12 @@ export function isTaskTypeExcluded(excludedTaskTypePatterns: string[], taskType: return false; } + +export function getExcludedTaskTypes( + definitions: TaskTypeDictionary, + excludedTaskTypePatterns: string[] +) { + return definitions + .getAllTypes() + .filter((taskType) => isTaskTypeExcluded(excludedTaskTypePatterns, taskType)); +} diff --git a/x-pack/plugins/task_manager/server/task_claimers/lib/task_selector_by_capacity.ts b/x-pack/plugins/task_manager/server/task_claimers/lib/task_selector_by_capacity.ts new file mode 100644 index 0000000000000..531357436c0bf --- /dev/null +++ b/x-pack/plugins/task_manager/server/task_claimers/lib/task_selector_by_capacity.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 { ConcreteTaskInstance } from '../../task'; +import { isLimited, TaskClaimingBatches } from '../../queries/task_claiming'; + +// given a list of tasks and capacity info, select the tasks that meet capacity +export function selectTasksByCapacity( + tasks: ConcreteTaskInstance[], + batches: TaskClaimingBatches +): ConcreteTaskInstance[] { + // create a map of task type - concurrency + const limitedBatches = batches.filter(isLimited); + const limitedMap = new Map(); + for (const limitedBatch of limitedBatches) { + const { tasksTypes, concurrency } = limitedBatch; + limitedMap.set(tasksTypes, concurrency); + } + + // apply the limited concurrency + const result: ConcreteTaskInstance[] = []; + for (const task of tasks) { + const concurrency = limitedMap.get(task.taskType); + if (concurrency == null) { + result.push(task); + continue; + } + + if (concurrency > 0) { + result.push(task); + limitedMap.set(task.taskType, concurrency - 1); + } + } + + return result; +} diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts index e9df1bda7b81d..4e47581ccbdd5 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.test.ts @@ -8,7 +8,9 @@ import _ from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { filter, take, toArray } from 'rxjs'; -import { CLAIM_STRATEGY_MGET } from '../config'; +import { SavedObjectsErrorHelpers } from '@kbn/core/server'; + +import { CLAIM_STRATEGY_MGET, DEFAULT_KIBANAS_PER_PARTITION } from '../config'; import { TaskStatus, @@ -34,7 +36,6 @@ import apm from 'elastic-apm-node'; import { TASK_MANAGER_TRANSACTION_TYPE } from '../task_running'; import { ClaimOwnershipResult } from '.'; import { FillPoolResult } from '../lib/fill_pool'; -import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { TaskPartitioner } from '../lib/task_partitioner'; import type { MustNotCondition } from '../queries/query_clauses'; import { @@ -100,7 +101,11 @@ discoveryServiceMock.getActiveKibanaNodes.mockResolvedValue([ createFindSO('test-pod-2', lastSeen), createFindSO('test-pod-3', lastSeen), ]); -const taskPartitioner = new TaskPartitioner('test', discoveryServiceMock); +const taskPartitioner = new TaskPartitioner({ + podName: 'test', + kibanaDiscoveryService: discoveryServiceMock, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, +}); // needs more tests in the similar to the `strategy_default.test.ts` test suite describe('TaskClaiming', () => { @@ -162,12 +167,12 @@ describe('TaskClaiming', () => { } for (let i = 0; i < hits.length; i++) { - store.fetch.mockResolvedValueOnce({ docs: hits[i], versionMap: versionMaps[i] }); - store.getDocVersions.mockResolvedValueOnce(docVersion[i]); - const oneBulkGetResult = hits[i].map((hit) => asOk(hit)); - store.bulkGet.mockResolvedValueOnce(oneBulkGetResult); + store.msearch.mockResolvedValueOnce({ docs: hits[i], versionMap: versionMaps[i] }); + store.getDocVersions.mockResolvedValueOnce(versionMaps[i]); const oneBulkResult = hits[i].map((hit) => asOk(hit)); store.bulkUpdate.mockResolvedValueOnce(oneBulkResult); + const oneBulkGetResult = hits[i].map((hit) => asOk(hit)); + store.bulkGet.mockResolvedValueOnce(oneBulkGetResult); } const taskClaiming = new TaskClaiming({ @@ -231,12 +236,12 @@ describe('TaskClaiming', () => { ); expect(mockApmTrans.end).toHaveBeenCalledWith('success'); - expect(store.fetch.mock.calls).toMatchObject({}); + expect(store.msearch.mock.calls).toMatchObject({}); expect(store.getDocVersions.mock.calls).toMatchObject({}); return results.map((result, index) => ({ result, args: { - search: store.fetch.mock.calls[index][0] as SearchOpts & { + search: store.msearch.mock.calls[index][0] as SearchOpts[] & { query: MustNotCondition; }, }, @@ -269,8 +274,8 @@ describe('TaskClaiming', () => { }, }); - store.fetch.mockReset(); - store.fetch.mockRejectedValue(new Error('Oh no')); + store.msearch.mockReset(); + store.msearch.mockRejectedValue(new Error('Oh no')); await expect( getAllAsPromise( @@ -333,7 +338,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce( @@ -376,7 +381,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith([ 'task:id-1', 'task:id-2', @@ -431,7 +439,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce([fetchedTasks[2]].map(asOk)); @@ -471,7 +479,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); expect(store.bulkUpdate).toHaveBeenCalledTimes(2); expect(store.bulkUpdate).toHaveBeenNthCalledWith( @@ -522,7 +533,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce([fetchedTasks[2]].map(asOk)); @@ -574,7 +585,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); expect(store.bulkUpdate).toHaveBeenCalledTimes(2); expect(store.bulkUpdate).toHaveBeenNthCalledWith( @@ -625,7 +639,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce([fetchedTasks[2]].map(asOk)); @@ -669,7 +683,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); expect(store.bulkGet).toHaveBeenCalledWith(['id-3']); expect(store.bulkUpdate).toHaveBeenCalledTimes(2); @@ -716,7 +733,7 @@ describe('TaskClaiming', () => { const fetchedTasks: ConcreteTaskInstance[] = []; const { versionMap } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); const taskClaiming = new TaskClaiming({ logger: taskManagerLogger, @@ -748,7 +765,10 @@ describe('TaskClaiming', () => { expect(taskManagerLogger.debug).not.toHaveBeenCalled(); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).not.toHaveBeenCalled(); expect(store.bulkGet).not.toHaveBeenCalled(); expect(store.bulkUpdate).not.toHaveBeenCalled(); @@ -773,7 +793,7 @@ describe('TaskClaiming', () => { const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); versionMap.delete('id-1'); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce([fetchedTasks[1], fetchedTasks[2]].map(asOk)); @@ -812,7 +832,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); expect(store.bulkUpdate).toHaveBeenCalledTimes(1); expect(store.bulkUpdate).toHaveBeenCalledWith( @@ -855,7 +878,7 @@ describe('TaskClaiming', () => { const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); docLatestVersions.delete('task:id-1'); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce([fetchedTasks[1], fetchedTasks[2]].map(asOk)); @@ -894,7 +917,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); expect(store.bulkUpdate).toHaveBeenCalledTimes(1); expect(store.bulkUpdate).toHaveBeenCalledWith( @@ -937,7 +963,7 @@ describe('TaskClaiming', () => { const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); docLatestVersions.set('task:id-1', { esId: 'task:id-1', seqNo: 33, primaryTerm: 33 }); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce([fetchedTasks[1], fetchedTasks[2]].map(asOk)); @@ -976,7 +1002,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith(['task:id-1', 'task:id-2', 'task:id-3']); expect(store.bulkUpdate).toHaveBeenCalledTimes(1); expect(store.bulkUpdate).toHaveBeenCalledWith( @@ -1021,7 +1050,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkGet.mockResolvedValueOnce( @@ -1064,7 +1093,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith([ 'task:id-1', 'task:id-2', @@ -1126,7 +1158,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkUpdate.mockResolvedValueOnce( [fetchedTasks[0], fetchedTasks[1], fetchedTasks[2], fetchedTasks[3]].map(asOk) @@ -1180,7 +1212,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith([ 'task:id-1', 'task:id-2', @@ -1240,7 +1275,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkUpdate.mockResolvedValueOnce( [fetchedTasks[0], fetchedTasks[1], fetchedTasks[2], fetchedTasks[3]].map(asOk) @@ -1284,7 +1319,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith([ 'task:id-1', 'task:id-2', @@ -1344,7 +1382,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkUpdate.mockResolvedValueOnce([ asOk(fetchedTasks[0]), @@ -1400,7 +1438,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith([ 'task:id-1', 'task:id-2', @@ -1460,7 +1501,7 @@ describe('TaskClaiming', () => { ]; const { versionMap, docLatestVersions } = getVersionMapsFromTasks(fetchedTasks); - store.fetch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); + store.msearch.mockResolvedValueOnce({ docs: fetchedTasks, versionMap }); store.getDocVersions.mockResolvedValueOnce(docLatestVersions); store.bulkUpdate.mockRejectedValueOnce(new Error('oh no')); store.bulkGet.mockResolvedValueOnce([]); @@ -1502,7 +1543,10 @@ describe('TaskClaiming', () => { { tags: ['claimAvailableTasksMget'] } ); - expect(store.fetch.mock.calls[0][0]).toMatchObject({ size: 40, seq_no_primary_term: true }); + expect(store.msearch.mock.calls[0][0]?.[0]).toMatchObject({ + size: 40, + seq_no_primary_term: true, + }); expect(store.getDocVersions).toHaveBeenCalledWith([ 'task:id-1', 'task:id-2', @@ -1563,13 +1607,7 @@ describe('TaskClaiming', () => { createTaskRunner: jest.fn(), }, }); - const [ - { - args: { - search: { query }, - }, - }, - ] = await testClaimAvailableTasks({ + const claimedResults = await testClaimAvailableTasks({ storeOpts: { taskManagerId, definitions, @@ -1579,6 +1617,13 @@ describe('TaskClaiming', () => { claimOwnershipUntil: new Date(), }, }); + const [ + { + args: { + search: [{ query }], + }, + }, + ] = claimedResults; expect(query).toMatchInlineSnapshot(` Object { @@ -1782,24 +1827,31 @@ describe('TaskClaiming', () => { const taskStore = taskStoreMock.create({ taskManagerId }); taskStore.convertToSavedObjectIds.mockImplementation((ids) => ids.map((id) => `task:${id}`)); for (const docs of taskCycles) { - taskStore.fetch.mockResolvedValueOnce({ docs, versionMap: new Map() }); - taskStore.updateByQuery.mockResolvedValueOnce({ - updated: docs.length, - version_conflicts: 0, - total: docs.length, + const versionMap = new Map(); + const docVersions = new Map(); + for (const doc of docs) { + const esId = `task:${doc.id}`; + versionMap.set(doc.id, { esId, seqNo: 42, primaryTerm: 666 }); + docVersions.set(esId, { esId, seqNo: 42, primaryTerm: 666 }); + } + taskStore.msearch.mockResolvedValueOnce({ docs, versionMap }); + taskStore.getDocVersions.mockResolvedValueOnce(docVersions); + const updatedDocs = docs.map((doc) => { + doc = { ...doc, retryAt: null }; + return asOk(doc); }); + taskStore.bulkUpdate.mockResolvedValueOnce(updatedDocs); + taskStore.bulkGet.mockResolvedValueOnce(updatedDocs); } - taskStore.fetch.mockResolvedValue({ docs: [], versionMap: new Map() }); - taskStore.updateByQuery.mockResolvedValue({ - updated: 0, - version_conflicts: 0, - total: 0, - }); + taskStore.msearch.mockResolvedValue({ docs: [], versionMap: new Map() }); + taskStore.getDocVersions.mockResolvedValue(new Map()); + taskStore.bulkUpdate.mockResolvedValue([]); + taskStore.bulkGet.mockResolvedValue([]); const taskClaiming = new TaskClaiming({ logger: taskManagerLogger, - strategy: 'default', + strategy: CLAIM_STRATEGY_MGET, definitions, excludedTaskTypes: [], unusedTypes: [], @@ -1813,7 +1865,21 @@ describe('TaskClaiming', () => { } test('emits an event when a task is succesfully by scheduling', async () => { - const { taskManagerId, runAt, taskClaiming } = instantiateStoreWithMockedApiResponses(); + const taskDefs = new TaskTypeDictionary(taskManagerLogger); + taskDefs.registerTaskDefinitions({ + foo: { + title: 'foo', + createTaskRunner: jest.fn(), + }, + bar: { + title: 'bar', + createTaskRunner: jest.fn(), + }, + }); + + const { taskManagerId, runAt, taskClaiming } = instantiateStoreWithMockedApiResponses({ + definitions: taskDefs, + }); const promise = taskClaiming.events .pipe( @@ -1850,7 +1916,8 @@ describe('TaskClaiming', () => { retryAt: null, scheduledAt: new Date(), traceparent: 'newParent', - }) + }), + event?.timing ) ); }); diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts index b2751803e8dc3..dce4bf66e57db 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_mget.ts @@ -23,15 +23,11 @@ import { TaskClaimerOpts, ClaimOwnershipResult, getEmptyClaimOwnershipResult, - isTaskTypeExcluded, + getExcludedTaskTypes, } from '.'; import { ConcreteTaskInstance, TaskStatus, ConcreteTaskInstanceVersion, TaskCost } from '../task'; import { TASK_MANAGER_TRANSACTION_TYPE } from '../task_running'; -import { - isLimited, - TASK_MANAGER_MARK_AS_CLAIMED, - TaskClaimingBatches, -} from '../queries/task_claiming'; +import { TASK_MANAGER_MARK_AS_CLAIMED } from '../queries/task_claiming'; import { TaskClaim, asTaskClaimEvent, startTaskTimer } from '../task_events'; import { shouldBeOneOf, mustBeAllOf, filterDownBy, matchesClauses } from '../queries/query_clauses'; @@ -48,6 +44,7 @@ import { import { TaskStore, SearchOpts } from '../task_store'; import { isOk, asOk } from '../lib/result_type'; +import { selectTasksByCapacity } from './lib/task_selector_by_capacity'; import { TaskPartitioner } from '../lib/task_partitioner'; interface OwnershipClaimingOpts { @@ -55,7 +52,8 @@ interface OwnershipClaimingOpts { size: number; taskTypes: Set; removedTypes: Set; - excludedTaskTypes: string[]; + getCapacity: (taskType?: string | undefined) => number; + excludedTaskTypePatterns: string[]; taskStore: TaskStore; events$: Subject; definitions: TaskTypeDictionary; @@ -113,11 +111,12 @@ async function claimAvailableTasks(opts: TaskClaimerOpts): Promise { - const searchedTypes = Array.from(taskTypes) - .concat(Array.from(removedTypes)) - .filter((type) => !isTaskTypeExcluded(excludedTaskTypes, type)); - const queryForScheduledTasks = mustBeAllOf( - // Task must be enabled - EnabledTask, - // a task type that's not excluded (may be removed or not) - OneOfTaskTypes('task.taskType', searchedTypes), - // Either a task with idle status and runAt <= now or - // status running or claiming with a retryAt <= now. - shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt), - // must have a status that isn't 'unrecognized' - RecognizedTask - ); + const excludedTaskTypes = new Set(getExcludedTaskTypes(definitions, excludedTaskTypePatterns)); + const claimPartitions = buildClaimPartitions({ + types: taskTypes, + excludedTaskTypes, + removedTypes, + getCapacity, + definitions, + }); const partitions = await taskPartitioner.getPartitions(); const sort: NonNullable = getClaimSort(definitions); - const query = matchesClauses( - queryForScheduledTasks, - filterDownBy(InactiveTasks), - tasksWithPartitions(partitions) - ); + const searches: SearchOpts[] = []; + + // not handling removed types yet + + // add search for unlimited types + if (claimPartitions.unlimitedTypes.length > 0) { + const queryForUnlimitedTasks = mustBeAllOf( + // Task must be enabled + EnabledTask, + // a task type that's not excluded (may be removed or not) + OneOfTaskTypes('task.taskType', claimPartitions.unlimitedTypes), + // Either a task with idle status and runAt <= now or + // status running or claiming with a retryAt <= now. + shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt), + // must have a status that isn't 'unrecognized' + RecognizedTask + ); + + const queryUnlimitedTasks = matchesClauses( + queryForUnlimitedTasks, + filterDownBy(InactiveTasks), + tasksWithPartitions(partitions) + ); + searches.push({ + query: queryUnlimitedTasks, + sort, // note: we could optimize this to not sort on priority, for this case + size, + seq_no_primary_term: true, + }); + } - return await taskStore.fetch( - { + // add searches for limited types + for (const [type, capacity] of claimPartitions.limitedTypes) { + const queryForLimitedTasks = mustBeAllOf( + // Task must be enabled + EnabledTask, + // Specific task type + OneOfTaskTypes('task.taskType', [type]), + // Either a task with idle status and runAt <= now or + // status running or claiming with a retryAt <= now. + shouldBeOneOf(IdleTaskWithExpiredRunAt, RunningOrClaimingTaskWithExpiredRetryAt), + // must have a status that isn't 'unrecognized' + RecognizedTask + ); + + const query = matchesClauses( + queryForLimitedTasks, + filterDownBy(InactiveTasks), + tasksWithPartitions(partitions) + ); + searches.push({ query, sort, - size, + size: capacity * SIZE_MULTIPLIER_FOR_TASK_FETCH, seq_no_primary_term: true, - }, - // limit the response size - true - ); + }); + } + + return await taskStore.msearch(searches); } -function applyLimitedConcurrency( - tasks: ConcreteTaskInstance[], - batches: TaskClaimingBatches -): ConcreteTaskInstance[] { - // create a map of task type - concurrency - const limitedBatches = batches.filter(isLimited); - const limitedMap = new Map(); - for (const limitedBatch of limitedBatches) { - const { tasksTypes, concurrency } = limitedBatch; - limitedMap.set(tasksTypes, concurrency); - } +interface ClaimPartitions { + removedTypes: string[]; + unlimitedTypes: string[]; + limitedTypes: Map; +} + +interface BuildClaimPartitionsOpts { + types: Set; + excludedTaskTypes: Set; + removedTypes: Set; + getCapacity: (taskType?: string) => number; + definitions: TaskTypeDictionary; +} + +function buildClaimPartitions(opts: BuildClaimPartitionsOpts): ClaimPartitions { + const result: ClaimPartitions = { + removedTypes: [], + unlimitedTypes: [], + limitedTypes: new Map(), + }; + + const { types, excludedTaskTypes, removedTypes, getCapacity, definitions } = opts; + for (const type of types) { + const definition = definitions.get(type); + if (definition == null) continue; + + if (excludedTaskTypes.has(type)) continue; + + if (removedTypes.has(type)) { + result.removedTypes.push(type); + continue; + } - // apply the limited concurrency - const result: ConcreteTaskInstance[] = []; - for (const task of tasks) { - const concurrency = limitedMap.get(task.taskType); - if (concurrency == null) { - result.push(task); + if (definition.maxConcurrency == null) { + result.unlimitedTypes.push(definition.type); continue; } - if (concurrency > 0) { - result.push(task); - limitedMap.set(task.taskType, concurrency - 1); + const capacity = getCapacity(definition.type) / definition.cost; + if (capacity !== 0) { + result.limitedTypes.set(definition.type, capacity); } } diff --git a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts index 38676ee1626e7..7744543ea9577 100644 --- a/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts +++ b/x-pack/plugins/task_manager/server/task_claimers/strategy_update_by_query.test.ts @@ -30,6 +30,7 @@ import { ClaimOwnershipResult } from '.'; import { FillPoolResult } from '../lib/fill_pool'; import { TaskPartitioner } from '../lib/task_partitioner'; import { KibanaDiscoveryService } from '../kibana_discovery_service'; +import { DEFAULT_KIBANAS_PER_PARTITION } from '../config'; jest.mock('../constants', () => ({ CONCURRENCY_ALLOW_LIST_BY_TASK_TYPE: [ @@ -43,7 +44,11 @@ jest.mock('../constants', () => ({ })); const taskManagerLogger = mockLogger(); -const taskPartitioner = new TaskPartitioner('test', {} as KibanaDiscoveryService); +const taskPartitioner = new TaskPartitioner({ + podName: 'test', + kibanaDiscoveryService: {} as KibanaDiscoveryService, + kibanasPerPartition: DEFAULT_KIBANAS_PER_PARTITION, +}); beforeEach(() => jest.clearAllMocks()); diff --git a/x-pack/plugins/task_manager/server/task_store.mock.ts b/x-pack/plugins/task_manager/server/task_store.mock.ts index c15518eaed510..7cf051f406532 100644 --- a/x-pack/plugins/task_manager/server/task_store.mock.ts +++ b/x-pack/plugins/task_manager/server/task_store.mock.ts @@ -33,6 +33,8 @@ export const taskStoreMock = { bulkGet: jest.fn(), bulkGetVersions: jest.fn(), getDocVersions: jest.fn(), + search: jest.fn(), + msearch: jest.fn(), index, taskManagerId, } as unknown as jest.Mocked; diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index 80c1f46f53e4d..19f2861b0ed16 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -360,6 +360,141 @@ describe('TaskStore', () => { }); }); + describe('msearch', () => { + let store: TaskStore; + let esClient: ReturnType['asInternalUser']; + let childEsClient: ReturnType< + typeof elasticsearchServiceMock.createClusterClient + >['asInternalUser']; + + beforeAll(() => { + esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + childEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser; + esClient.child.mockReturnValue(childEsClient as unknown as Client); + store = new TaskStore({ + logger: mockLogger(), + index: 'tasky', + taskManagerId: '', + serializer, + esClient, + definitions: taskDefinitions, + savedObjectsRepository: savedObjectsClient, + adHocTaskCounter, + allowReadingInvalidState: false, + requestTimeouts: { + update_by_query: 1000, + }, + }); + }); + + async function testMsearch( + optsArray: SearchOpts[], + hitsArray: Array> = [] + ) { + childEsClient.msearch.mockResponse({ + took: 0, + responses: hitsArray.map((hits) => ({ + hits, + took: 0, + _shards: { + failed: 0, + successful: 1, + total: 1, + }, + timed_out: false, + status: 200, + })), + }); + + const result = await store.msearch(optsArray); + + expect(childEsClient.msearch).toHaveBeenCalledTimes(1); + + return { + result, + args: childEsClient.msearch.mock.calls[0][0], + }; + } + + test('empty call filters by type, sorts by runAt and id', async () => { + const { args } = await testMsearch([{}], []); + expect(args).toMatchObject({ + index: 'tasky', + body: [ + {}, + { + sort: [{ 'task.runAt': 'asc' }], + query: { term: { type: 'task' } }, + }, + ], + }); + }); + + test('allows multiple custom queries', async () => { + const { args } = await testMsearch( + [ + { + query: { + term: { 'task.taskType': 'foo' }, + }, + }, + { + query: { + term: { 'task.taskType': 'bar' }, + }, + }, + ], + [] + ); + + expect(args).toMatchObject({ + body: [ + {}, + { + query: { + bool: { + must: [{ term: { type: 'task' } }, { term: { 'task.taskType': 'foo' } }], + }, + }, + }, + {}, + { + query: { + bool: { + must: [{ term: { type: 'task' } }, { term: { 'task.taskType': 'bar' } }], + }, + }, + }, + ], + }); + }); + + test('pushes error from call cluster to errors$', async () => { + const firstErrorPromise = store.errors$.pipe(first()).toPromise(); + childEsClient.msearch.mockResponse({ + took: 0, + responses: [ + { + took: 0, + _shards: { + failed: 0, + successful: 1, + total: 1, + }, + timed_out: false, + status: 429, + }, + ], + } as estypes.MsearchResponse); + await expect(store.msearch([{}])).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected status code from taskStore::msearch: 429"` + ); + expect(await firstErrorPromise).toMatchInlineSnapshot( + `[Error: Unexpected status code from taskStore::msearch: 429]` + ); + }); + }); + describe('aggregate', () => { let store: TaskStore; let esClient: ReturnType['asInternalUser']; diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 9b58d7bc3c18b..12a1f256c585b 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -41,6 +41,7 @@ import { import { TaskTypeDictionary } from './task_type_dictionary'; import { AdHocTaskCounter } from './lib/adhoc_task_counter'; import { TaskValidator } from './task_validator'; +import { claimSort } from './queries/mark_available_tasks_as_claimed'; import { MAX_PARTITIONS } from './lib/task_partitioner'; export interface StoreOpts { @@ -504,6 +505,41 @@ export class TaskStore { } } + // like search(), only runs multiple searches in parallel returning the combined results + async msearch(opts: SearchOpts[] = []): Promise { + const queries = opts.map(({ sort = [{ 'task.runAt': 'asc' }], ...opt }) => + ensureQueryOnlyReturnsTaskObjects({ sort, ...opt }) + ); + const body = queries.flatMap((query) => [{}, query]); + + const result = await this.esClientWithoutRetries.msearch({ + index: this.index, + ignore_unavailable: true, + body, + }); + const { responses } = result; + + const versionMap = this.createVersionMap([]); + let allTasks = new Array(); + + for (const response of responses) { + if (response.status !== 200) { + const err = new Error(`Unexpected status code from taskStore::msearch: ${response.status}`); + this.errors$.next(err); + throw err; + } + + const { hits } = response as estypes.MsearchMultiSearchItem; + const { hits: tasks } = hits; + this.addTasksToVersionMap(versionMap, tasks); + allTasks = allTasks.concat(this.filterTasks(tasks)); + } + + const allSortedTasks = claimSort(this.definitions, allTasks); + + return { docs: allSortedTasks, versionMap }; + } + private async search( opts: SearchOpts = {}, limitResponse: boolean = false @@ -522,27 +558,9 @@ export class TaskStore { hits: { hits: tasks }, } = result; - const versionMap = new Map(); - for (const task of tasks) { - if (task._seq_no == null || task._primary_term == null) continue; - - const esId = task._id!.startsWith('task:') ? task._id!.slice(5) : task._id!; - versionMap.set(esId, { - esId: task._id!, - seqNo: task._seq_no, - primaryTerm: task._primary_term, - }); - } - + const versionMap = this.createVersionMap(tasks); return { - docs: tasks - // @ts-expect-error @elastic/elasticsearch _source is optional - .filter((doc) => this.serializer.isRawSavedObject(doc)) - // @ts-expect-error @elastic/elasticsearch _source is optional - .map((doc) => this.serializer.rawToSavedObject(doc)) - .map((doc) => omit(doc, 'namespace') as SavedObject) - .map((doc) => savedObjectToConcreteTaskInstance(doc)) - .filter((doc): doc is ConcreteTaskInstance => !!doc), + docs: this.filterTasks(tasks), versionMap, }; } catch (e) { @@ -551,6 +569,45 @@ export class TaskStore { } } + private filterTasks( + tasks: Array> + ): ConcreteTaskInstance[] { + return ( + tasks + // @ts-expect-error @elastic/elasticsearch _source is optional + .filter((doc) => this.serializer.isRawSavedObject(doc)) + // @ts-expect-error @elastic/elasticsearch _source is optional + .map((doc) => this.serializer.rawToSavedObject(doc)) + .map((doc) => omit(doc, 'namespace') as SavedObject) + .map((doc) => savedObjectToConcreteTaskInstance(doc)) + .filter((doc): doc is ConcreteTaskInstance => !!doc) + ); + } + + private addTasksToVersionMap( + versionMap: Map, + tasks: Array> + ): void { + for (const task of tasks) { + if (task._id == null || task._seq_no == null || task._primary_term == null) continue; + + const esId = task._id.startsWith('task:') ? task._id.slice(5) : task._id; + versionMap.set(esId, { + esId: task._id, + seqNo: task._seq_no, + primaryTerm: task._primary_term, + }); + } + } + + private createVersionMap( + tasks: Array> + ): Map { + const versionMap = new Map(); + this.addTasksToVersionMap(versionMap, tasks); + return versionMap; + } + public async aggregate({ aggs, query, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 2c8e779aad579..aa2234cf80738 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -6791,7 +6791,6 @@ "searchResponseWarnings.title.clustersClause": "Un problème est survenu avec {nonSuccessfulClustersCount} {nonSuccessfulClustersCount, plural, one {cluster} other {clusters}}", "searchResponseWarnings.title.clustersClauseAndRequestsClause": "{clustersClause} pour {requestsCount} requêtes", "searchResponseWarnings.viewDetailsButtonLabel": "Afficher les détails", - "securitySolutionPackages.alertAssignments.upsell": "Passer à {requiredLicense} pour utiliser les affectations d'alertes", "securitySolutionPackages.alertSuppressionRuleDetails.upsell": "La suppression d'alertes est configurée mais elle ne sera pas appliquée en raison d'une licence insuffisante", "securitySolutionPackages.alertSuppressionRuleForm.upsell": "La suppression d'alertes est activée avec la licence {requiredLicense} ou supérieure", "securitySolutionPackages.beta.label": "Bêta", @@ -10931,7 +10930,7 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serverUrlHint": "Définir l'URL personnalisée du serveur APM (par défaut : {defaultApmServerUrl}). L'URL doit être complète et inclure le protocole (http ou https) et le port.", "xpack.apm.onboarding.shared_clients.configure.commands.serviceEnvironmentHint": "Le nom de l'environnement dans lequel ce service est déployé, par exemple \"production\" ou \"test\". Les environnements vous permettent de facilement filtrer les données à un niveau global dans l'interface utilisateur APM. Il est important de garantir la cohérence des noms d'environnements entre les différents agents.", "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "Le nom de service est le filtre principal dans l'interface utilisateur APM et est utilisé pour regrouper les erreurs et suivre les données ensemble. Caractères autorisés : a-z, A-Z, 0-9, -, _ et espace.", - "xpack.apm.onboarding.specProvider.longDescription": "Le monitoring des performances applicatives (APM) collecte les indicateurs et les erreurs de performance approfondies depuis votre application. Cela vous permet de monitorer les performances de milliers d'applications en temps réel. [Learn more]({learnMoreLink}).", + "xpack.apm.onboarding.specProvider.longDescription": "Le monitoring des performances applicatives (APM) collecte les indicateurs et les erreurs de performance approfondies depuis votre application. Cela vous permet de monitorer les performances de milliers d'applications en temps réel. {learnMoreLink}.", "xpack.apm.pages.alertDetails.alertSummary.actualValue": "Valeur réelle", "xpack.apm.pages.alertDetails.alertSummary.expectedValue": "Valeur attendue", "xpack.apm.percentOfParent": "({value} de {parentType, select, transaction { transaction } trace {trace} other {parentType inconnu} })", @@ -14452,7 +14451,6 @@ "xpack.csp.gcpIntegration.projectidFieldLabel": "ID de projet", "xpack.csp.gcpIntegration.setupFormatOptions.googleCloudShell": "Google Cloud Shell", "xpack.csp.gcpIntegration.setupFormatOptions.manual": "Manuel", - "xpack.csp.gcpIntegration.setupInfoContent": "L'intégration nécessitera des droits d'accès supérieurs pour l'exécution de certaines règles CIS Benchmarks. Sélectionnez votre méthode préférée pour la fourniture d'informations d'identification Google Cloud que cette intégration utilisera. Vous pouvez suivre ces instructions détaillées pour générer les informations d'identification nécessaires.", "xpack.csp.gcpIntegration.setupInfoContentTitle": "Configurer l'accès", "xpack.csp.grouping.loadingGroupPanelTitle": "Chargement", "xpack.csp.grouping.nullGroupTooltip": "Le champ {groupingTitle} sélectionné, {field}, a une valeur manquante de {unit} pour ce groupe.", @@ -14615,7 +14613,6 @@ "xpack.datasetQuality.appTitle": "Qualité de l’ensemble de données", "xpack.datasetQuality.betaBadgeDescription": "Cette fonctionnalité est actuellement en version bêta. Nous aimerions beaucoup savoir si vous avez des commentaires ou si vous rencontrez des bugs. Veuillez ouvrir un dossier d'assistance et/ou consulter notre forum de discussion.", "xpack.datasetQuality.betaBadgeLabel": "Bêta", - "xpack.datasetQuality.collapseLabel": "Réduire", "xpack.datasetQuality.datasetQualityColumnName": "Qualité de l’ensemble de données", "xpack.datasetQuality.datasetQualityColumnTooltip": "La qualité est basée sur le pourcentage de documents dégradés dans un ensemble de données. {visualQueue}", "xpack.datasetQuality.datasetQualityIdicator": "{quality}", @@ -14626,9 +14623,6 @@ "xpack.datasetQuality.emptyState.noData.title": "Aucun ensemble de données trouvé", "xpack.datasetQuality.emptyState.noPrivileges.message": "Vous ne disposez pas des autorisations requises pour voir les données de logs. Assurez-vous d'avoir les autorisations requises pour voir {datasetPattern}.", "xpack.datasetQuality.emptyState.noPrivileges.title": "Impossible de charger les ensembles de données", - "xpack.datasetQuality.expandLabel": "Développer", - "xpack.datasetQuality.fetchDatasetDetailsFailed": "Nous n'avons pas pu obtenir les détails de votre ensemble de données.", - "xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected": "Vous n'avez sélectionné aucun ensemble de données", "xpack.datasetQuality.fetchDatasetStatsFailed": "Nous n'avons pas pu obtenir vos ensembles de données.", "xpack.datasetQuality.fetchDegradedStatsFailed": "Nous n'avons pas pu obtenir d'informations sur vos documents dégradés.", "xpack.datasetQuality.fetchIntegrationsFailed": "Nous n'avons pas pu obtenir vos intégrations.", @@ -14636,9 +14630,6 @@ "xpack.datasetQuality.fewDegradedDocsTooltip": "{degradedDocsCount} documents dégradés dans cet ensemble de données.", "xpack.datasetQuality.filterBar.placeholder": "Filtrer les ensembles de données", "xpack.datasetQuality.flyout.degradedDocsTitle": "Documents dégradés", - "xpack.datasetQuality.flyout.degradedField.count": "Nombre de documents", - "xpack.datasetQuality.flyout.degradedField.field": "Champ", - "xpack.datasetQuality.flyout.degradedField.lastOccurrence": "Dernière occurrence", "xpack.datasetQuality.flyout.nonAggregatable.description": "{description}", "xpack.datasetQuality.flyout.nonAggregatable.howToFixIt": "{rolloverLink} manuellement cet ensemble de données pour empêcher des délais à l'avenir.", "xpack.datasetQuality.flyout.nonAggregatable.warning": "{dataset} est incompatible avec l'agrégation _ignored, ce qui peut entraîner des délais lors de la recherche de données. {howToFixIt}", @@ -39269,10 +39260,10 @@ "xpack.securitySolution.flyout.right.alertPreview.ariaLabel": "Voir un aperçu de l'alerte avec l'id {id}", "xpack.securitySolution.flyout.right.eventCategoryText": "Catégorie d'événement", "xpack.securitySolution.flyout.right.header.assignedTitle": "Utilisateurs affectés", - "xpack.securitySolution.flyout.right.header.collapseDetailButtonAriaLabel": "Réduire les détails", - "xpack.securitySolution.flyout.right.header.collapseDetailButtonLabel": "Réduire les détails", - "xpack.securitySolution.flyout.right.header.expandDetailButtonAriaLabel": "Développer les détails", - "xpack.securitySolution.flyout.right.header.expandDetailButtonLabel": "Développer les détails", + "securitySolutionPackages.flyout.right.header.collapseDetailButtonAriaLabel": "Réduire les détails", + "securitySolutionPackages.flyout.right.header.collapseDetailButtonLabel": "Réduire les détails", + "securitySolutionPackages.flyout.right.header.expandDetailButtonAriaLabel": "Développer les détails", + "securitySolutionPackages.flyout.right.header.expandDetailButtonLabel": "Développer les détails", "xpack.securitySolution.flyout.right.header.headerTitle": "Détails des documents", "xpack.securitySolution.flyout.right.header.jsonTabLabel": "JSON", "xpack.securitySolution.flyout.right.header.overviewTabLabel": "Aperçu", @@ -39359,10 +39350,10 @@ "xpack.securitySolution.flyout.right.visualizations.sessionPreview.timeDescription": "à", "xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellDescription": "Cette fonctionnalité requiert un {subscription}", "xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellLinkText": "Abonnement Enterprise", - "xpack.securitySolution.flyout.shared.errorDescription": "Une erreur est survenue lors de l'affichage de {message}.", - "xpack.securitySolution.flyout.shared.errorTitle": "Impossible d'afficher {title}.", - "xpack.securitySolution.flyout.shared.ExpandablePanelButtonIconAriaLabel": "Activer/Désactiver le panneau extensible", - "xpack.securitySolution.flyout.shared.expandablePanelLoadingAriaLabel": "panneau extensible", + "securitySolutionPackages.flyout.shared.errorDescription": "Une erreur est survenue lors de l'affichage de {message}.", + "securitySolutionPackages.flyout.shared.errorTitle": "Impossible d'afficher {title}.", + "securitySolutionPackages.flyout.shared.ExpandablePanelButtonIconAriaLabel": "Activer/Désactiver le panneau extensible", + "securitySolutionPackages.flyout.shared.expandablePanelLoadingAriaLabel": "panneau extensible", "xpack.securitySolution.flyout.tour.entities.description": "Consultez la vue {entities} étendue pour en savoir plus sur les hôtes et les utilisateurs liés à l'alerte.", "xpack.securitySolution.flyout.tour.entities.text": "Entités", "xpack.securitySolution.flyout.tour.entities.title": "De nouvelles informations sur les hôtes et les utilisateurs sont disponibles", @@ -40635,7 +40626,6 @@ "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionFromAlertComment": "Les conditions d'exceptions sont préremplies avec les données pertinentes d'une alerte possédant l'identifiant d'alerte (_id) : {alertId}.", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessText": "L'exception a été ajoutée aux règles - {ruleName}.", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessTitle": "Exception à la règle ajoutée", - "xpack.securitySolution.ruleExceptions.addExceptionFlyout.closeAlerts.successDetails": "L'exception de la règle a été ajoutée aux listes partagées : {listNames}.", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.commentsTitle": "Ajouter des commentaires ({comments})", "xpack.securitySolution.ruleExceptions.allExceptionItems.activeDetectionsLabel": "Exceptions actives", "xpack.securitySolution.ruleExceptions.allExceptionItems.addExceptionsEmptyPromptTitle": "Ajouter des exceptions à cette règle", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 38b706cc807e7..b7143b2f78cd7 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -10920,7 +10920,7 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serverUrlHint": "カスタム APM Server URL(デフォルト:{defaultApmServerUrl})を設定します。URLはプロトコル(httpまたはhttps)とポートを含む完全修飾URLでなければなりません。", "xpack.apm.onboarding.shared_clients.configure.commands.serviceEnvironmentHint": "このサービスがデプロイされている環境の名前(例:「本番」、「ステージング」)。環境では、APM UIでグローバルレベルで簡単にデータをフィルタリングできます。すべてのエージェントで環境の命名方法を統一することが重要です。", "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "このサービス名はAPM UIの主フィルターであり、エラーとトレースデータをグループ化するために使用されます。使用できる文字はA-Z、0-9、-、_、スペースです。", - "xpack.apm.onboarding.specProvider.longDescription": "アプリケーションパフォーマンスモニタリング(APM)は、アプリケーション内から詳細なパフォーマンスメトリックやエラーを収集します。何千ものアプリケーションのパフォーマンスをリアルタイムで監視できます。[詳細]({learnMoreLink})。", + "xpack.apm.onboarding.specProvider.longDescription": "アプリケーションパフォーマンスモニタリング(APM)は、アプリケーション内から詳細なパフォーマンスメトリックやエラーを収集します。何千ものアプリケーションのパフォーマンスをリアルタイムで監視できます。{learnMoreLink}。", "xpack.apm.pages.alertDetails.alertSummary.actualValue": "実際の値", "xpack.apm.pages.alertDetails.alertSummary.expectedValue": "想定された値", "xpack.apm.percentOfParent": "({value} of {parentType, select, transaction { トランザクション } trace {トレース} other {不明なparentType} })", @@ -14441,7 +14441,6 @@ "xpack.csp.gcpIntegration.projectidFieldLabel": "プロジェクト ID", "xpack.csp.gcpIntegration.setupFormatOptions.googleCloudShell": "Google Cloud Shell", "xpack.csp.gcpIntegration.setupFormatOptions.manual": "手動", - "xpack.csp.gcpIntegration.setupInfoContent": "この統合では、一部のCISベンチマークルールを実行するために昇格されたアクセス権が必要です。この統合で使用するGCP資格情報を提供するための任意の方法を選択します。これらの段階的な手順に従い、必要な資格情報を作成できます。", "xpack.csp.gcpIntegration.setupInfoContentTitle": "アクセスの設定", "xpack.csp.grouping.loadingGroupPanelTitle": "読み込み中", "xpack.csp.grouping.nullGroupTooltip.groupingTitle": "グループ分けの条件", @@ -14603,7 +14602,6 @@ "xpack.datasetQuality.appTitle": "データセット品質", "xpack.datasetQuality.betaBadgeDescription": "現在、この機能はベータです。バグが発生した場合やフィードバックがある場合は、お問い合わせください。サポート問題をオープンするか、ディスカッションフォーラムをご覧ください。", "xpack.datasetQuality.betaBadgeLabel": "ベータ", - "xpack.datasetQuality.collapseLabel": "縮小", "xpack.datasetQuality.datasetQualityColumnName": "データセット品質", "xpack.datasetQuality.datasetQualityColumnTooltip": "品質は、データセットの劣化したドキュメントの割合に基づきます。{visualQueue}", "xpack.datasetQuality.datasetQualityIdicator": "{quality}", @@ -14614,9 +14612,6 @@ "xpack.datasetQuality.emptyState.noData.title": "データセットが見つかりません", "xpack.datasetQuality.emptyState.noPrivileges.message": "ログデータを表示するために必要な権限がありません。{datasetPattern}を表示するための十分な権限があることを確認してください。", "xpack.datasetQuality.emptyState.noPrivileges.title": "データセットを読み込めませんでした", - "xpack.datasetQuality.expandLabel": "拡張", - "xpack.datasetQuality.fetchDatasetDetailsFailed": "データセット詳細を取得できませんでした。", - "xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected": "データセットが選択されていません", "xpack.datasetQuality.fetchDatasetStatsFailed": "データセットを取得できませんでした。", "xpack.datasetQuality.fetchDegradedStatsFailed": "劣化したドキュメント情報を取得できませんでした。", "xpack.datasetQuality.fetchIntegrationsFailed": "統合を取得できませんでした。", @@ -14624,9 +14619,6 @@ "xpack.datasetQuality.fewDegradedDocsTooltip": "このデータセットの{degradedDocsCount}個の劣化したドキュメント。", "xpack.datasetQuality.filterBar.placeholder": "データセットのフィルタリング", "xpack.datasetQuality.flyout.degradedDocsTitle": "劣化したドキュメント", - "xpack.datasetQuality.flyout.degradedField.count": "ドキュメント数", - "xpack.datasetQuality.flyout.degradedField.field": "フィールド", - "xpack.datasetQuality.flyout.degradedField.lastOccurrence": "前回の発生", "xpack.datasetQuality.flyout.nonAggregatable.description": "{description}", "xpack.datasetQuality.flyout.nonAggregatable.howToFixIt": "今後の遅れを防止するには、手動でこのデータを{rolloverLink}してください。", "xpack.datasetQuality.flyout.nonAggregatable.warning": "{dataset}は_ignored集約をサポートしていません。データのクエリを実行するときに遅延が生じる可能性があります。{howToFixIt}", @@ -39251,10 +39243,10 @@ "xpack.securitySolution.flyout.right.alertPreview.ariaLabel": "ID {id}のアラートをプレビュー", "xpack.securitySolution.flyout.right.eventCategoryText": "イベントカテゴリ", "xpack.securitySolution.flyout.right.header.assignedTitle": "担当者", - "xpack.securitySolution.flyout.right.header.collapseDetailButtonAriaLabel": "詳細を折りたたむ", - "xpack.securitySolution.flyout.right.header.collapseDetailButtonLabel": "詳細を折りたたむ", - "xpack.securitySolution.flyout.right.header.expandDetailButtonAriaLabel": "詳細を展開", - "xpack.securitySolution.flyout.right.header.expandDetailButtonLabel": "詳細を展開", + "securitySolutionPackages.flyout.right.header.collapseDetailButtonAriaLabel": "詳細を折りたたむ", + "securitySolutionPackages.flyout.right.header.collapseDetailButtonLabel": "詳細を折りたたむ", + "securitySolutionPackages.flyout.right.header.expandDetailButtonAriaLabel": "詳細を展開", + "securitySolutionPackages.flyout.right.header.expandDetailButtonLabel": "詳細を展開", "xpack.securitySolution.flyout.right.header.headerTitle": "ドキュメント詳細", "xpack.securitySolution.flyout.right.header.jsonTabLabel": "JSON", "xpack.securitySolution.flyout.right.header.overviewTabLabel": "概要", @@ -39341,10 +39333,10 @@ "xpack.securitySolution.flyout.right.visualizations.sessionPreview.timeDescription": "に", "xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellDescription": "この機能には{subscription}が必要です", "xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellLinkText": "エンタープライズサブスクリプション", - "xpack.securitySolution.flyout.shared.errorDescription": "{message}の表示中にエラーが発生しました。", - "xpack.securitySolution.flyout.shared.errorTitle": "{title}を表示できません。", - "xpack.securitySolution.flyout.shared.ExpandablePanelButtonIconAriaLabel": "展開可能なパネルトグル", - "xpack.securitySolution.flyout.shared.expandablePanelLoadingAriaLabel": "展開可能なパネル", + "securitySolutionPackages.flyout.shared.errorDescription": "{message}の表示中にエラーが発生しました。", + "securitySolutionPackages.flyout.shared.errorTitle": "{title}を表示できません。", + "securitySolutionPackages.flyout.shared.ExpandablePanelButtonIconAriaLabel": "展開可能なパネルトグル", + "securitySolutionPackages.flyout.shared.expandablePanelLoadingAriaLabel": "展開可能なパネル", "xpack.securitySolution.flyout.tour.entities.description": "アラートに関連付けられたホストとユーザーの詳細については、展開された{entities}ビューを確認してください。", "xpack.securitySolution.flyout.tour.entities.text": "エンティティ", "xpack.securitySolution.flyout.tour.entities.title": "新しいホストとユーザーのインサイトがあります", @@ -40618,7 +40610,6 @@ "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionFromAlertComment": "例外条件は、アラートID(_id)のアラートからの関連データがあらかじめ入力されます:{alertId}。", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessText": "例外がルール - {ruleName}に追加されました。", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessTitle": "ルール例外が追加されました", - "xpack.securitySolution.ruleExceptions.addExceptionFlyout.closeAlerts.successDetails": "ルール例外が共有リストに追加されました:{listNames}。", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.commentsTitle": "コメントの追加({comments})", "xpack.securitySolution.ruleExceptions.allExceptionItems.activeDetectionsLabel": "アクティブな例外", "xpack.securitySolution.ruleExceptions.allExceptionItems.addExceptionsEmptyPromptTitle": "このルールに例外を追加", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e9f526337e125..6bcd4d85954db 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -10939,7 +10939,7 @@ "xpack.apm.onboarding.shared_clients.configure.commands.serverUrlHint": "设置定制 APM Server URL(默认值:{defaultApmServerUrl})。此 URL 必须为完全限定 URL,包括协议(http 或 https)和端口。", "xpack.apm.onboarding.shared_clients.configure.commands.serviceEnvironmentHint": "在其中部署此服务的环境的名称,如“生产”或“暂存”。在 APM UI 中,您可以通过环境在全局级别轻松筛选数据。跨代理命名环境时,保持一致至关重要。", "xpack.apm.onboarding.shared_clients.configure.commands.serviceNameHint": "服务名称是 APM UI 中的初级筛选,用于分组错误并跟踪数据。允许使用的字符包括 a-z、A-Z、0-9、-、_ 和空格。", - "xpack.apm.onboarding.specProvider.longDescription": "应用程序性能监测 (APM) 从您的应用程序内收集深入全面的性能指标和错误。其允许您实时监测数以千计的应用程序的性能。[了解详情]({learnMoreLink})。", + "xpack.apm.onboarding.specProvider.longDescription": "应用程序性能监测 (APM) 从您的应用程序内收集深入全面的性能指标和错误。其允许您实时监测数以千计的应用程序的性能。{learnMoreLink}。", "xpack.apm.pages.alertDetails.alertSummary.actualValue": "实际值", "xpack.apm.pages.alertDetails.alertSummary.expectedValue": "预期值", "xpack.apm.percentOfParent": "({parentType, select, transaction {事务} trace {追溯} other {parentType 未知}}的 {value})", @@ -14463,7 +14463,6 @@ "xpack.csp.gcpIntegration.projectidFieldLabel": "项目 ID", "xpack.csp.gcpIntegration.setupFormatOptions.googleCloudShell": "Google Cloud Shell", "xpack.csp.gcpIntegration.setupFormatOptions.manual": "手动", - "xpack.csp.gcpIntegration.setupInfoContent": "该集成需要提升访问权限才能运行某些 CIS 基准规则。选择提供此集成将使用的 GCP 凭据的首选方法。您可以按照这些分步说明生成所需凭据。", "xpack.csp.gcpIntegration.setupInfoContentTitle": "设置访问权限", "xpack.csp.grouping.loadingGroupPanelTitle": "正在加载", "xpack.csp.grouping.nullGroupTooltip": "选定 {groupingTitle} 字段 {field} 缺少此 {unit} 组的值。", @@ -14626,7 +14625,6 @@ "xpack.datasetQuality.appTitle": "数据集质量", "xpack.datasetQuality.betaBadgeDescription": "此功能当前为公测版。如果遇到任何错误或有任何反馈,我们乐于倾听您的意见。请报告支持问题和/或访问我们的讨论论坛。", "xpack.datasetQuality.betaBadgeLabel": "公测版", - "xpack.datasetQuality.collapseLabel": "折叠", "xpack.datasetQuality.datasetQualityColumnName": "数据集质量", "xpack.datasetQuality.datasetQualityColumnTooltip": "质量基于数据集中的已降级文档的百分比。{visualQueue}", "xpack.datasetQuality.datasetQualityIdicator": "{quality}", @@ -14637,9 +14635,6 @@ "xpack.datasetQuality.emptyState.noData.title": "找不到数据集", "xpack.datasetQuality.emptyState.noPrivileges.message": "您没有查看日志数据所需的权限。请确保您具有足够的权限,可以查看 {datasetPattern}。", "xpack.datasetQuality.emptyState.noPrivileges.title": "无法加载数据集", - "xpack.datasetQuality.expandLabel": "展开", - "xpack.datasetQuality.fetchDatasetDetailsFailed": "无法获取数据集详情。", - "xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected": "尚未选择任何数据集", "xpack.datasetQuality.fetchDatasetStatsFailed": "无法获取数据集。", "xpack.datasetQuality.fetchDegradedStatsFailed": "无法获取已降级文档信息。", "xpack.datasetQuality.fetchIntegrationsFailed": "无法获取集成。", @@ -14647,9 +14642,6 @@ "xpack.datasetQuality.fewDegradedDocsTooltip": "此数据集中的 {degradedDocsCount} 个已降级文档。", "xpack.datasetQuality.filterBar.placeholder": "筛选数据集", "xpack.datasetQuality.flyout.degradedDocsTitle": "已降级文档", - "xpack.datasetQuality.flyout.degradedField.count": "文档计数", - "xpack.datasetQuality.flyout.degradedField.field": "字段", - "xpack.datasetQuality.flyout.degradedField.lastOccurrence": "最后一次发生", "xpack.datasetQuality.flyout.nonAggregatable.description": "{description}", "xpack.datasetQuality.flyout.nonAggregatable.howToFixIt": "手动 {rolloverLink} 此数据集以防止未来出现延迟。", "xpack.datasetQuality.flyout.nonAggregatable.warning": "{dataset} 不支持 _ignored 聚合,在查询数据时可能会导致延迟。{howToFixIt}", @@ -39295,10 +39287,10 @@ "xpack.securitySolution.flyout.right.alertPreview.ariaLabel": "预览 ID 为 {id} 的告警", "xpack.securitySolution.flyout.right.eventCategoryText": "事件类别", "xpack.securitySolution.flyout.right.header.assignedTitle": "被分配人", - "xpack.securitySolution.flyout.right.header.collapseDetailButtonAriaLabel": "折叠详情", - "xpack.securitySolution.flyout.right.header.collapseDetailButtonLabel": "折叠详情", - "xpack.securitySolution.flyout.right.header.expandDetailButtonAriaLabel": "展开详情", - "xpack.securitySolution.flyout.right.header.expandDetailButtonLabel": "展开详情", + "securitySolutionPackages.flyout.right.header.collapseDetailButtonAriaLabel": "折叠详情", + "securitySolutionPackages.flyout.right.header.collapseDetailButtonLabel": "折叠详情", + "securitySolutionPackages.flyout.right.header.expandDetailButtonAriaLabel": "展开详情", + "securitySolutionPackages.flyout.right.header.expandDetailButtonLabel": "展开详情", "xpack.securitySolution.flyout.right.header.headerTitle": "文档详情", "xpack.securitySolution.flyout.right.header.jsonTabLabel": "JSON", "xpack.securitySolution.flyout.right.header.overviewTabLabel": "概览", @@ -39384,10 +39376,10 @@ "xpack.securitySolution.flyout.right.visualizations.sessionPreview.timeDescription": "处于", "xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellDescription": "此功能需要{subscription}", "xpack.securitySolution.flyout.right.visualizations.sessionPreview.upsellLinkText": "企业级订阅", - "xpack.securitySolution.flyout.shared.errorDescription": "显示 {message} 时出现错误。", - "xpack.securitySolution.flyout.shared.errorTitle": "无法显示 {title}。", - "xpack.securitySolution.flyout.shared.ExpandablePanelButtonIconAriaLabel": "可展开面板切换按钮", - "xpack.securitySolution.flyout.shared.expandablePanelLoadingAriaLabel": "可展开面板", + "securitySolutionPackages.flyout.shared.errorDescription": "显示 {message} 时出现错误。", + "securitySolutionPackages.flyout.shared.errorTitle": "无法显示 {title}。", + "securitySolutionPackages.flyout.shared.ExpandablePanelButtonIconAriaLabel": "可展开面板切换按钮", + "securitySolutionPackages.flyout.shared.expandablePanelLoadingAriaLabel": "可展开面板", "xpack.securitySolution.flyout.tour.entities.description": "请查阅展开的 {entities} 视图以了解与该告警有关的主机和用户的更多信息。", "xpack.securitySolution.flyout.tour.entities.text": "实体", "xpack.securitySolution.flyout.tour.entities.title": "有新主机和用户洞见可用", @@ -40661,7 +40653,6 @@ "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionFromAlertComment": "将使用具有告警 ID (_id) 的告警中的相关数据预填充例外条件:{alertId}。", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessText": "例外已添加到规则 - {ruleName}。", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.addRuleExceptionToastSuccessTitle": "已添加规则例外", - "xpack.securitySolution.ruleExceptions.addExceptionFlyout.closeAlerts.successDetails": "规则例外已添加到共享列表:{listNames}。", "xpack.securitySolution.ruleExceptions.addExceptionFlyout.commentsTitle": "添加注释 ({comments})", "xpack.securitySolution.ruleExceptions.allExceptionItems.activeDetectionsLabel": "活动例外", "xpack.securitySolution.ruleExceptions.allExceptionItems.addExceptionsEmptyPromptTitle": "将例外添加到此规则", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx index ced47444f3a8f..18db63c44234e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx @@ -90,6 +90,33 @@ describe('useColumns', () => { }; const defaultColumns: EuiDataGridColumn[] = [ + { + id: 'event.action', + displayAsText: 'Alert status', + initialWidth: 150, + schema: 'string', + }, + { + id: '@timestamp', + displayAsText: 'Last updated', + initialWidth: 250, + schema: 'datetime', + }, + { + id: 'kibana.alert.duration.us', + displayAsText: 'Duration', + initialWidth: 150, + schema: 'numeric', + }, + { + id: 'kibana.alert.reason', + displayAsText: 'Reason', + initialWidth: 260, + schema: 'string', + }, + ]; + + const resultColumns = [ { id: 'event.action', displayAsText: 'Alert status', @@ -122,10 +149,9 @@ describe('useColumns', () => { }); test('onColumnResize', async () => { - // storageTable will always be in sync with defualtColumns. - // it is an invariant. If that is the case, that can be considered an issue - const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook( + const localDefaultColumns = [...defaultColumns]; + const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(localDefaultColumns); + const { result, rerender } = renderHook( () => useColumns({ defaultColumns, @@ -137,13 +163,15 @@ describe('useColumns', () => { { wrapper } ); - act(() => { + await act(async () => { result.current.onColumnResize({ columnId: '@timestamp', width: 100 }); }); + rerender(); + expect(setItemStorageMock).toHaveBeenCalledWith( 'useColumnTest', - '{"columns":[{"id":"event.action","displayAsText":"Alert status","initialWidth":150,"schema":"string"},{"id":"@timestamp","displayAsText":"Last updated","initialWidth":100,"schema":"datetime"},{"id":"kibana.alert.duration.us","displayAsText":"Duration","initialWidth":150,"schema":"numeric"},{"id":"kibana.alert.reason","displayAsText":"Reason","schema":"string"}],"visibleColumns":["event.action","@timestamp","kibana.alert.duration.us","kibana.alert.reason"],"sort":[]}' + '{"columns":[{"id":"event.action","displayAsText":"Alert status","initialWidth":150,"schema":"string"},{"id":"@timestamp","displayAsText":"Last updated","initialWidth":100,"schema":"datetime"},{"id":"kibana.alert.duration.us","displayAsText":"Duration","initialWidth":150,"schema":"numeric"},{"id":"kibana.alert.reason","displayAsText":"Reason","initialWidth":260,"schema":"string"}],"visibleColumns":["event.action","@timestamp","kibana.alert.duration.us","kibana.alert.reason"],"sort":[]}' ); expect(result.current.columns.find((c) => c.id === '@timestamp')).toEqual({ displayAsText: 'Last updated', @@ -153,6 +181,28 @@ describe('useColumns', () => { }); }); + test('check if initial width for the last column does not exist', async () => { + const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); + const { result } = renderHook( + () => + useColumns({ + defaultColumns, + featureIds, + id, + storageAlertsTable: localStorageAlertsTable, + storage, + }), + { wrapper } + ); + + const columns = result.current.columns; + const visibleColumns = result.current.visibleColumns; + const lastVisibleColumnId = visibleColumns[visibleColumns.length - 1]; + const lastVisiableColumn = columns.find((col) => col.id === lastVisibleColumnId); + + expect(lastVisiableColumn).not.toHaveProperty('initialWidth'); + }); + test("does not fetch alerts fields if they're overridden through the alertsFields prop", () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); const alertsFields = { @@ -216,7 +266,7 @@ describe('useColumns', () => { result.current.onChangeVisibleColumns([]); }); act(() => { - result.current.onChangeVisibleColumns(defaultColumns.map((dc) => dc.id)); + result.current.onChangeVisibleColumns(resultColumns.map((dc) => dc.id)); }); expect(result.current.visibleColumns).toEqual([ 'event.action', @@ -224,7 +274,7 @@ describe('useColumns', () => { 'kibana.alert.duration.us', 'kibana.alert.reason', ]); - expect(result.current.columns).toEqual(defaultColumns); + expect(result.current.columns).toEqual(resultColumns); }); test('should populate visibleColumns correctly', async () => { @@ -296,7 +346,7 @@ describe('useColumns', () => { { wrapper } ); - await waitFor(() => expect(result.current.columns).toMatchObject(defaultColumns)); + await waitFor(() => expect(result.current.columns).toMatchObject(resultColumns)); }); }); @@ -316,10 +366,10 @@ describe('useColumns', () => { ); act(() => { - result.current.onToggleColumn(defaultColumns[0].id); + result.current.onToggleColumn(resultColumns[0].id); }); - expect(result.current.columns).toMatchObject(defaultColumns.slice(1)); + expect(result.current.columns).toMatchObject(resultColumns.slice(1)); }); test('should update the list of visible columns when onToggleColumn is called', async () => { @@ -338,17 +388,17 @@ describe('useColumns', () => { // remove particular column act(() => { - result.current.onToggleColumn(defaultColumns[0].id); + result.current.onToggleColumn(resultColumns[0].id); }); - expect(result.current.columns).toMatchObject(defaultColumns.slice(1)); + expect(result.current.columns).toMatchObject(resultColumns.slice(1)); // make it visible again act(() => { - result.current.onToggleColumn(defaultColumns[0].id); + result.current.onToggleColumn(resultColumns[0].id); }); - expect(result.current.columns).toMatchObject(defaultColumns); + expect(result.current.columns).toMatchObject(resultColumns); }); test('should update the column details in the storage when onToggleColumn is called', () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts index 8846470a2d263..30c9ff0ea69ed 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts @@ -306,9 +306,22 @@ export const useColumns = ({ [columns] ); + // remove initialWidth property from the last column to extended it to meet the full page width + const columnsWithoutInitialWidthForLastVisibleColumn = useMemo(() => { + const lastVisibleColumns = visibleColumns[visibleColumns.length - 1]; + return columns.map((col) => { + if (col.id !== lastVisibleColumns) { + return col; + } + + const { initialWidth, ...rest } = col; + return rest; + }); + }, [columns, visibleColumns]); + return useMemo( () => ({ - columns, + columns: columnsWithoutInitialWidthForLastVisibleColumn, visibleColumns, isBrowserFieldDataLoading: fieldsQuery.isLoading, browserFields: selectedAlertsFields, @@ -319,7 +332,7 @@ export const useColumns = ({ fields: fieldsToFetch, }), [ - columns, + columnsWithoutInitialWidthForLastVisibleColumn, visibleColumns, fieldsQuery.isLoading, selectedAlertsFields, diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts index 498020cb4b7d2..0700cba718324 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/rule_types.ts @@ -917,7 +917,7 @@ function getAlwaysFiringAlertAsDataRuleType( validate: { params: paramsSchema, }, - category: 'kibana', + category: 'management', producer: 'alertsFixture', defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts index 7bd9db83dcc00..302bbf2b06668 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/sub_action_connector.ts @@ -11,6 +11,7 @@ import type { ServiceParams } from '@kbn/actions-plugin/server'; import { PluginSetupContract as ActionsPluginSetup } from '@kbn/actions-plugin/server/plugin'; import { schema, TypeOf } from '@kbn/config-schema'; import { SubActionConnectorType } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; const TestConfigSchema = schema.object({ url: schema.string() }); const TestSecretsSchema = schema.object({ @@ -69,7 +70,11 @@ export const getTestSubActionConnector = ( return `Message: ${error.response?.data.errorMessage}. Code: ${error.response?.data.errorCode}`; } - public async subActionWithParams({ id }: { id: string }) { + public async subActionWithParams( + { id }: { id: string }, + connectorUsageCollector: ConnectorUsageCollector + ) { + connectorUsageCollector.addRequestBodyBytes(undefined, { id }); return { id }; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts index 1b39410a7bf93..3bc7b665e2c2e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/bedrock.ts @@ -13,8 +13,9 @@ import { } from '@kbn/actions-simulators-plugin/server/bedrock_simulation'; import { DEFAULT_TOKEN_LIMIT } from '@kbn/stack-connectors-plugin/common/bedrock/constants'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; -import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; +import { getEventLog, getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; const connectorTypeId = '.bedrock'; const name = 'A bedrock action'; @@ -344,6 +345,23 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(145); }); it('should overwrite the model when a model argument is provided', async () => { @@ -374,6 +392,23 @@ export default function bedrockTest({ getService }: FtrProviderContext) { }, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(145); }); it('should invoke AI with assistant AI body argument formatted to bedrock expectations', async () => { @@ -423,6 +458,23 @@ export default function bedrockTest({ getService }: FtrProviderContext) { connector_id: bedrockActionId, data: { message: bedrockClaude2SuccessResponse.completion }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: bedrockActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(256); }); describe('Token tracking dashboard', () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts index f26ba86f6fa3a..1ef7b170a4f0d 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases_webhook.ts @@ -14,13 +14,16 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function casesWebhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); const config = { createCommentJson: '{"body":{{{case.comment}}}}', createCommentMethod: 'post', @@ -398,6 +401,23 @@ export default function casesWebhookTest({ getService }: FtrProviderContext) { const { pushedDate, ...dataWithoutTime } = body.data; body.data = dataWithoutTime; + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(125); + expect(body).to.eql({ status: 'ok', connector_id: simulatedActionId, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts index 7e1f0636b3a96..72cea764d0165 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/d3security.ts @@ -12,7 +12,9 @@ import { d3SecuritySuccessResponse, } from '@kbn/actions-simulators-plugin/server/d3security_simulation'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const connectorTypeId = '.d3security'; const name = 'A D3 Security action'; @@ -24,6 +26,7 @@ const secrets = { export default function d3SecurityTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const createConnector = async (url: string) => { const { body } = await supertest @@ -248,6 +251,24 @@ export default function d3SecurityTest({ getService }: FtrProviderContext) { }, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: d3SecurityActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(99); + expect(body).to.eql({ status: 'ok', connector_id: d3SecurityActionId, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts index cfffe90126fac..6ed2c89e094f9 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/email.ts @@ -11,12 +11,15 @@ import { ExternalServiceSimulator, getExternalServiceSimulatorPath, } from '@kbn/actions-simulators-plugin/server/plugin'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function emailTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); + const retry = getService('retry'); describe('create email action', () => { let createdActionId = ''; @@ -103,7 +106,7 @@ export default function emailTest({ getService }: FtrProviderContext) { }, }) .expect(200) - .then((resp: any) => { + .then(async (resp: any) => { expect(resp.body.data.message.messageId).to.be.a('string'); expect(resp.body.data.messageId).to.be.a('string'); @@ -131,6 +134,23 @@ export default function emailTest({ getService }: FtrProviderContext) { headers: {}, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: createdActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(350); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts index 46287db208b87..8d867aea49685 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/es_index.ts @@ -7,7 +7,9 @@ import type { Client } from '@elastic/elasticsearch'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const ES_TEST_INDEX_NAME = 'functional-test-actions-index'; @@ -16,6 +18,7 @@ export default function indexTest({ getService }: FtrProviderContext) { const es: Client = getService('es'); const supertest = getService('supertest'); const esDeleteAllIndices = getService('esDeleteAllIndices'); + const retry = getService('retry'); describe('index action', () => { beforeEach(() => esDeleteAllIndices(ES_TEST_INDEX_NAME)); @@ -214,6 +217,23 @@ export default function indexTest({ getService }: FtrProviderContext) { } expect(passed1).to.be(true); expect(passed2).to.be(true); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: createdAction.id, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); it('should execute successly with refresh false', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts index 054678996888f..2268e379f441a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/jira.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { @@ -16,12 +17,14 @@ import { import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { MAX_OTHER_FIELDS_LENGTH } from '@kbn/stack-connectors-plugin/common/jira/constants'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function jiraTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); const mockJira = { config: { @@ -517,6 +520,23 @@ export default function jiraTest({ getService }: FtrProviderContext) { url: `${jiraSimulatorURL}/browse/CK-1`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(124); }); it('should handle creating an incident with other fields', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts index 716041e939e8a..05dfc61dd59e3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/openai.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { OpenAISimulator, @@ -14,6 +15,7 @@ import { import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; +import { getEventLog } from '../../../../../common/lib'; const connectorTypeId = '.gen-ai'; const name = 'A genAi action'; @@ -315,6 +317,23 @@ export default function genAiTest({ getService }: FtrProviderContext) { connector_id: genAiActionId, data: genAiSuccessResponse, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: genAiActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(78); }); describe('Token tracking dashboard', () => { const dashboardId = 'specific-dashboard-id-default'; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts index 48386480b00da..75913a4182bbd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/opsgenie.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { OpsgenieSimulator, @@ -13,11 +14,13 @@ import { } from '@kbn/actions-simulators-plugin/server/opsgenie_simulation'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function opsgenieTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); describe('Opsgenie', () => { describe('action creation', () => { @@ -535,6 +538,23 @@ export default function opsgenieTest({ getService }: FtrProviderContext) { connector_id: opsgenieActionId, data: opsgenieSuccessResponse, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: opsgenieActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(21); }); it('should preserve the alias when it is 512 characters when creating an alert', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts index 7148ac962c728..2871066b6456a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/pagerduty.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { @@ -14,12 +15,14 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function pagerdutyTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); describe('pagerduty action', () => { let simulatedActionId = ''; @@ -173,6 +176,23 @@ export default function pagerdutyTest({ getService }: FtrProviderContext) { status: 'success', }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(142); }); it('should execute successfully with links and customDetails', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts index c9b4e7ecafa3f..6dfb420463e9f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/resilient.ts @@ -6,15 +6,18 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { ResilientSimulator } from '@kbn/actions-simulators-plugin/server/resilient_simulation'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function resilientTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockResilient = { config: { @@ -409,6 +412,23 @@ export default function resilientTest({ getService }: FtrProviderContext) { url: `${simulatorUrl}/#incidents/123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: resilientActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(167); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts index a5f14e512ddb1..a3fedba5d1f69 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/server_log.ts @@ -6,12 +6,15 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serverLogTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const retry = getService('retry'); describe('server-log action', () => { let serverLogActionId: string; @@ -69,6 +72,23 @@ export default function serverLogTest({ getService }: FtrProviderContext) { .expect(200); expect(result.status).to.eql('ok'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: serverLogActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts index 4702d3bbe6df7..0f1748db4f5ef 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itom.ts @@ -10,16 +10,19 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getServiceNowServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serviceNowITOMTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockServiceNowCommon = { params: { @@ -500,6 +503,23 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { }) .expect(200); expect(result.status).to.eql('ok'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(317); }); }); @@ -548,6 +568,23 @@ export default function serviceNowITOMTest({ getService }: FtrProviderContext) { }, ], }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 2 }], + ['execute', { equal: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts index ec62e6d30f6ff..bc0f48f15caf5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_itsm.ts @@ -10,17 +10,20 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getServiceNowServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { MAX_ADDITIONAL_FIELDS_LENGTH } from '@kbn/stack-connectors-plugin/common/servicenow/constants'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serviceNowITSMTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockServiceNowCommon = { params: { @@ -708,6 +711,23 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=incident.do?sys_id=123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(261); }); }); @@ -755,6 +775,23 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=incident.do?sys_id=123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(239); }); }); @@ -803,6 +840,23 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { }, ], }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); @@ -829,6 +883,22 @@ export default function serviceNowITSMTest({ getService }: FtrProviderContext) { connector_id: simulatedActionId, data: {}, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts index fd4781f6d9e62..717a44a406712 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/servicenow_sir.ts @@ -10,17 +10,20 @@ import expect from '@kbn/expect'; import { asyncForEach } from '@kbn/std'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getServiceNowServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { MAX_ADDITIONAL_FIELDS_LENGTH } from '@kbn/stack-connectors-plugin/common/servicenow/constants'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function serviceNowSIRTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockServiceNowCommon = { config: { @@ -721,6 +724,23 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=sn_si_incident.do?sys_id=123`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(645); }); }); @@ -768,6 +788,22 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { url: `${serviceNowSimulatorURL}/nav_to.do?uri=sn_si_incident.do?sys_id=123`, }, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(429); }); }); @@ -816,6 +852,23 @@ export default function serviceNowSIRTest({ getService }: FtrProviderContext) { }, ], }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(0); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts index 4941bec1844ca..457f9edbed2fc 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/slack_webhook.ts @@ -9,14 +9,18 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; import http from 'http'; import getPort from 'get-port'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; + import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getSlackServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); describe('Slack webhook action', () => { let simulatedActionId = ''; @@ -175,6 +179,23 @@ export default function slackTest({ getService }: FtrProviderContext) { .expect(200); expect(result.status).to.eql('ok'); expect(proxyHaveBeenCalled).to.equal(true); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(18); }); it('should handle an empty message error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts index 859f4f952fe58..4d91fdddf80dd 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/swimlane.ts @@ -9,16 +9,19 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; import getPort from 'get-port'; import http from 'http'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { getSwimlaneServer } from '@kbn/actions-simulators-plugin/server/plugin'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function swimlaneTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const mockSwimlane = { name: 'A swimlane action', @@ -459,6 +462,23 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { url: `${swimlaneSimulatorURL}/record/123456asdf/wowzeronza`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(175); }); it('should handle updating an incident', async () => { @@ -490,6 +510,23 @@ export default function swimlaneTest({ getService }: FtrProviderContext) { url: `${swimlaneSimulatorURL}/record/123456asdf/wowzeronza`, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(193); }); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts index 53dd3aaaf026a..04971990f879e 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/tines.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { TinesSimulator, @@ -16,6 +17,7 @@ import { } from '@kbn/actions-simulators-plugin/server/tines_simulation'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const connectorTypeId = '.tines'; const name = 'A tines action'; @@ -35,6 +37,7 @@ const webhook = { export default function tinesTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const configService = getService('config'); + const retry = getService('retry'); const createConnector = async (url: string) => { const { body } = await supertest @@ -392,6 +395,23 @@ export default function tinesTest({ getService }: FtrProviderContext) { incompleteResponse: false, }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(2); }); it('should get webhooks', async () => { @@ -422,6 +442,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { incompleteResponse: false, }, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 2 }], + ['execute', { gte: 2 }], + ]), + }); + }); + + const executeEvent = events[3]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(2); }); it('should run the webhook', async () => { @@ -440,6 +476,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { connector_id: tinesActionId, data: tinesWebhookSuccessResponse, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(8); }); it('should run the webhook url', async () => { @@ -464,6 +516,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { connector_id: tinesActionId, data: tinesWebhookSuccessResponse, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 3 }], + ['execute', { gte: 3 }], + ]), + }); + }); + + const executeEvent = events[5]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(8); }); }); @@ -506,6 +574,22 @@ export default function tinesTest({ getService }: FtrProviderContext) { errorSource: TaskErrorSource.FRAMEWORK, service_message: 'Status code: 422. Message: API Error: Unprocessable Entity', }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: tinesActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(2); }); it('should return a failure when attempting to get webhooks', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts index 257378b406da5..b709ef837ad03 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/torq.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers/get_proxy_server'; import { @@ -14,12 +15,14 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function torqTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); describe('Torq action', () => { let simulatedActionId = ''; @@ -159,6 +162,22 @@ export default function torqTest({ getService }: FtrProviderContext) { connector_id: simulatedActionId, data: `{"msg": "test"}`, }); + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(14); }); it('should handle a 400 Torq error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts index c7a8f1c1b2524..f05db95254c1c 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/webhook.ts @@ -8,6 +8,8 @@ import httpProxy from 'http-proxy'; import http from 'http'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; + import { URL, format as formatUrl } from 'url'; import getPort from 'get-port'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; @@ -17,6 +19,7 @@ import { getWebhookServer, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; const defaultValues: Record = { headers: null, @@ -36,6 +39,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); async function createWebhookAction( webhookSimulatorURL: string, @@ -258,6 +262,23 @@ export default function webhookTest({ getService }: FtrProviderContext) { .expect(200); expect(result.status).to.eql('ok'); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: webhookActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(19); }); it('should support the PUT method against webhook target', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts index 4efacbf78f951..7cf2320c97933 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/xmatters.ts @@ -7,6 +7,7 @@ import httpProxy from 'http-proxy'; import expect from '@kbn/expect'; +import { IValidatedEvent } from '@kbn/event-log-plugin/server'; import { getHttpProxyServer } from '@kbn/alerting-api-integration-helpers'; import { @@ -14,12 +15,14 @@ import { ExternalServiceSimulator, } from '@kbn/actions-simulators-plugin/server/plugin'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; +import { getEventLog } from '../../../../../common/lib'; // eslint-disable-next-line import/no-default-export export default function xmattersTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const kibanaServer = getService('kibanaServer'); const configService = getService('config'); + const retry = getService('retry'); describe('xmatters action', () => { let simulatedActionId = ''; @@ -180,6 +183,23 @@ export default function xmattersTest({ getService }: FtrProviderContext) { spaceId: '', }, }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: simulatedActionId, + provider: 'actions', + actions: new Map([ + ['execute-start', { gte: 1 }], + ['execute', { gte: 1 }], + ]), + }); + }); + + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.be(130); }); it('should handle a 40x xmatters error', async () => { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts index acfb06e64cff6..f7b62d51d635f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/execute.ts @@ -652,6 +652,8 @@ export default function ({ getService }: FtrProviderContext) { expect(executeEvent?.message).to.eql(message); expect(startExecuteEvent?.message).to.eql(message.replace('executed', 'started')); + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.eql(0); + if (source) { expect(executeEvent?.kibana?.action?.execution?.source).to.eql(source.toLowerCase()); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts index c8fb3e4b6ce2d..b504f8204c4aa 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/sub_action_framework/index.ts @@ -8,8 +8,9 @@ import type SuperTest from 'supertest'; import expect from '@kbn/expect'; import { TaskErrorSource } from '@kbn/task-manager-plugin/common'; +import { IValidatedEvent } from '@kbn/event-log-plugin/generated/schemas'; import { FtrProviderContext } from '../../../../../common/ftr_provider_context'; -import { getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; +import { getEventLog, getUrlPrefix, ObjectRemover } from '../../../../../common/lib'; /** * The sub action connector is defined here @@ -79,6 +80,7 @@ const executeSubAction = async ({ // eslint-disable-next-line import/no-default-export export default function createActionTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const retry = getService('retry'); describe('Sub action framework', () => { const objectRemover = new ObjectRemover(supertest); @@ -140,13 +142,35 @@ export default function createActionTests({ getService }: FtrProviderContext) { const res = await createSubActionConnector({ supertest }); objectRemover.add('default', res.body.id, 'action', 'actions'); + const connectorId = res.body.id as string; + const subActionParams = { id: 'test-id' }; + const execRes = await executeSubAction({ supertest, - connectorId: res.body.id as string, + connectorId, subAction: 'subActionWithParams', - subActionParams: { id: 'test-id' }, + subActionParams, + }); + + const events: IValidatedEvent[] = await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: 'default', + type: 'action', + id: connectorId, + provider: 'actions', + actions: new Map([ + ['execute-start', { equal: 1 }], + ['execute', { equal: 1 }], + ]), + }); }); + const executeEvent = events[1]; + expect(executeEvent?.kibana?.action?.execution?.usage?.request_body_bytes).to.eql( + Buffer.byteLength(JSON.stringify(subActionParams)) + ); + expect(execRes.body).to.eql({ status: 'ok', data: { id: 'test-id' }, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/maintenance_window_scoped_query.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/maintenance_window_scoped_query.ts index b0900bc48c4bc..03880f79b5b14 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/maintenance_window_scoped_query.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/maintenance_window_scoped_query.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import type { Alert } from '@kbn/alerts-as-data-utils'; import { ALERT_MAINTENANCE_WINDOW_IDS } from '@kbn/rule-data-utils'; -import { ObjectRemover } from '../../../../common/lib'; +import { getTestRuleData, getUrlPrefix, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { createRule, @@ -18,6 +18,7 @@ import { expectNoActionsFired, runSoon, } from './test_helpers'; +import { Spaces } from '../../../scenarios'; const alertAsDataIndex = '.internal.alerts-test.patternfiring.alerts-default-000001'; @@ -177,5 +178,72 @@ export default function maintenanceWindowScopedQueryTests({ getService }: FtrPro getService, }); }); + + it('should associate alerts for rules that generate multiple alerts', async () => { + await createMaintenanceWindow({ + supertest, + objectRemover, + overwrites: { + scoped_query: { + kql: 'kibana.alert.rule.tags: "test"', + filters: [], + }, + category_ids: ['management'], + }, + }); + + // Create action and rule + const action = await await createAction({ + supertest, + objectRemover, + }); + + const { body: rule } = await supertestWithoutAuth + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + name: 'test-rule', + rule_type_id: 'test.always-firing-alert-as-data', + schedule: { interval: '24h' }, + tags: ['test'], + throttle: undefined, + notify_when: 'onActiveAlert', + params: { + index: alertAsDataIndex, + reference: 'test', + }, + actions: [ + { + id: action.id, + group: 'default', + params: {}, + }, + { + id: action.id, + group: 'recovered', + params: {}, + }, + ], + }) + ) + .expect(200); + + objectRemover.add(Spaces.space1.id, rule.id, 'rule', 'alerting'); + + // Run the first time - active + await getRuleEvents({ + id: rule.id, + activeInstance: 2, + retry, + getService, + }); + + await expectNoActionsFired({ + id: rule.id, + supertest, + retry, + }); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/test_helpers.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/test_helpers.ts index b2196d9ea3724..8c3438f7152a5 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/test_helpers.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group3/test_helpers.ts @@ -22,7 +22,7 @@ export const createRule = async ({ overwrites, }: { actionId: string; - pattern: { instance: boolean[] }; + pattern?: { instance: boolean[] }; supertest: SuperTestAgent; objectRemover: ObjectRemover; overwrites?: any; diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts b/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts index 199cacf99dea2..13bc2ee7de9d2 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/helper.ts @@ -9,7 +9,7 @@ import type { Agent as SuperTestAgent } from 'supertest'; import { Client } from '@elastic/elasticsearch'; import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { IndexDetails } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { IndexDetails } from '@kbn/cloud-security-posture-common'; import { CLOUD_SECURITY_PLUGIN_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import { SecurityService } from '@kbn/test-suites-src/common/services/security/security'; diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_index_timeout.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_index_timeout.ts index 3eda0f6a7b01a..b82140727fc24 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_index_timeout.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_index_timeout.ts @@ -5,7 +5,7 @@ * 2.0. */ import expect from '@kbn/expect'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FINDINGS_INDEX_DEFAULT_NS, diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexed.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexed.ts index 5e6d639490e45..1793944480ac7 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexed.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexed.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { FINDINGS_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_DEFAULT_NS, diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexing.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexing.ts index f55f5533718ed..ab8345284380a 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexing.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_indexing.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { FINDINGS_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_DEFAULT_NS, diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_not_deployed_not_installed.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_not_deployed_not_installed.ts index f67e2d5a0814b..ef442c575981a 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_not_deployed_not_installed.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_not_deployed_not_installed.ts @@ -5,7 +5,7 @@ * 2.0. */ import expect from '@kbn/expect'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { createPackagePolicy } from '../helper'; diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts index e80e80c322568..fe234e45e21f0 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_unprivileged.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { BENCHMARK_SCORE_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_DEFAULT_NS, diff --git a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_waiting_for_results.ts b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_waiting_for_results.ts index a148f160bfd81..bfb5321bdcba9 100644 --- a/x-pack/test/api_integration/apis/cloud_security_posture/status/status_waiting_for_results.ts +++ b/x-pack/test/api_integration/apis/cloud_security_posture/status/status_waiting_for_results.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { setupFleetAndAgents } from '../../../../fleet_api_integration/apis/agents/services'; import { generateAgent } from '../../../../fleet_api_integration/helpers'; import { FtrProviderContext } from '../../../ftr_provider_context'; diff --git a/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts b/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts index 6716cc859f278..ae51bbdf9e154 100644 --- a/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts +++ b/x-pack/test/cloud_security_posture_api/routes/helper/user_roles_utilites.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN } from '@kbn/cloud-security-posture-common'; import { - CDR_LATEST_NATIVE_MISCONFIGURATIONS_INDEX_PATTERN, BENCHMARK_SCORE_INDEX_PATTERN, LATEST_VULNERABILITIES_INDEX_PATTERN, ALERTS_INDEX_PATTERN, diff --git a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts index 66bd58ea4967e..698c2db91938e 100644 --- a/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts +++ b/x-pack/test/cloud_security_posture_functional/pages/cis_integrations/cspm/cis_integration_gcp.ts @@ -36,7 +36,8 @@ export default function (providerContext: FtrProviderContext) { await cisIntegration.navigateToAddIntegrationCspmPage(); }); - describe('CIS_GCP Organization', () => { + // FLAKY: https://github.com/elastic/kibana/issues/191027 + describe.skip('CIS_GCP Organization', () => { it('Switch between Manual and Google cloud shell', async () => { await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID); await cisIntegration.clickOptionButton(GCP_ORGANIZATION_TEST_ID); @@ -131,7 +132,8 @@ export default function (providerContext: FtrProviderContext) { }); }); - describe('CIS_GCP Organization Credentials File', () => { + // FLAKY: https://github.com/elastic/kibana/issues/190779 + describe.skip('CIS_GCP Organization Credentials File', () => { it('CIS_GCP Organization Credentials File workflow', async () => { const projectName = 'PRJ_NAME_TEST'; const credentialFileName = 'CRED_FILE_TEST_NAME'; @@ -177,7 +179,8 @@ export default function (providerContext: FtrProviderContext) { }); }); - describe('CIS_GCP Single', () => { + // FLAKY: https://github.com/elastic/kibana/issues/191144 + describe.skip('CIS_GCP Single', () => { it('Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are no Project ID, it should use default value', async () => { await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID); await cisIntegration.clickOptionButton(GCP_SINGLE_ACCOUNT_TEST_ID); diff --git a/x-pack/test/common/services/spaces.ts b/x-pack/test/common/services/spaces.ts index b4e99cacee571..9d11935bd7068 100644 --- a/x-pack/test/common/services/spaces.ts +++ b/x-pack/test/common/services/spaces.ts @@ -10,8 +10,22 @@ import Axios from 'axios'; import Https from 'https'; import { format as formatUrl } from 'url'; import util from 'util'; +import Chance from 'chance'; +import Url from 'url'; import { FtrProviderContext } from '../ftr_provider_context'; +const chance = new Chance(); + +interface SpaceCreate { + name?: string; + id?: string; + description?: string; + color?: string; + initials?: string; + solution?: 'es' | 'oblt' | 'security' | 'classic'; + disabledFeatures?: string[]; +} + export function SpacesServiceProvider({ getService }: FtrProviderContext) { const log = getService('log'); const config = getService('config'); @@ -35,7 +49,9 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { }); return new (class SpacesService { - public async create(space: any) { + public async create(_space?: SpaceCreate) { + const space = { id: chance.guid(), name: 'foo', ..._space }; + log.debug(`creating space ${space.id}`); const { data, status, statusText } = await axios.post('/api/spaces/space', space); @@ -45,6 +61,15 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { ); } log.debug(`created space ${space.id}`); + + const cleanUp = async () => { + return this.delete(space.id); + }; + + return { + cleanUp, + space, + }; } public async delete(spaceId: string) { @@ -72,5 +97,17 @@ export function SpacesServiceProvider({ getService }: FtrProviderContext) { return data; } + + /** Return the full URL that points to the root of the space */ + public getRootUrl(spaceId: string) { + const { protocol, hostname, port } = config.get('servers.kibana'); + + return Url.format({ + protocol, + hostname, + port, + pathname: `/s/${spaceId}`, + }); + } })(); } diff --git a/x-pack/test/common/utils/synthtrace/logs_es_client.ts b/x-pack/test/common/utils/synthtrace/logs_es_client.ts new file mode 100644 index 0000000000000..4d7222818bb9c --- /dev/null +++ b/x-pack/test/common/utils/synthtrace/logs_es_client.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 { Client } from '@elastic/elasticsearch'; +import { LogsSynthtraceEsClient, createLogger, LogLevel } from '@kbn/apm-synthtrace'; + +export async function getLogsSynthtraceEsClient(client: Client) { + return new LogsSynthtraceEsClient({ + client, + logger: createLogger(LogLevel.info), + refreshAfterIndex: true, + }); +} diff --git a/x-pack/test/fleet_api_integration/apis/epm/setup.ts b/x-pack/test/fleet_api_integration/apis/epm/setup.ts index ac43d7a141a25..001cab435d75b 100644 --- a/x-pack/test/fleet_api_integration/apis/epm/setup.ts +++ b/x-pack/test/fleet_api_integration/apis/epm/setup.ts @@ -32,9 +32,9 @@ export default function (providerContext: FtrProviderContext) { await uninstallPackage('deprecated', '0.1.0'); await uninstallPackage('multiple_versions', '0.3.0'); }); - // FLAKY: https://github.com/elastic/kibana/issues/118479 - describe.skip('setup performs upgrades', async () => { - const oldEndpointVersion = '0.13.0'; + + describe('setup performs upgrades', async () => { + const oldEndpointVersion = '1.0.0'; beforeEach(async () => { const url = '/api/fleet/epm/packages/endpoint'; await supertest.delete(url).set('kbn-xsrf', 'xxxx').send({ force: true }).expect(200); diff --git a/x-pack/test/fleet_api_integration/config.base.ts b/x-pack/test/fleet_api_integration/config.base.ts index 8e11dc1c5aa52..1be78bcdc04df 100644 --- a/x-pack/test/fleet_api_integration/config.base.ts +++ b/x-pack/test/fleet_api_integration/config.base.ts @@ -90,7 +90,6 @@ export default async function ({ readConfigFile, log }: FtrConfigProviderContext 'agentTamperProtectionEnabled', 'enableStrictKQLValidation', 'subfeaturePrivileges', - 'enablePackagesStateMachine', ])}`, `--xpack.cloud.id='123456789'`, `--xpack.fleet.agentless.enabled=true`, diff --git a/x-pack/test/fleet_api_integration/config.space_awareness.ts b/x-pack/test/fleet_api_integration/config.space_awareness.ts index f77d3826964ed..9647f52c911a2 100644 --- a/x-pack/test/fleet_api_integration/config.space_awareness.ts +++ b/x-pack/test/fleet_api_integration/config.space_awareness.ts @@ -20,7 +20,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { 'agentTamperProtectionEnabled', 'enableStrictKQLValidation', 'subfeaturePrivileges', - 'enablePackagesStateMachine', 'useSpaceAwareness', ])}`; diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts similarity index 69% rename from x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts rename to x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts index 52ccfad201a53..3ac6cf8b46945 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts @@ -10,6 +10,7 @@ import { DatasetQualityFtrProviderContext } from './config'; import { createDegradedFieldsRecord, datasetNames, + defaultNamespace, getInitialTestLogs, getLogsForDataset, productionNamespace, @@ -33,8 +34,9 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const retry = getService('retry'); const browser = getService('browser'); const to = '2024-01-01T12:00:00.000Z'; + const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + const apacheAccessDataStreamName = `logs-${apacheAccessDatasetName}-${productionNamespace}`; const apacheIntegrationId = 'apache'; const apachePkg = { name: 'apache', @@ -42,15 +44,18 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid }; const bitbucketDatasetName = 'atlassian_bitbucket.audit'; - const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + const bitbucketAuditDataStreamName = `logs-${bitbucketDatasetName}-${defaultNamespace}`; const bitbucketPkg = { name: 'atlassian_bitbucket', version: '1.14.0', }; + const regularDatasetName = datasetNames[0]; + const regularDataStreamName = `logs-${datasetNames[0]}-${defaultNamespace}`; const degradedDatasetName = datasetNames[2]; + const degradedDataStreamName = `logs-${degradedDatasetName}-${defaultNamespace}`; - describe('Flyout', () => { + describe('Dataset Quality Details', () => { before(async () => { // Install Apache Integration and ingest logs for it await PageObjects.observabilityLogsExplorer.installPackage(apachePkg); @@ -85,8 +90,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid // Index logs for Bitbucket integration getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName }), ]); - - await PageObjects.datasetQuality.navigateTo(); }); after(async () => { @@ -95,21 +98,49 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid await synthtrace.clean(); }); - describe('open flyout', () => { - it('should open the flyout for the right dataset', async () => { - const testDatasetName = datasetNames[1]; + describe('navigate to dataset details', () => { + it('should navigate to right dataset', async () => { + await PageObjects.datasetQuality.navigateToDetails({ dataStream: regularDataStreamName }); + + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle + ); + }); + + it('should navigate to details page from a main page', async () => { + await PageObjects.datasetQuality.navigateTo(); + + const synthDataset = await testSubjects.find( + 'datasetQualityTableDetailsLink-logs-synth.1-default', + 20 * 1000 + ); - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + await synthDataset.click(); await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutTitle + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle ); + }); - await PageObjects.datasetQuality.closeFlyout(); + it('should show an empty prompt with error message when the dataset is not found', async () => { + const nonExistentDataStreamName = 'logs-non.existent-production'; + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: nonExistentDataStreamName, + }); + + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPrompt + ); + + const emptyPromptBody = await testSubjects.getVisibleText( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPromptBody + ); + + expect(emptyPromptBody).to.contain(nonExistentDataStreamName); }); it('reflects the breakdown field state in url', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDataStreamName }); const breakdownField = 'service.name'; await PageObjects.datasetQuality.selectBreakdownField(breakdownField); @@ -128,46 +159,72 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.not.contain('breakdownField'); }); - await PageObjects.datasetQuality.closeFlyout(); }); }); - describe('integrations', () => { - it('should hide the integration section for non integrations', async () => { - const testDatasetName = datasetNames[1]; + describe('overview summary panel', () => { + it('should show summary KPIs', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + const { docsCountTotal, degradedDocs, services, hosts, size } = + await PageObjects.datasetQuality.parseOverviewSummaryPanelKpis(); + expect(parseInt(docsCountTotal, 10)).to.be(226); + expect(parseInt(degradedDocs, 10)).to.be(1); + expect(parseInt(services, 10)).to.be(3); + expect(parseInt(hosts, 10)).to.be(52); + expect(parseInt(size, 10)).to.be.greaterThan(0); + }); + }); + describe('overview integrations', () => { + it('should hide the integration section for non integrations', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); + + // The Integration row should not be present await testSubjects.missingOrFail( PageObjects.datasetQuality.testSubjectSelectors - .datasetQualityFlyoutFieldsListIntegrationDetails + .datasetQualityDetailsIntegrationRowIntegration ); - await PageObjects.datasetQuality.closeFlyout(); + // The Version row should not be present + await testSubjects.missingOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion + ); }); it('should shows the integration section for integrations', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors - .datasetQualityFlyoutFieldsListIntegrationDetails + .datasetQualityDetailsIntegrationRowIntegration + ); + + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion ); await retry.tryForTime(5000, async () => { const integrationNameExists = await PageObjects.datasetQuality.doesTextExist( PageObjects.datasetQuality.testSubjectSelectors - .datasetQualityFlyoutFieldsListIntegrationDetails, + .datasetQualityDetailsIntegrationRowIntegration, apacheIntegrationId ); expect(integrationNameExists).to.be(true); }); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should show the integration actions menu with correct actions', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); const actions = await Promise.all( @@ -177,23 +234,26 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid ); expect(actions.length).to.eql(3); - await PageObjects.datasetQuality.closeFlyout(); }); it('should hide integration dashboard for integrations without dashboards', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: bitbucketAuditDataStreamName, + }); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction( integrationActions.viewDashboards ) ); - await PageObjects.datasetQuality.closeFlyout(); }); it('Should navigate to integration overview page on clicking integration overview action', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: bitbucketAuditDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( @@ -208,12 +268,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket'); }); - - await PageObjects.datasetQuality.navigateTo(); }); it('should navigate to index template page in clicking Integration template', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( @@ -229,11 +289,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid `/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}` ); }); - await PageObjects.datasetQuality.navigateTo(); }); it('should navigate to the selected dashboard on clicking integration dashboard action ', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( @@ -251,119 +312,87 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last'); expect(breadcrumbText).to.eql(dashboardText); - - await PageObjects.datasetQuality.navigateTo(); - }); - }); - - describe('summary panel', () => { - it('should show summary KPIs', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - - const { docsCountTotal, degradedDocs, services, hosts, size } = - await PageObjects.datasetQuality.parseFlyoutKpis(); - expect(parseInt(docsCountTotal, 10)).to.be(226); - expect(parseInt(degradedDocs, 10)).to.be(1); - expect(parseInt(services, 10)).to.be(3); - expect(parseInt(hosts, 10)).to.be(52); - expect(parseInt(size, 10)).to.be.greaterThan(0); - - await PageObjects.datasetQuality.closeFlyout(); }); }); describe('navigation', () => { - afterEach(async () => { - // Navigate back to dataset quality page after each test - await PageObjects.datasetQuality.navigateTo(); - }); - it('should go to log explorer page when the open in log explorer button is clicked', async () => { - const testDatasetName = datasetNames[2]; - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); - const logExplorerButton = await PageObjects.datasetQuality.getFlyoutLogsExplorerButton(); + const logExplorerButton = + await PageObjects.datasetQuality.getDatasetQualityDetailsHeaderButton(); await logExplorerButton.click(); // Confirm dataset selector text in observability logs explorer const datasetSelectorText = await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); - expect(datasetSelectorText).to.eql(testDatasetName); + expect(datasetSelectorText).to.eql(regularDatasetName); }); - it('should go log explorer for degraded docs when the show all button is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + it('should go log explorer for degraded docs when the button next to breakdown selector is clicked', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); - const degradedDocsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.degradedDocs}`; - await testSubjects.click(degradedDocsShowAllSelector); + await testSubjects.click( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsLinkToDiscover + ); // Confirm dataset selector text in observability logs explorer const datasetSelectorText = await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); expect(datasetSelectorText).to.contain(apacheAccessDatasetName); }); - - // Blocked by https://github.com/elastic/kibana/issues/181705 - // Its a test written ahead of its time. - it.skip('goes to infra hosts for hosts when show all is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - - const hostsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.hosts}`; - await testSubjects.click(hostsShowAllSelector); - - // Confirm url contains metrics/hosts - await retry.tryForTime(5000, async () => { - const currentUrl = await browser.getCurrentUrl(); - const parsedUrl = new URL(currentUrl); - expect(parsedUrl.pathname).to.contain('/app/metrics/hosts'); - }); - }); }); describe('degraded fields table', () => { it(' should show empty degraded fields table when no degraded fields are present', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(datasetNames[0]); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedTableNoData ); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should show the degraded fields table with data when present', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedFieldTable ); const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); + await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); expect(rows.length).to.eql(2); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should display Spark Plot for every row of degraded fields', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); + await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); const sparkPlots = await testSubjects.findAll( PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot ); expect(rows.length).to.be(sparkPlots.length); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should sort the table when the count table header is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); @@ -374,12 +403,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const sortedCellTexts = await countColumn.getCellTexts(); expect(cellTexts.reverse()).to.eql(sortedCellTexts); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should update the URL when the table is sorted', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); const countColumn = table['Docs count']; @@ -405,8 +434,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid 'sort:(direction:asc,field:count)' ); }); - - await PageObjects.datasetQuality.closeFlyout(); }); // This is the only test which ingest data during the test. @@ -414,7 +441,9 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid // Even though this test ingest data, it can also be freely moved inside // this describe block, and it won't affect any of the existing tests it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); @@ -429,7 +458,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid }), ]); - await PageObjects.datasetQuality.refreshFlyout(); + await PageObjects.datasetQuality.refreshDetailsPageData(); const updatedTable = await PageObjects.datasetQuality.parseDegradedFieldTable(); const updatedCountColumn = updatedTable['Docs count']; @@ -440,8 +469,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const singleValueNow = parseInt(updatedCellTexts[0], 10); expect(singleValueNow).to.be.greaterThan(singleValuePreviously); - - await PageObjects.datasetQuality.closeFlyout(); }); }); }); diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts index c7c3cbf709931..c94a083946066 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { DatasetQualityFtrProviderContext } from './config'; -import { getInitialTestLogs, getLogsForDataset } from './data'; +import { datasetNames, defaultNamespace, getInitialTestLogs, getLogsForDataset } from './data'; export default function ({ getService, getPageObjects }: DatasetQualityFtrProviderContext) { const PageObjects = getPageObjects([ @@ -25,6 +25,8 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const apacheAccessDatasetName = 'apache.access'; const apacheAccessDatasetHumanName = 'Apache access logs'; + const regularDataStreamName = `logs-${datasetNames[0]}-${defaultNamespace}`; + const apacheAccessDataStreamName = `logs-${apacheAccessDatasetName}-${defaultNamespace}`; describe('Dataset quality handles user privileges', () => { before(async () => { @@ -170,35 +172,39 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid ); }); - it('flyout shows insufficient privileges warning for underprivileged data stream', async () => { - await PageObjects.datasetQuality.openDatasetFlyout('synth.1'); + it('Details page shows insufficient privileges warning for underprivileged data stream', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); await testSubjects.existOrFail( `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityInsufficientPrivileges}-Size` ); - await PageObjects.datasetQuality.closeFlyout(); + await PageObjects.datasetQuality.navigateTo(); }); it('"View dashboards" and "See integration" are hidden for underprivileged user', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); // "See Integration" is hidden await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction( 'Overview' ) ); // "View Dashboards" is hidden await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction( 'ViewDashboards' ) ); - await PageObjects.datasetQuality.closeFlyout(); + await PageObjects.datasetQuality.navigateTo(); }); }); }); diff --git a/x-pack/test/functional/apps/dataset_quality/index.ts b/x-pack/test/functional/apps/dataset_quality/index.ts index f22af151ca6c9..ec975f6cafff6 100644 --- a/x-pack/test/functional/apps/dataset_quality/index.ts +++ b/x-pack/test/functional/apps/dataset_quality/index.ts @@ -13,7 +13,7 @@ export default function ({ loadTestFile }: DatasetQualityFtrProviderContext) { loadTestFile(require.resolve('./dataset_quality_summary')); loadTestFile(require.resolve('./dataset_quality_table')); loadTestFile(require.resolve('./dataset_quality_table_filters')); - loadTestFile(require.resolve('./dataset_quality_flyout')); loadTestFile(require.resolve('./dataset_quality_privileges')); + loadTestFile(require.resolve('./dataset_quality_details')); }); } diff --git a/x-pack/test/functional/apps/infra/constants.ts b/x-pack/test/functional/apps/infra/constants.ts index 4c1d0d29a6ca4..d5e929c1bcc0f 100644 --- a/x-pack/test/functional/apps/infra/constants.ts +++ b/x-pack/test/functional/apps/infra/constants.ts @@ -56,6 +56,16 @@ export const HOSTS_VIEW_PATH = 'metrics/hosts'; export const DATE_PICKER_FORMAT = 'MMM D, YYYY @ HH:mm:ss.SSS'; +// synthtrace date constants + export const DATE_WITH_DOCKER_DATA_FROM = '2023-03-28T18:20:00.000Z'; export const DATE_WITH_DOCKER_DATA_TO = '2023-03-28T18:21:00.000Z'; export const DATE_WITH_DOCKER_DATA = '03/28/2023 6:20:59 PM'; + +export const DATE_WITH_HOSTS_DATA_FROM = '2023-03-28T18:20:00.000Z'; +export const DATE_WITH_HOSTS_DATA_TO = '2023-03-28T18:21:00.000Z'; +export const DATE_WITH_HOSTS_DATA = '03/28/2023 6:20:59 PM'; + +export const DATE_WITH_POD_DATA_FROM = '2023-09-19T07:20:00.000Z'; +export const DATE_WITH_POD_DATA_TO = '2023-09-19T07:21:00.000Z'; +export const DATE_WITH_POD_DATA = '09/19/2023 7:20:59 AM'; diff --git a/x-pack/test/functional/apps/infra/helpers.ts b/x-pack/test/functional/apps/infra/helpers.ts index 2ddabf314390f..48f94303a42cb 100644 --- a/x-pack/test/functional/apps/infra/helpers.ts +++ b/x-pack/test/functional/apps/infra/helpers.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { apm, timerange, infra } from '@kbn/apm-synthtrace-client'; +import { apm, timerange, infra, generateShortId, log } from '@kbn/apm-synthtrace-client'; const SERVICE_PREFIX = 'service'; // generates traces, metrics for services @@ -69,3 +69,141 @@ export function generateDockerContainersData({ containers.flatMap((container) => container.metrics().timestamp(timestamp)) ); } + +export function generateHostData({ + from, + to, + hosts, +}: { + from: string; + to: string; + hosts: Array<{ hostName: string; cpuValue: number }>; +}) { + const range = timerange(from, to); + + return range + .interval('30s') + .rate(1) + .generator((timestamp) => + hosts.flatMap(({ hostName, cpuValue }) => [ + infra.host(hostName).cpu({ cpuTotalValue: cpuValue }).timestamp(timestamp), + infra.host(hostName).memory().timestamp(timestamp), + infra.host(hostName).network().timestamp(timestamp), + infra.host(hostName).load().timestamp(timestamp), + infra.host(hostName).filesystem().timestamp(timestamp), + infra.host(hostName).diskio().timestamp(timestamp), + infra.host(hostName).core().timestamp(timestamp), + ]) + ); +} + +export function generateHostsWithK8sNodeData({ from, to }: { from: string; to: string }) { + const range = timerange(from, to); + + // cpuValue is sent to the generator to simulate different 'system.cpu.total.norm.pct' metric + // that is the default metric in inventory and hosts view and host details page + const hosts = [ + { + hostName: 'demo-stack-kubernetes-01', + cpuValue: 0.5, + }, + ]; + + return range + .interval('30s') + .rate(1) + .generator((timestamp) => + hosts.flatMap(({ hostName, cpuValue }) => [ + infra.host(hostName).cpu({ cpuTotalValue: cpuValue }).timestamp(timestamp), + infra.host(hostName).memory().timestamp(timestamp), + infra.host(hostName).network().timestamp(timestamp), + infra.host(hostName).load().timestamp(timestamp), + infra.host(hostName).filesystem().timestamp(timestamp), + infra.host(hostName).diskio().timestamp(timestamp), + infra.host(hostName).core().timestamp(timestamp), + infra.host(hostName).node('demo-stack-kubernetes-01').metrics().timestamp(timestamp), + infra.host(hostName).pod('pod-1').metrics().timestamp(timestamp), + ]) + ); +} + +export function generatePodsData({ + from, + to, + count = 1, +}: { + from: string; + to: string; + count: number; +}) { + const range = timerange(from, to); + + const pods = Array(count) + .fill(0) + .map((_, idx) => infra.pod(`pod-${idx}`, `node-name-${idx}`)); + + return range + .interval('30s') + .rate(1) + .generator((timestamp) => + pods.flatMap((pod, idx) => [ + pod.metrics().timestamp(timestamp), + pod.container(`container-${idx}`).metrics().timestamp(timestamp), + ]) + ); +} + +export function generateLogsDataForHosts({ + from, + to, + hosts, +}: { + from: string; + to: string; + hosts: Array<{ hostName: string }>; +}) { + const range = timerange(from, to); + + // Logs Data logic + const MESSAGE_LOG_LEVELS = [ + { message: 'A simple log', level: 'info' }, + { message: 'Yet another debug log', level: 'debug' }, + { message: 'Error with certificate: "ca_trusted_fingerprint"', level: 'error' }, + ]; + const CLOUD_PROVIDERS = ['gcp', 'aws', 'azure']; + const CLOUD_REGION = ['eu-central-1', 'us-east-1', 'area-51']; + + const CLUSTER = [ + { clusterId: generateShortId(), clusterName: 'synth-cluster-1' }, + { clusterId: generateShortId(), clusterName: 'synth-cluster-2' }, + { clusterId: generateShortId(), clusterName: 'synth-cluster-3' }, + ]; + + return range + .interval('30s') + .rate(1) + .generator((timestamp) => + hosts.flatMap(({ hostName }) => { + const index = Math.floor(Math.random() * MESSAGE_LOG_LEVELS.length); + return log + .create() + .message(MESSAGE_LOG_LEVELS[index].message) + .logLevel(MESSAGE_LOG_LEVELS[index].level) + .hostName(hostName) + .defaults({ + 'trace.id': generateShortId(), + 'agent.name': 'synth-agent', + 'orchestrator.cluster.name': CLUSTER[index].clusterName, + 'orchestrator.cluster.id': CLUSTER[index].clusterId, + 'orchestrator.resource.id': generateShortId(), + 'cloud.provider': CLOUD_PROVIDERS[index], + 'cloud.region': CLOUD_REGION[index], + 'cloud.availability_zone': `${CLOUD_REGION[index]}a`, + 'cloud.project.id': generateShortId(), + 'cloud.instance.id': generateShortId(), + 'log.file.path': `/logs/${generateShortId()}/error.txt`, + }) + .timestamp(timestamp); + }) + ); +} diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 163c91593b33b..50e055f5bc6bf 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -8,25 +8,51 @@ import expect from '@kbn/expect'; import { KUBERNETES_TOUR_STORAGE_KEY } from '@kbn/infra-plugin/public/pages/metrics/inventory_view/components/kubernetes_tour'; import { InfraSynthtraceEsClient } from '@kbn/apm-synthtrace'; -import { enableInfrastructureContainerAssetView } from '@kbn/observability-plugin/common'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { DATES, INVENTORY_PATH } from './constants'; -import { generateDockerContainersData } from './helpers'; +import { + INVENTORY_PATH, + DATE_WITH_DOCKER_DATA_FROM, + DATE_WITH_DOCKER_DATA_TO, + DATE_WITH_DOCKER_DATA, + DATE_WITH_HOSTS_DATA_FROM, + DATE_WITH_HOSTS_DATA_TO, + DATE_WITH_HOSTS_DATA, + DATE_WITH_POD_DATA, + DATE_WITH_POD_DATA_FROM, + DATE_WITH_POD_DATA_TO, +} from './constants'; +import { generateDockerContainersData, generateHostData, generatePodsData } from './helpers'; import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client'; -const DATE_WITH_DATA = DATES.metricsAndLogs.hosts.withData; -const DATE_WITHOUT_DATA = DATES.metricsAndLogs.hosts.withoutData; -const DATE_WITH_POD_WITH_DATA = DATES.metricsAndLogs.pods.withData; -const DATE_WITH_DOCKER_DATA_FROM = '2023-03-28T18:20:00.000Z'; -const DATE_WITH_DOCKER_DATA_TO = '2023-03-28T18:21:00.000Z'; -const DATE_WITH_DOCKER_DATA = '03/28/2023 6:20:00 PM'; +const DATE_WITHOUT_DATA = '10/09/2018 10:00:00 PM'; + +const HOSTS = [ + { + hostName: 'host-1', + cpuValue: 0.5, + }, + { + hostName: 'host-2', + cpuValue: 0.7, + }, + { + hostName: 'host-3', + cpuValue: 0.9, + }, + { + hostName: 'host-4', + cpuValue: 0.3, + }, + { + hostName: 'host-5', + cpuValue: 0.1, + }, +]; export default ({ getPageObjects, getService }: FtrProviderContext) => { - const esArchiver = getService('esArchiver'); const browser = getService('browser'); const retry = getService('retry'); const esClient = getService('es'); - const infraSynthtraceKibanaClient = getService('infraSynthtraceKibanaClient'); const pageObjects = getPageObjects([ 'common', 'header', @@ -46,30 +72,20 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { return !!currentUrl.match(path); }); - const setInfrastructureContainerAssetViewUiSetting = async (value: boolean = true) => { - await kibanaServer.uiSettings.update({ [enableInfrastructureContainerAssetView]: value }); - await browser.refresh(); - await pageObjects.header.waitUntilLoadingHasFinished(); - }; - describe('Home page', function () { this.tags('includeFirefox'); + before(async () => { await kibanaServer.savedObjects.cleanStandardList(); }); describe('without metrics present', () => { - before( - async () => - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs') - ); - it('renders an empty data prompt and redirects to the onboarding page', async () => { await pageObjects.common.navigateToApp('infraOps'); await pageObjects.infraHome.noDataPromptExists(); await pageObjects.infraHome.noDataPromptAddDataClick(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}`; @@ -94,16 +110,33 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('with metrics present', () => { + let synthEsClient: InfraSynthtraceEsClient; before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - await esArchiver.load('x-pack/test/functional/es_archives/infra/8.0.0/pods_only'); + synthEsClient = await getInfraSynthtraceEsClient(esClient); + await synthEsClient.clean(); + await synthEsClient.index([ + generateHostData({ + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + hosts: HOSTS, + }), + generateDockerContainersData({ + from: DATE_WITH_DOCKER_DATA_FROM, + to: DATE_WITH_DOCKER_DATA_TO, + count: 5, + }), + generatePodsData({ + from: DATE_WITH_POD_DATA_FROM, + to: DATE_WITH_POD_DATA_TO, + count: 1, + }), + ]); await pageObjects.common.navigateToApp('infraOps'); await pageObjects.infraHome.waitForLoading(); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - await esArchiver.unload('x-pack/test/functional/es_archives/infra/8.0.0/pods_only'); await browser.removeLocalStorageItem(KUBERNETES_TOUR_STORAGE_KEY); + await synthEsClient.clean(); }); it('renders the correct page title', async () => { @@ -137,7 +170,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.infraHome.clickDismissKubernetesTourButton(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await pageObjects.infraHome.ensureKubernetesTourIsClosed(); }); }); @@ -146,22 +179,23 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.infraHome.goToTime(DATE_WITHOUT_DATA); await pageObjects.infraHome.getNoMetricsDataPrompt(); }); + it('renders the waffle map and tooltips for dates with data', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); // await pageObjects.infraHome.getWaffleMapTooltips(); see https://github.com/elastic/kibana/issues/137903 }); describe('Asset Details flyout for a host', () => { before(async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); - await pageObjects.infraHome.inputAddHostNameFilter('demo-stack-nginx-01'); + await pageObjects.infraHome.inputAddHostNameFilter('host-1'); await pageObjects.infraHome.clickOnNode(); }); after(async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await pageObjects.infraHome.clickCloseFlyoutButton(); }); }); @@ -172,10 +206,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); [ - { metric: 'cpuUsage', value: 'N/A' }, - { metric: 'normalizedLoad1m', value: '1.4%' }, - { metric: 'memoryUsage', value: '18.0%' }, - { metric: 'diskUsage', value: '35.0%' }, + { metric: 'cpuUsage', value: '50.0%' }, + { metric: 'normalizedLoad1m', value: '18.8%' }, + { metric: 'memoryUsage', value: '35.0%' }, + { metric: 'diskUsage', value: '1,223.0%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { await retry.tryForTime(3 * 1000, async () => { @@ -237,31 +271,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); describe('Asset Details flyout for a container', () => { - let synthEsClient: InfraSynthtraceEsClient; before(async () => { - await setInfrastructureContainerAssetViewUiSetting(true); - const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion(); - await infraSynthtraceKibanaClient.installSystemPackage(version); - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.index( - generateDockerContainersData({ - from: DATE_WITH_DOCKER_DATA_FROM, - to: DATE_WITH_DOCKER_DATA_TO, - count: 5, - }) - ); - - await pageObjects.infraHome.clickDismissKubernetesTourButton(); await pageObjects.infraHome.goToContainer(); await pageObjects.infraHome.goToTime(DATE_WITH_DOCKER_DATA); await pageObjects.infraHome.clickOnFirstNode(); }); - after(async () => { - await setInfrastructureContainerAssetViewUiSetting(false); - return await synthEsClient.clean(); - }); - describe('Overview Tab', () => { before(async () => { await pageObjects.assetDetails.clickOverviewTab(); @@ -272,7 +287,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'memoryUsage', value: '20.0%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { - await retry.tryForTime(3 * 1000, async () => { + await retry.tryForTime(5000, async () => { const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue( metric ); @@ -327,7 +342,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await pageObjects.infraHome.closeFlyout(); }); }); @@ -339,89 +354,85 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('shows query suggestions', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.clickQueryBar(); await pageObjects.infraHome.inputQueryData(); await pageObjects.infraHome.ensureSuggestionsPanelVisible(); await pageObjects.infraHome.clearSearchTerm(); }); - it.skip('sort nodes by descending value', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + it('sort nodes by descending value', async () => { + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); await pageObjects.infraHome.sortNodesBy('value'); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const nodesWithValue = await pageObjects.infraHome.getNodesWithValues(); expect(nodesWithValue).to.eql([ - { name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' }, - { name: 'demo-stack-mysql-01', value: 1.2, color: '#82a7cd' }, - { name: 'demo-stack-nginx-01', value: 1.1, color: '#93b1d3' }, - { name: 'demo-stack-redis-01', value: 1, color: '#a2bcd9' }, - { name: 'demo-stack-haproxy-01', value: 0.8, color: '#c2d2e6' }, - { name: 'demo-stack-client-01', value: 0.6, color: '#f0f4f9' }, + { name: 'host-3', value: 90, color: '#6092c0' }, + { name: 'host-2', value: 70, color: '#82a7cd' }, + { name: 'host-1', value: 50, color: '#a2bcd9' }, + { name: 'host-4', value: 30, color: '#d1ddec' }, + { name: 'host-5', value: 10, color: '#f0f4f9' }, ]); }); }); - it.skip('sort nodes by ascending value', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + it('sort nodes by ascending value', async () => { + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); await pageObjects.infraHome.sortNodesBy('value'); await pageObjects.infraHome.toggleReverseSort(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const nodesWithValue = await pageObjects.infraHome.getNodesWithValues(); expect(nodesWithValue).to.eql([ - { name: 'demo-stack-client-01', value: 0.6, color: '#f0f4f9' }, - { name: 'demo-stack-haproxy-01', value: 0.8, color: '#c2d2e6' }, - { name: 'demo-stack-redis-01', value: 1, color: '#a2bcd9' }, - { name: 'demo-stack-nginx-01', value: 1.1, color: '#93b1d3' }, - { name: 'demo-stack-mysql-01', value: 1.2, color: '#82a7cd' }, - { name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' }, + { name: 'host-5', value: 10, color: '#f0f4f9' }, + { name: 'host-4', value: 30, color: '#d1ddec' }, + { name: 'host-1', value: 50, color: '#a2bcd9' }, + { name: 'host-2', value: 70, color: '#82a7cd' }, + { name: 'host-3', value: 90, color: '#6092c0' }, ]); }); }); it('group nodes by custom field', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const groups = await pageObjects.infraHome.groupByCustomField('host.os.platform'); expect(groups).to.eql(['ubuntu']); }); }); - it.skip('filter nodes by search term', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + it('filter nodes by search term', async () => { + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); - await pageObjects.infraHome.enterSearchTerm('host.name: "demo-stack-apache-01"'); - await retry.try(async () => { + await pageObjects.infraHome.enterSearchTerm('host.name: "host-1"'); + await retry.tryForTime(5000, async () => { const nodesWithValue = await pageObjects.infraHome.getNodesWithValues(); - expect(nodesWithValue).to.eql([ - { name: 'demo-stack-apache-01', value: 1.4, color: '#6092c0' }, - ]); + expect(nodesWithValue).to.eql([{ name: 'host-1', value: 50, color: '#6092c0' }]); }); await pageObjects.infraHome.clearSearchTerm(); }); - it.skip('change color palette', async () => { + it('change color palette', async () => { + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.openLegendControls(); await pageObjects.infraHome.changePalette('temperature'); await pageObjects.infraHome.applyLegendControls(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const nodesWithValue = await pageObjects.infraHome.getNodesWithValues(); expect(nodesWithValue).to.eql([ - { name: 'demo-stack-client-01', value: 0.6, color: '#6092c0' }, - { name: 'demo-stack-haproxy-01', value: 0.8, color: '#b5c9df' }, - { name: 'demo-stack-redis-01', value: 1, color: '#f1d9b9' }, - { name: 'demo-stack-nginx-01', value: 1.1, color: '#eec096' }, - { name: 'demo-stack-mysql-01', value: 1.2, color: '#eba47a' }, - { name: 'demo-stack-apache-01', value: 1.4, color: '#e7664c' }, + { name: 'host-5', value: 10, color: '#6092c0' }, + { name: 'host-4', value: 30, color: '#9ab6d5' }, + { name: 'host-1', value: 50, color: '#f1d9b9' }, + { name: 'host-2', value: 70, color: '#eba47a' }, + { name: 'host-3', value: 90, color: '#e7664c' }, ]); }); }); it('toggle the timeline', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.getWaffleMap(); await pageObjects.infraHome.openTimeline(); await pageObjects.infraHome.closeTimeline(); @@ -438,62 +449,47 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('Should redirect to Host Details page', async () => { - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); await pageObjects.infraHome.goToHost(); await pageObjects.infraHome.clickOnFirstNode(); await pageObjects.infraHome.clickOnNodeDetailsFlyoutOpenAsPage(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const documentTitle = await browser.getTitle(); expect(documentTitle).to.contain( - 'demo-stack-redis-01 - Inventory - Infrastructure - Observability - Elastic' + 'host-5 - Inventory - Infrastructure - Observability - Elastic' ); }); await returnTo(INVENTORY_PATH); }); - it('Should redirect to Pod Details page', async () => { - await pageObjects.infraHome.goToPods(); - await pageObjects.infraHome.goToTime(DATE_WITH_POD_WITH_DATA); - await pageObjects.infraHome.clickOnFirstNode(); - await pageObjects.infraHome.clickOnGoToNodeDetails(); + describe('Redirect to Pod Details page', () => { + it('should redirect to Pod Details page', async () => { + await pageObjects.infraHome.goToPods(); + await pageObjects.infraHome.goToTime(DATE_WITH_POD_DATA); + await pageObjects.infraHome.clickOnFirstNode(); + await pageObjects.infraHome.clickOnGoToNodeDetails(); - await retry.try(async () => { - const documentTitle = await browser.getTitle(); - expect(documentTitle).to.contain( - 'pod-0 - Inventory - Infrastructure - Observability - Elastic' - ); - }); + await retry.tryForTime(5000, async () => { + const documentTitle = await browser.getTitle(); + expect(documentTitle).to.contain( + 'pod-0 - Inventory - Infrastructure - Observability - Elastic' + ); + }); - await returnTo(INVENTORY_PATH); + await returnTo(INVENTORY_PATH); + }); }); describe('Redirect to Container Details page', () => { - let synthEsClient: InfraSynthtraceEsClient; - before(async () => { - const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion(); - await infraSynthtraceKibanaClient.installSystemPackage(version); - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.index( - generateDockerContainersData({ - from: DATE_WITH_DOCKER_DATA_FROM, - to: DATE_WITH_DOCKER_DATA_TO, - count: 5, - }) - ); - }); - - after(async () => { - return await synthEsClient.clean(); - }); - it('Should redirect to Container Details page', async () => { + it('should redirect to Container Details page', async () => { await pageObjects.infraHome.goToContainer(); await pageObjects.infraHome.goToTime(DATE_WITH_DOCKER_DATA); await pageObjects.infraHome.clickOnFirstNode(); - await pageObjects.infraHome.clickOnGoToNodeDetails(); + await pageObjects.infraHome.clickOnNodeDetailsFlyoutOpenAsPage(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const documentTitle = await browser.getTitle(); expect(documentTitle).to.contain( 'container-id-4 - Inventory - Infrastructure - Observability - Elastic' @@ -534,105 +530,96 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // close await pageObjects.infraHome.clickCustomMetricDropdown(); }); - }); - describe('alerts flyouts', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - await pageObjects.common.navigateToApp('infraOps'); - await pageObjects.infraHome.waitForLoading(); - await pageObjects.infraHome.goToTime(DATE_WITH_DATA); - }); - after( - async () => - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs') - ); - - it('should open and close inventory alert flyout', async () => { - await pageObjects.infraHome.openInventoryAlertFlyout(); - await pageObjects.infraHome.closeAlertFlyout(); - }); + describe('alerts flyouts', () => { + before(async () => { + await pageObjects.common.navigateToApp('infraOps'); + await pageObjects.infraHome.waitForLoading(); + await pageObjects.infraHome.goToTime(DATE_WITH_HOSTS_DATA); + }); - it('should open and close metrics threshold alert flyout', async () => { - await pageObjects.infraHome.openMetricsThresholdAlertFlyout(); - await pageObjects.infraHome.closeAlertFlyout(); - }); + it('should open and close inventory alert flyout', async () => { + await pageObjects.infraHome.openInventoryAlertFlyout(); + await pageObjects.infraHome.closeAlertFlyout(); + }); - it('should open and close alerts popover using button', async () => { - await pageObjects.infraHome.clickAlertsAndRules(); - await pageObjects.infraHome.ensurePopoverOpened(); - await pageObjects.infraHome.clickAlertsAndRules(); - await retry.try(async () => { - await pageObjects.infraHome.ensurePopoverClosed(); + it('should open and close metrics threshold alert flyout', async () => { + await pageObjects.infraHome.openMetricsThresholdAlertFlyout(); + await pageObjects.infraHome.closeAlertFlyout(); }); - }); - it('should not have an option to create custom threshold alert', async () => { - await pageObjects.infraHome.clickAlertsAndRules(); - await pageObjects.infraHome.ensurePopoverOpened(); - await pageObjects.infraHome.ensureCustomThresholdAlertMenuItemIsMissing(); - await pageObjects.infraHome.clickAlertsAndRules(); - }); - }); + it('should open and close alerts popover using button', async () => { + await pageObjects.infraHome.clickAlertsAndRules(); + await pageObjects.infraHome.ensurePopoverOpened(); + await pageObjects.infraHome.clickAlertsAndRules(); + await retry.tryForTime(5000, async () => { + await pageObjects.infraHome.ensurePopoverClosed(); + }); + }); - describe('Saved Views', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - await pageObjects.infraHome.goToMetricExplorer(); + it('should not have an option to create custom threshold alert', async () => { + await pageObjects.infraHome.clickAlertsAndRules(); + await pageObjects.infraHome.ensurePopoverOpened(); + await pageObjects.infraHome.ensureCustomThresholdAlertMenuItemIsMissing(); + await pageObjects.infraHome.clickAlertsAndRules(); + }); }); + describe('Saved Views', () => { + before(async () => { + await pageObjects.infraHome.goToMetricExplorer(); + }); - after(() => esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs')); - - beforeEach(async () => { - await pageObjects.infraSavedViews.clickSavedViewsButton(); - }); - afterEach(async () => { - await pageObjects.infraSavedViews.closeSavedViewsPopover(); - }); + beforeEach(async () => { + await pageObjects.infraSavedViews.clickSavedViewsButton(); + }); + afterEach(async () => { + await pageObjects.infraSavedViews.closeSavedViewsPopover(); + }); - it('should render a button with the view name', async () => { - await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view'); - }); + it('should render a button with the view name', async () => { + await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view'); + }); - it('should open/close the views popover menu on button click', async () => { - await pageObjects.infraSavedViews.clickSavedViewsButton(); - await testSubjects.existOrFail('savedViews-popover'); - await pageObjects.infraSavedViews.closeSavedViewsPopover(); - }); + it('should open/close the views popover menu on button click', async () => { + await pageObjects.infraSavedViews.clickSavedViewsButton(); + await testSubjects.existOrFail('savedViews-popover'); + await pageObjects.infraSavedViews.closeSavedViewsPopover(); + }); - it('should create a new saved view and load it', async () => { - await pageObjects.infraSavedViews.createView('view1'); - await pageObjects.infraSavedViews.ensureViewIsLoaded('view1'); - }); + it('should create a new saved view and load it', async () => { + await pageObjects.infraSavedViews.createView('view1'); + await pageObjects.infraSavedViews.ensureViewIsLoaded('view1'); + }); - it('should load a clicked view from the manage views section', async () => { - const views = await pageObjects.infraSavedViews.getManageViewsEntries(); - await views[0].click(); - await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view'); - }); + it('should load a clicked view from the manage views section', async () => { + const views = await pageObjects.infraSavedViews.getManageViewsEntries(); + await views[0].click(); + await pageObjects.infraSavedViews.ensureViewIsLoaded('Default view'); + }); - it('should update the current saved view and load it', async () => { - let views = await pageObjects.infraSavedViews.getManageViewsEntries(); - expect(views.length).to.equal(2); - await pageObjects.infraSavedViews.pressEsc(); + it('should update the current saved view and load it', async () => { + let views = await pageObjects.infraSavedViews.getManageViewsEntries(); + expect(views.length).to.equal(2); + await pageObjects.infraSavedViews.pressEsc(); - await pageObjects.infraSavedViews.clickSavedViewsButton(); - await pageObjects.infraSavedViews.createView('view2'); - await pageObjects.infraSavedViews.ensureViewIsLoaded('view2'); + await pageObjects.infraSavedViews.clickSavedViewsButton(); + await pageObjects.infraSavedViews.createView('view2'); + await pageObjects.infraSavedViews.ensureViewIsLoaded('view2'); - await pageObjects.infraSavedViews.clickSavedViewsButton(); - views = await pageObjects.infraSavedViews.getManageViewsEntries(); - expect(views.length).to.equal(3); - await pageObjects.infraSavedViews.pressEsc(); + await pageObjects.infraSavedViews.clickSavedViewsButton(); + views = await pageObjects.infraSavedViews.getManageViewsEntries(); + expect(views.length).to.equal(3); + await pageObjects.infraSavedViews.pressEsc(); - await pageObjects.infraSavedViews.clickSavedViewsButton(); - await pageObjects.infraSavedViews.updateView('view3'); - await pageObjects.infraSavedViews.ensureViewIsLoaded('view3'); + await pageObjects.infraSavedViews.clickSavedViewsButton(); + await pageObjects.infraSavedViews.updateView('view3'); + await pageObjects.infraSavedViews.ensureViewIsLoaded('view3'); - await pageObjects.infraSavedViews.clickSavedViewsButton(); - views = await pageObjects.infraSavedViews.getManageViewsEntries(); - expect(views.length).to.equal(3); - await pageObjects.infraSavedViews.pressEsc(); + await pageObjects.infraSavedViews.clickSavedViewsButton(); + views = await pageObjects.infraSavedViews.getManageViewsEntries(); + expect(views.length).to.equal(3); + await pageObjects.infraSavedViews.pressEsc(); + }); }); }); }); diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index cc4c53594a3c3..06464b0f962f8 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -7,11 +7,12 @@ import moment from 'moment'; import expect from '@kbn/expect'; -import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; import { - enableInfrastructureAssetCustomDashboards, - enableInfrastructureHostsView, -} from '@kbn/observability-plugin/common'; + ApmSynthtraceEsClient, + InfraSynthtraceEsClient, + LogsSynthtraceEsClient, +} from '@kbn/apm-synthtrace'; +import { enableInfrastructureAssetCustomDashboards } from '@kbn/observability-plugin/common'; import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -20,14 +21,24 @@ import { HOSTS_LINK_LOCAL_STORAGE_KEY, HOSTS_VIEW_PATH, DATE_PICKER_FORMAT, + DATE_WITH_HOSTS_DATA_FROM, + DATE_WITH_HOSTS_DATA_TO, } from './constants'; -import { generateAddServicesToExistingHost } from './helpers'; +import { + generateAddServicesToExistingHost, + generateHostData, + generateLogsDataForHosts, +} from './helpers'; import { getApmSynthtraceEsClient } from '../../../common/utils/synthtrace/apm_es_client'; +import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client'; +import { getLogsSynthtraceEsClient } from '../../../common/utils/synthtrace/logs_es_client'; const START_DATE = moment.utc(DATES.metricsAndLogs.hosts.min); const END_DATE = moment.utc(DATES.metricsAndLogs.hosts.max); -const START_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataStartDate); -const END_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataEndDate); + +// synthtrace data dates +const START_SYNTHTRACE_DATE = moment.utc(DATE_WITH_HOSTS_DATA_FROM); +const END_SYNTHTRACE_DATE = moment.utc(DATE_WITH_HOSTS_DATA_TO); const tableEntries = [ { @@ -98,6 +109,96 @@ const tableEntries = [ }, ]; +const synthtraceHostsTableEntries = [ + { + title: 'host-1', + cpuUsage: '90%', + normalizedLoad: '18.8%', + memoryUsage: '35%', + memoryFree: '44.7 GB', + diskSpaceUsage: '1,223%', + rx: '1.5 Mbit/s', + tx: '1.5 Mbit/s', + }, + { + title: 'host-2', + cpuUsage: '70%', + normalizedLoad: '18.8%', + memoryUsage: '35%', + memoryFree: '44.7 GB', + diskSpaceUsage: '1,223%', + rx: '1.5 Mbit/s', + tx: '1.5 Mbit/s', + }, + { + title: 'host-3', + cpuUsage: '50%', + normalizedLoad: '18.8%', + memoryUsage: '35%', + memoryFree: '44.7 GB', + diskSpaceUsage: '1,223%', + rx: '1.5 Mbit/s', + tx: '1.5 Mbit/s', + }, + { + title: 'host-4', + cpuUsage: '40%', + normalizedLoad: '18.8%', + memoryUsage: '35%', + memoryFree: '44.7 GB', + diskSpaceUsage: '1,223%', + rx: '1.5 Mbit/s', + tx: '1.5 Mbit/s', + }, + { + title: 'host-5', + cpuUsage: '30%', + normalizedLoad: '18.8%', + memoryUsage: '35%', + memoryFree: '44.7 GB', + diskSpaceUsage: '1,223%', + rx: '1.5 Mbit/s', + tx: '1.5 Mbit/s', + }, + { + title: 'host-6', + cpuUsage: '10%', + normalizedLoad: '18.8%', + memoryUsage: '35%', + memoryFree: '44.7 GB', + diskSpaceUsage: '1,223%', + rx: '1.5 Mbit/s', + tx: '1.5 Mbit/s', + }, +]; + +const SYNTH_HOSTS = [ + { + hostName: 'host-1', + cpuValue: 0.9, + }, + { + hostName: 'host-2', + cpuValue: 0.7, + }, + { + hostName: 'host-3', + cpuValue: 0.5, + }, + { + hostName: 'host-4', + cpuValue: 0.4, + }, + { + hostName: 'host-5', + cpuValue: 0.3, + }, + { + hostName: 'host-6', + cpuValue: 0.1, + }, +]; + export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const security = getService('security'); @@ -126,7 +227,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const loginWithReadOnlyUserAndNavigateToHostsFlyout = async () => { await security.role.create('global_hosts_read_privileges_role', { elasticsearch: { - indices: [{ names: ['metricbeat-*'], privileges: ['read', 'view_index_metadata'] }], + indices: [ + { names: ['metrics-*'], privileges: ['read', 'view_index_metadata'] }, + { names: ['metricbeat-*'], privileges: ['read', 'view_index_metadata'] }, + ], }, kibana: [ { @@ -158,8 +262,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.timePicker.setAbsoluteRange( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT), - END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) + START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT), + END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT) ); await waitForPageToLoad(); @@ -175,9 +279,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); }; - const setHostViewEnabled = (value: boolean = true) => - kibanaServer.uiSettings.update({ [enableInfrastructureHostsView]: value }); - const setCustomDashboardsEnabled = (value: boolean = true) => kibanaServer.uiSettings.update({ [enableInfrastructureAssetCustomDashboards]: value }); @@ -198,9 +299,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); describe('Hosts View', function () { + let synthEsInfraClient: InfraSynthtraceEsClient; + let syntEsLogsClient: LogsSynthtraceEsClient; + describe('#Onboarding', function () { before(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + synthEsInfraClient = await getInfraSynthtraceEsClient(esClient); + await synthEsInfraClient.clean(); await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); }); @@ -208,7 +313,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.infraHome.noDataPromptExists(); await pageObjects.infraHome.noDataPromptAddDataClick(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}`; @@ -221,6 +326,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('#With data', function () { let synthtraceApmClient: ApmSynthtraceEsClient; before(async () => { + synthEsInfraClient = await getInfraSynthtraceEsClient(esClient); + syntEsLogsClient = await getLogsSynthtraceEsClient(esClient); const version = (await apmSynthtraceKibanaClient.installApmPackage()).version; synthtraceApmClient = await getApmSynthtraceEsClient({ client: esClient, @@ -228,19 +335,30 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); const services = generateAddServicesToExistingHost({ - from: DATES.metricsAndLogs.hosts.processesDataStartDate, - to: DATES.metricsAndLogs.hosts.processesDataEndDate, - hostName: 'Jennys-MBP.fritz.box', + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + hostName: 'host-1', servicesPerHost: 3, }); + const logs = generateLogsDataForHosts({ + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + hosts: SYNTH_HOSTS, + }); + await browser.setWindowSize(1600, 1200); return Promise.all([ synthtraceApmClient.index(services), - esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'), - esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'), - esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'), + synthEsInfraClient.index( + generateHostData({ + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + hosts: SYNTH_HOSTS, + }) + ), + syntEsLogsClient.index(logs), ]); }); @@ -248,9 +366,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { return Promise.all([ apmSynthtraceKibanaClient.uninstallApmPackage(), synthtraceApmClient.clean(), - esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'), - esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'), - esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'), + synthEsInfraClient.clean(), browser.removeLocalStorageItem(HOSTS_LINK_LOCAL_STORAGE_KEY), ]); }); @@ -269,7 +385,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('#Single Host Flyout', () => { before(async () => { - await setHostViewEnabled(true); await setCustomDashboardsEnabled(true); await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); await pageObjects.header.waitUntilLoadingHasFinished(); @@ -278,8 +393,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Tabs', () => { before(async () => { await pageObjects.timePicker.setAbsoluteRange( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT), - END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) + START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT), + END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT) ); await waitForPageToLoad(); @@ -288,7 +403,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await pageObjects.infraHome.clickCloseFlyoutButton(); }); }); @@ -299,13 +414,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); [ - { metric: 'cpuUsage', value: '13.9%' }, + { metric: 'cpuUsage', value: '48.3%' }, { metric: 'normalizedLoad1m', value: '18.8%' }, - { metric: 'memoryUsage', value: '94.9%' }, - { metric: 'diskUsage', value: 'N/A' }, + { metric: 'memoryUsage', value: '35.0%' }, + { metric: 'diskUsage', value: '1,223.0%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue( metric ); @@ -374,7 +489,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.header.waitUntilLoadingHasFinished(); const addedFilter = await pageObjects.assetDetails.getMetadataAppliedFilter(); - expect(addedFilter).to.contain('host.architecture: arm64'); + expect(addedFilter).to.contain('host.name: host-1'); const removeFilterExists = await pageObjects.assetDetails.metadataRemoveFilterExists(); expect(removeFilterExists).to.be(true); @@ -403,8 +518,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.assetDetails.clickProcessesTab(); }); - it('should show processes table', async () => { - await pageObjects.assetDetails.processesTableExists(); + it('should show processes content', async () => { + await pageObjects.assetDetails.processesContentExist(); }); }); @@ -432,10 +547,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should navigate to Host Details page after click', async () => { await pageObjects.assetDetails.clickOpenAsPageLink(); const dateRange = await pageObjects.timePicker.getTimeConfigAsAbsoluteTimes(); - expect(dateRange.start).to.equal( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) - ); - expect(dateRange.end).to.equal(END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT)); + expect(dateRange.start).to.equal(START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT)); + expect(dateRange.end).to.equal(END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT)); await returnTo(HOSTS_VIEW_PATH); }); @@ -443,14 +556,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - describe('#Page Content', () => { + describe('#Page Content without alerts', () => { before(async () => { - await setHostViewEnabled(true); await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.timePicker.setAbsoluteRange( - START_DATE.format(DATE_PICKER_FORMAT), - END_DATE.format(DATE_PICKER_FORMAT) + START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT), + END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT) ); await waitForPageToLoad(); @@ -479,7 +591,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should render the computed metrics for each host entry', async () => { for (let i = 0; i < hostRows.length; i++) { const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]); - expect(hostRowData).to.eql(tableEntries[i]); + expect(hostRowData).to.eql(synthtraceHostsTableEntries[i]); } }); @@ -488,8 +600,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.infraHostsView.selectedHostsButtonExist(); expect(selectHostsButtonExistsOnLoad).to.be(false); - await pageObjects.infraHostsView.clickHostCheckbox('demo-stack-client-01', '-'); - await pageObjects.infraHostsView.clickHostCheckbox('demo-stack-apache-01', '-'); + await pageObjects.infraHostsView.clickHostCheckbox('host-1', 'Linux'); + await pageObjects.infraHostsView.clickHostCheckbox('host-2', 'Linux'); const selectHostsButtonExistsOnSelection = await pageObjects.infraHostsView.selectedHostsButtonExist(); @@ -503,7 +615,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(hostRowsAfterFilter.length).to.equal(2); const deleteFilterButton = await find.byCssSelector( - `[title="Delete host.name: demo-stack-client-01 OR host.name: demo-stack-apache-01"]` + `[title="Delete host.name: host-1 OR host.name: host-2"]` ); await deleteFilterButton.click(); await pageObjects.header.waitUntilLoadingHasFinished(); @@ -518,16 +630,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.timePicker.setAbsoluteRange( - START_DATE.format(DATE_PICKER_FORMAT), - END_DATE.format(DATE_PICKER_FORMAT) + START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT), + END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT) ); await waitForPageToLoad(); }); it('should maintain the selected date range when navigating to the individual host details', async () => { - const start = START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT); - const end = END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT); + const start = START_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT); + const end = END_SYNTHTRACE_DATE.format(DATE_PICKER_FORMAT); await pageObjects.timePicker.setAbsoluteRange(start, end); @@ -549,13 +661,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('KPIs', () => { [ { metric: 'hostsCount', value: '6' }, - { metric: 'cpuUsage', value: 'N/A' }, - { metric: 'normalizedLoad1m', value: '0.3%' }, - { metric: 'memoryUsage', value: '16.8%' }, - { metric: 'diskUsage', value: '35.7%' }, + { metric: 'cpuUsage', value: '48.3%' }, + { metric: 'normalizedLoad1m', value: '18.8%' }, + { metric: 'memoryUsage', value: '35.0%' }, + { metric: 'diskUsage', value: '1,223.0%' }, ].forEach(({ metric, value }) => { it(`${metric} tile should show ${value}`, async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const tileValue = metric === 'hostsCount' ? await pageObjects.infraHostsView.getKPITileValue(metric) @@ -583,7 +695,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should have an option to open the chart in lens', async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await pageObjects.infraHostsView.clickAndValidateMetricChartActionOptions(); await browser.pressKeys(browser.keys.ESCAPE); }); @@ -605,7 +717,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should load the Logs tab with the right columns', async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const columnLabels = await pageObjects.infraHostsView.getLogsTableColumnHeaders(); expect(columnLabels).to.eql(['Timestamp', 'host.name', 'Message']); @@ -613,6 +725,115 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); + describe('Pagination and Sorting', () => { + before(async () => { + await browser.scrollTop(); + }); + + after(async () => { + await browser.scrollTop(); + }); + + beforeEach(async () => { + await retry.tryForTime(5000, async () => { + await pageObjects.infraHostsView.changePageSize(5); + }); + }); + + it('should show 5 rows on the first page', async () => { + const hostRows = await pageObjects.infraHostsView.getHostsTableData(); + + for (let i = 0; i < hostRows.length; i++) { + const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]); + expect(hostRowData).to.eql(synthtraceHostsTableEntries[i]); + } + }); + + it('should paginate to the last page', async () => { + await pageObjects.infraHostsView.paginateTo(2); + const hostRows = await pageObjects.infraHostsView.getHostsTableData(); + + expect(hostRows.length).to.equal(1); + + const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostRowData).to.eql(synthtraceHostsTableEntries[5]); + }); + + it('should show all hosts on the same page', async () => { + await pageObjects.infraHostsView.changePageSize(10); + const hostRows = await pageObjects.infraHostsView.getHostsTableData(); + + for (let i = 0; i < hostRows.length; i++) { + const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]); + expect(hostRowData).to.eql(synthtraceHostsTableEntries[i]); + } + }); + + it('should sort by a numeric field asc', async () => { + await pageObjects.infraHostsView.sortByCpuUsage(); + let hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[5]); + + await pageObjects.infraHostsView.paginateTo(2); + hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[0]); + }); + + it('should sort by a numeric field desc', async () => { + await pageObjects.infraHostsView.sortByCpuUsage(); + let hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[0]); + + await pageObjects.infraHostsView.paginateTo(2); + hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[5]); + }); + + it('should sort by text field asc', async () => { + await pageObjects.infraHostsView.sortByTitle(); + let hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[0]); + + await pageObjects.infraHostsView.paginateTo(2); + hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[5]); + }); + + it('should sort by text field desc', async () => { + await pageObjects.infraHostsView.sortByTitle(); + let hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataFirtPage).to.eql(synthtraceHostsTableEntries[5]); + + await pageObjects.infraHostsView.paginateTo(2); + hostRows = await pageObjects.infraHostsView.getHostsTableData(); + const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); + expect(hostDataLastPage).to.eql(synthtraceHostsTableEntries[0]); + }); + }); + }); + + describe('#Page Content with alerts', () => { + before(async () => { + return Promise.all([ + esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'), + esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'), + ]); + }); + + after(async () => { + return Promise.all([ + esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'), + esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'), + ]); + }); + describe('Alerts Tab', () => { const ACTIVE_ALERTS = 6; const RECOVERED_ALERTS = 4; @@ -620,6 +841,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const COLUMNS = 11; before(async () => { + await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_DATE.format(DATE_PICKER_FORMAT), + END_DATE.format(DATE_PICKER_FORMAT) + ); + + await waitForPageToLoad(); await browser.scrollTop(); await pageObjects.infraHostsView.visitAlertTab(); }); @@ -641,7 +870,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('#FilterButtonGroup', () => { it('can be filtered to only show "all" alerts using the filter button', async () => { await pageObjects.infraHostsView.setAlertStatusFilter(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const tableRows = await observability.alerts.common.getTableCellsInRows(); expect(tableRows.length).to.be(ALL_ALERTS); }); @@ -649,7 +878,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('can be filtered to only show "active" alerts using the filter button', async () => { await pageObjects.infraHostsView.setAlertStatusFilter(ALERT_STATUS_ACTIVE); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const tableRows = await observability.alerts.common.getTableCellsInRows(); expect(tableRows.length).to.be(ACTIVE_ALERTS); }); @@ -657,7 +886,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('can be filtered to only show "recovered" alerts using the filter button', async () => { await pageObjects.infraHostsView.setAlertStatusFilter(ALERT_STATUS_RECOVERED); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const tableRows = await observability.alerts.common.getTableCellsInRows(); expect(tableRows.length).to.be(RECOVERED_ALERTS); }); @@ -671,7 +900,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should renders the correct number of cells', async () => { await pageObjects.infraHostsView.setAlertStatusFilter(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const cells = await observability.alerts.common.getTableCells(); expect(cells.length).to.be(ALL_ALERTS * COLUMNS); }); @@ -685,6 +914,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const query = filtererEntries.map((entry) => `host.name :"${entry.title}"`).join(' or '); before(async () => { + await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_DATE.format(DATE_PICKER_FORMAT), + END_DATE.format(DATE_PICKER_FORMAT) + ); + + await waitForPageToLoad(); await browser.scrollTop(); await pageObjects.infraHostsView.submitQuery(query); await await waitForPageToLoad(); @@ -701,7 +938,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(hostRows.length).to.equal(3); for (let i = 0; i < hostRows.length; i++) { - const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]); + const hostRowData = await pageObjects.infraHostsView.getHostsRowDataWithAlerts( + hostRows[i] + ); expect(hostRowData).to.eql(filtererEntries[i]); } }); @@ -715,7 +954,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { metric: 'memoryUsage', value: '17.5%' }, { metric: 'diskUsage', value: '35.7%' }, ].map(async ({ metric, value }) => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const tileValue = metric === 'hostsCount' ? await pageObjects.infraHostsView.getKPITileValue(metric) @@ -741,7 +980,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.infraHostsView.visitAlertTab(); await pageObjects.infraHostsView.setAlertStatusFilter(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const cells = await observability.alerts.common.getTableCells(); expect(cells.length).to.be(ALL_ALERTS * COLUMNS); }); @@ -757,104 +996,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await waitForPageToLoad(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await testSubjects.exists('hostsViewTableNoData'); }); }); }); - - describe('Pagination and Sorting', () => { - before(async () => { - await browser.scrollTop(); - }); - - after(async () => { - await browser.scrollTop(); - }); - - beforeEach(async () => { - await retry.try(async () => { - await pageObjects.infraHostsView.changePageSize(5); - }); - }); - - it('should show 5 rows on the first page', async () => { - const hostRows = await pageObjects.infraHostsView.getHostsTableData(); - - for (let i = 0; i < hostRows.length; i++) { - const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]); - expect(hostRowData).to.eql(tableEntries[i]); - } - }); - - it('should paginate to the last page', async () => { - await pageObjects.infraHostsView.paginateTo(2); - const hostRows = await pageObjects.infraHostsView.getHostsTableData(); - - expect(hostRows.length).to.equal(1); - - const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostRowData).to.eql(tableEntries[5]); - }); - - it('should show all hosts on the same page', async () => { - await pageObjects.infraHostsView.changePageSize(10); - const hostRows = await pageObjects.infraHostsView.getHostsTableData(); - - for (let i = 0; i < hostRows.length; i++) { - const hostRowData = await pageObjects.infraHostsView.getHostsRowData(hostRows[i]); - expect(hostRowData).to.eql(tableEntries[i]); - } - }); - - it('should sort by a numeric field asc', async () => { - await pageObjects.infraHostsView.sortByMemoryUsage(); - let hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataFirtPage).to.eql(tableEntries[3]); - - await pageObjects.infraHostsView.paginateTo(2); - hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataLastPage).to.eql(tableEntries[0]); - }); - - it('should sort by a numeric field desc', async () => { - await pageObjects.infraHostsView.sortByMemoryUsage(); - let hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataFirtPage).to.eql(tableEntries[0]); - - await pageObjects.infraHostsView.paginateTo(2); - hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataLastPage).to.eql(tableEntries[3]); - }); - - it('should sort by text field asc', async () => { - await pageObjects.infraHostsView.sortByTitle(); - let hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataFirtPage).to.eql(tableEntries[0]); - - await pageObjects.infraHostsView.paginateTo(2); - hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataLastPage).to.eql(tableEntries[2]); - }); - - it('should sort by text field desc', async () => { - await pageObjects.infraHostsView.sortByTitle(); - let hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataFirtPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataFirtPage).to.eql(tableEntries[2]); - - await pageObjects.infraHostsView.paginateTo(2); - hostRows = await pageObjects.infraHostsView.getHostsTableData(); - const hostDataLastPage = await pageObjects.infraHostsView.getHostsRowData(hostRows[0]); - expect(hostDataLastPage).to.eql(tableEntries[0]); - }); - }); }); describe('#Permissions: Read Only User - Single Host Flyout', () => { @@ -866,7 +1012,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await pageObjects.infraHome.clickCloseFlyoutButton(); }); await logoutAndDeleteReadOnlyUser(); @@ -875,7 +1021,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should render dashboards tab splash screen with disabled option to add dashboard', async () => { await pageObjects.assetDetails.addDashboardExists(); const elementToHover = await pageObjects.assetDetails.getAddDashboardButton(); - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await elementToHover.moveMouseTo(); await testSubjects.existOrFail('infraCannotAddDashboardTooltip'); }); diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts index 2fe8901323db1..4d31091caabb5 100644 --- a/x-pack/test/functional/apps/infra/node_details.ts +++ b/x-pack/test/functional/apps/infra/node_details.ts @@ -25,24 +25,47 @@ import { DATE_PICKER_FORMAT, DATE_WITH_DOCKER_DATA_FROM, DATE_WITH_DOCKER_DATA_TO, + DATE_WITH_HOSTS_DATA_FROM, + DATE_WITH_HOSTS_DATA_TO, } from './constants'; import { getInfraSynthtraceEsClient } from '../../../common/utils/synthtrace/infra_es_client'; -import { generateDockerContainersData } from './helpers'; +import { + generateDockerContainersData, + generateHostData, + generateHostsWithK8sNodeData, +} from './helpers'; const START_HOST_ALERTS_DATE = moment.utc(DATES.metricsAndLogs.hosts.min); const END_HOST_ALERTS_DATE = moment.utc(DATES.metricsAndLogs.hosts.max); const START_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataStartDate); const END_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataEndDate); - -const START_HOST_KUBERNETES_SECTION_DATE = moment.utc( - DATES.metricsAndLogs.hosts.kubernetesSectionStartDate -); -const END_HOST_KUBERNETES_SECTION_DATE = moment.utc( - DATES.metricsAndLogs.hosts.kubernetesSectionEndDate -); +const START_HOST_DATE = moment.utc(DATE_WITH_HOSTS_DATA_FROM); +const END_HOST_DATE = moment.utc(DATE_WITH_HOSTS_DATA_TO); const START_CONTAINER_DATE = moment.utc(DATE_WITH_DOCKER_DATA_FROM); const END_CONTAINER_DATE = moment.utc(DATE_WITH_DOCKER_DATA_TO); +const HOSTS = [ + { + hostName: 'host-1', + cpuValue: 0.5, + }, + { + hostName: 'host-2', + cpuValue: 0.7, + }, + { + hostName: 'host-3', + cpuValue: 0.9, + }, + { + hostName: 'host-4', + cpuValue: 0.3, + }, + { + hostName: 'host-5', + cpuValue: 0.1, + }, +]; interface QueryParams { name?: string; alertMetric?: string; @@ -53,7 +76,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const browser = getService('browser'); const kibanaServer = getService('kibanaServer'); const esArchiver = getService('esArchiver'); - const infraSynthtraceKibanaClient = getService('infraSynthtraceKibanaClient'); const esClient = getService('es'); const retry = getService('retry'); const testSubjects = getService('testSubjects'); @@ -114,28 +136,52 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; describe('Node Details', () => { - describe('#With Asset Details', () => { - before(async () => { - await Promise.all([ - esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'), - esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'), - esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'), - kibanaServer.savedObjects.cleanStandardList(), - ]); - await browser.setWindowSize(1600, 1200); + let synthEsClient: InfraSynthtraceEsClient; + before(async () => { + synthEsClient = await getInfraSynthtraceEsClient(esClient); + await synthEsClient.clean(); + await kibanaServer.savedObjects.cleanStandardList(); + await browser.setWindowSize(1600, 1200); + }); + + after(async () => { + await synthEsClient.clean(); + }); - await navigateToNodeDetails('Jennys-MBP.fritz.box', 'host', { - name: 'Jennys-MBP.fritz.box', + describe('#Asset Type: host', () => { + before(async () => { + synthEsClient = await getInfraSynthtraceEsClient(esClient); + await synthEsClient.clean(); + await synthEsClient.index( + generateHostData({ + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + hosts: HOSTS, + }) + ); + await navigateToNodeDetails('host-1', 'host', { + name: 'host-1', }); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) + ); }); after(async () => { - await Promise.all([ - esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'), - esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'), - esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'), - ]); + await synthEsClient.clean(); + }); + + it('preserves selected tab between page reloads', async () => { + await testSubjects.missingOrFail('infraAssetDetailsMetadataTable'); + await pageObjects.assetDetails.clickMetadataTab(); + await pageObjects.assetDetails.metadataTableExists(); + + await refreshPageWithDelay(); + + await pageObjects.assetDetails.metadataTableExists(); }); describe('#Date picker: host', () => { @@ -143,8 +189,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.assetDetails.clickOverviewTab(); await pageObjects.timePicker.setAbsoluteRange( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT), - END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) ); }); @@ -172,18 +218,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const datePickerValue = await pageObjects.timePicker.getTimeConfig(); expect(await pageObjects.timePicker.timePickerExists()).to.be(true); - expect(datePickerValue.start).to.equal( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) - ); - expect(datePickerValue.end).to.equal( - END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) - ); + expect(datePickerValue.start).to.equal(START_HOST_DATE.format(DATE_PICKER_FORMAT)); + expect(datePickerValue.end).to.equal(END_HOST_DATE.format(DATE_PICKER_FORMAT)); }); }); it('preserves selected date range between page reloads', async () => { - const start = moment.utc(START_HOST_ALERTS_DATE).format(DATE_PICKER_FORMAT); - const end = moment.utc(END_HOST_ALERTS_DATE).format(DATE_PICKER_FORMAT); + const start = moment.utc(START_HOST_DATE).format(DATE_PICKER_FORMAT); + const end = moment.utc(END_HOST_DATE).format(DATE_PICKER_FORMAT); await pageObjects.timePicker.setAbsoluteRange(start, end); await refreshPageWithDelay(); @@ -195,614 +237,634 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - describe('#Asset Type: host', () => { + describe('Overview Tab', () => { before(async () => { + await pageObjects.assetDetails.clickOverviewTab(); await pageObjects.timePicker.setAbsoluteRange( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT), - END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) ); }); - it('preserves selected tab between page reloads', async () => { - await testSubjects.missingOrFail('infraAssetDetailsMetadataTable'); - await pageObjects.assetDetails.clickMetadataTab(); - await pageObjects.assetDetails.metadataTableExists(); + [ + { metric: 'cpuUsage', value: '50.0%' }, + { metric: 'normalizedLoad1m', value: '18.8%' }, + { metric: 'memoryUsage', value: '35.0%' }, + { metric: 'diskUsage', value: '1,223.0%' }, + ].forEach(({ metric, value }) => { + it(`${metric} tile should show ${value}`, async () => { + await retry.tryForTime(3 * 1000, async () => { + const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(metric); + expect(tileValue).to.eql(value); + }); + }); + }); - await refreshPageWithDelay(); + [ + { metric: 'cpu', chartsCount: 2 }, + { metric: 'memory', chartsCount: 1 }, + { metric: 'disk', chartsCount: 2 }, + { metric: 'network', chartsCount: 1 }, + ].forEach(({ metric, chartsCount }) => { + it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { + const hosts = await pageObjects.assetDetails.getOverviewTabHostMetricCharts(metric); + expect(hosts.length).to.equal(chartsCount); + }); + }); - await pageObjects.assetDetails.metadataTableExists(); + it('should show all section as collapsable', async () => { + await pageObjects.assetDetails.metadataSectionCollapsibleExist(); + await pageObjects.assetDetails.alertsSectionCollapsibleExist(); + await pageObjects.assetDetails.metricsSectionCollapsibleExist(); + await pageObjects.assetDetails.servicesSectionCollapsibleExist(); }); - describe('Overview Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickOverviewTab(); - }); + it('should show alerts', async () => { + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.assetDetails.overviewAlertsTitleExists(); + }); - [ - { metric: 'cpuUsage', value: '13.9%' }, - { metric: 'normalizedLoad1m', value: '18.8%' }, - { metric: 'memoryUsage', value: '94.9%' }, - { metric: 'diskUsage', value: 'N/A' }, - ].forEach(({ metric, value }) => { - it(`${metric} tile should show ${value}`, async () => { - await retry.tryForTime(3 * 1000, async () => { - const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue( - metric - ); - expect(tileValue).to.eql(value); - }); - }); - }); + it('should show / hide alerts section with no alerts and show / hide closed section content', async () => { + await pageObjects.assetDetails.alertsSectionCollapsibleExist(); + // Collapsed by default + await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsExist(); + // Expand + await pageObjects.assetDetails.alertsSectionCollapsibleClick(); + await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsMissing(); + }); - [ - { metric: 'cpu', chartsCount: 2 }, - { metric: 'memory', chartsCount: 1 }, - { metric: 'disk', chartsCount: 2 }, - { metric: 'network', chartsCount: 1 }, - ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { - const hosts = await pageObjects.assetDetails.getOverviewTabHostMetricCharts(metric); - expect(hosts.length).to.equal(chartsCount); + it('shows the CPU Profiling prompt if UI setting for Profiling integration is enabled', async () => { + await setInfrastructureProfilingIntegrationUiSetting(true); + await pageObjects.assetDetails.cpuProfilingPromptExists(); + }); + + it('hides the CPU Profiling prompt if UI setting for Profiling integration is disabled', async () => { + await setInfrastructureProfilingIntegrationUiSetting(false); + await pageObjects.assetDetails.cpuProfilingPromptMissing(); + }); + + describe('Alerts Section with alerts', () => { + const ACTIVE_ALERTS = 2; + const RECOVERED_ALERTS = 2; + const ALL_ALERTS = ACTIVE_ALERTS + RECOVERED_ALERTS; + const COLUMNS = 11; + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/infra/alerts'); + await navigateToNodeDetails('demo-stack-apache-01', 'host', { + name: 'demo-stack-apache-01', }); - }); + await pageObjects.header.waitUntilLoadingHasFinished(); - it('should show all section as collapsable', async () => { - await pageObjects.assetDetails.metadataSectionCollapsibleExist(); - await pageObjects.assetDetails.alertsSectionCollapsibleExist(); - await pageObjects.assetDetails.metricsSectionCollapsibleExist(); - await pageObjects.assetDetails.servicesSectionCollapsibleExist(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT), + END_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT) + ); + + await pageObjects.assetDetails.clickOverviewTab(); }); - it('should show alerts', async () => { + after(async () => { + await navigateToNodeDetails('host-1', 'host', { + name: 'host-1', + }); await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.assetDetails.overviewAlertsTitleExists(); + await esArchiver.unload('x-pack/test/functional/es_archives/infra/alerts'); }); - it('should show / hide alerts section with no alerts and show / hide closed section content', async () => { + it('should show / hide alerts section with active alerts and show / hide closed section content', async () => { await pageObjects.assetDetails.alertsSectionCollapsibleExist(); - // Collapsed by default - await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsExist(); + // Expanded by default + await pageObjects.assetDetails.alertsSectionClosedContentMissing(); + // Collapse + await pageObjects.assetDetails.alertsSectionCollapsibleClick(); + await pageObjects.assetDetails.alertsSectionClosedContentExist(); // Expand await pageObjects.assetDetails.alertsSectionCollapsibleClick(); - await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsMissing(); - }); - - it('shows the CPU Profiling prompt if UI setting for Profiling integration is enabled', async () => { - await setInfrastructureProfilingIntegrationUiSetting(true); - await pageObjects.assetDetails.cpuProfilingPromptExists(); + await pageObjects.assetDetails.alertsSectionClosedContentMissing(); }); - it('hides the CPU Profiling prompt if UI setting for Profiling integration is disabled', async () => { - await setInfrastructureProfilingIntegrationUiSetting(false); - await pageObjects.assetDetails.cpuProfilingPromptMissing(); + it('should show alert summary ', async () => { + await pageObjects.assetDetails.setAlertStatusFilter(); + await retry.tryForTime(5000, async () => { + const cells = await observability.alerts.common.getTableCells(); + expect(cells.length).to.be(ALL_ALERTS * COLUMNS); + }); }); - describe('Alerts Section with alerts', () => { - const ACTIVE_ALERTS = 2; - const RECOVERED_ALERTS = 2; - const ALL_ALERTS = ACTIVE_ALERTS + RECOVERED_ALERTS; - const COLUMNS = 11; - before(async () => { - await navigateToNodeDetails('demo-stack-apache-01', 'host', { - name: 'demo-stack-apache-01', - }); - await pageObjects.header.waitUntilLoadingHasFinished(); - - await pageObjects.timePicker.setAbsoluteRange( - START_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT), - END_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT) - ); - - await pageObjects.assetDetails.clickOverviewTab(); + it('can be filtered to only show "all" alerts using the filter button', async () => { + await pageObjects.assetDetails.setAlertStatusFilter(); + await retry.tryForTime(5000, async () => { + const tableRows = await observability.alerts.common.getTableCellsInRows(); + expect(tableRows.length).to.be(ALL_ALERTS); }); + }); - after(async () => { - await navigateToNodeDetails('Jennys-MBP.fritz.box', 'host', { - name: 'Jennys-MBP.fritz.box', - }); - await pageObjects.header.waitUntilLoadingHasFinished(); - - await pageObjects.timePicker.setAbsoluteRange( - START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT), - END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) - ); + it('can be filtered to only show "active" alerts using the filter button', async () => { + await pageObjects.assetDetails.setAlertStatusFilter(ALERT_STATUS_ACTIVE); + await retry.tryForTime(5000, async () => { + const tableRows = await observability.alerts.common.getTableCellsInRows(); + expect(tableRows.length).to.be(ACTIVE_ALERTS); }); + const pageUrl = await browser.getCurrentUrl(); + expect(pageUrl).to.contain('alertStatus%3Aactive'); + }); - it('should show / hide alerts section with active alerts and show / hide closed section content', async () => { - await pageObjects.assetDetails.alertsSectionCollapsibleExist(); - // Expanded by default - await pageObjects.assetDetails.alertsSectionClosedContentMissing(); - // Collapse - await pageObjects.assetDetails.alertsSectionCollapsibleClick(); - await pageObjects.assetDetails.alertsSectionClosedContentExist(); - // Expand - await pageObjects.assetDetails.alertsSectionCollapsibleClick(); - await pageObjects.assetDetails.alertsSectionClosedContentMissing(); + it('can be filtered to only show "recovered" alerts using the filter button', async () => { + await pageObjects.assetDetails.setAlertStatusFilter(ALERT_STATUS_RECOVERED); + await retry.tryForTime(5000, async () => { + const tableRows = await observability.alerts.common.getTableCellsInRows(); + expect(tableRows.length).to.be(RECOVERED_ALERTS); }); + const pageUrl = await browser.getCurrentUrl(); + expect(pageUrl).to.contain('alertStatus%3Arecovered'); + }); - it('should show alert summary ', async () => { - await pageObjects.assetDetails.setAlertStatusFilter(); - await retry.try(async () => { - const cells = await observability.alerts.common.getTableCells(); - expect(cells.length).to.be(ALL_ALERTS * COLUMNS); - }); - }); + it('can be filtered to only show "untracked" alerts using the filter button', async () => { + await pageObjects.assetDetails.setAlertStatusFilter(ALERT_STATUS_UNTRACKED); + await observability.alerts.common.getNoDataStateOrFail(); + const pageUrl = await browser.getCurrentUrl(); + expect(pageUrl).to.contain('alertStatus%3Auntracked'); + }); - it('can be filtered to only show "all" alerts using the filter button', async () => { - await pageObjects.assetDetails.setAlertStatusFilter(); - await retry.try(async () => { - const tableRows = await observability.alerts.common.getTableCellsInRows(); - expect(tableRows.length).to.be(ALL_ALERTS); - }); - }); + it('should render alerts count for a host inside a flyout', async () => { + await pageObjects.assetDetails.clickOverviewTab(); - it('can be filtered to only show "active" alerts using the filter button', async () => { - await pageObjects.assetDetails.setAlertStatusFilter(ALERT_STATUS_ACTIVE); - await retry.try(async () => { - const tableRows = await observability.alerts.common.getTableCellsInRows(); - expect(tableRows.length).to.be(ACTIVE_ALERTS); - }); - const pageUrl = await browser.getCurrentUrl(); - expect(pageUrl).to.contain('alertStatus%3Aactive'); + await retry.tryForTime(30 * 1000, async () => { + await observability.components.alertSummaryWidget.getFullSizeComponentSelectorOrFail(); }); - it('can be filtered to only show "recovered" alerts using the filter button', async () => { - await pageObjects.assetDetails.setAlertStatusFilter(ALERT_STATUS_RECOVERED); - await retry.try(async () => { - const tableRows = await observability.alerts.common.getTableCellsInRows(); - expect(tableRows.length).to.be(RECOVERED_ALERTS); - }); - const pageUrl = await browser.getCurrentUrl(); - expect(pageUrl).to.contain('alertStatus%3Arecovered'); - }); + const activeAlertsCount = + await observability.components.alertSummaryWidget.getActiveAlertCount(); + const totalAlertsCount = + await observability.components.alertSummaryWidget.getTotalAlertCount(); - it('can be filtered to only show "untracked" alerts using the filter button', async () => { - await pageObjects.assetDetails.setAlertStatusFilter(ALERT_STATUS_UNTRACKED); - await observability.alerts.common.getNoDataStateOrFail(); - const pageUrl = await browser.getCurrentUrl(); - expect(pageUrl).to.contain('alertStatus%3Auntracked'); - }); + expect(activeAlertsCount.trim()).to.equal('2'); + expect(totalAlertsCount.trim()).to.equal('4'); }); - }); - describe('Metadata Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickMetadataTab(); + it('should render "N/A" when processes summary is not available in flyout', async () => { + await pageObjects.assetDetails.clickProcessesTab(); + const processesTotalValue = + await pageObjects.assetDetails.getProcessesTabContentTotalValue(); + const processValue = await processesTotalValue.getVisibleText(); + expect(processValue).to.eql('N/A'); }); + }); + }); - it('should show metadata table', async () => { - await pageObjects.assetDetails.metadataTableExists(); - }); + describe('Metadata Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickMetadataTab(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) + ); + }); - it('should render metadata tab, pin and unpin table row', async () => { - // Add Pin - await pageObjects.assetDetails.clickAddMetadataPin(); - expect(await pageObjects.assetDetails.metadataRemovePinExists()).to.be(true); + it('should show metadata table', async () => { + await pageObjects.assetDetails.metadataTableExists(); + }); - // Persist pin after refresh - await browser.refresh(); - await retry.try(async () => { - // Temporary until URL state isn't implemented - await pageObjects.assetDetails.clickMetadataTab(); - await pageObjects.infraHome.waitForLoading(); - const removePinExist = await pageObjects.assetDetails.metadataRemovePinExists(); - expect(removePinExist).to.be(true); - }); + it('should render metadata tab, pin and unpin table row', async () => { + // Add Pin + await pageObjects.assetDetails.clickAddMetadataPin(); + expect(await pageObjects.assetDetails.metadataRemovePinExists()).to.be(true); - // Remove Pin - await pageObjects.assetDetails.clickRemoveMetadataPin(); - expect(await pageObjects.assetDetails.metadataRemovePinExists()).to.be(false); + // Persist pin after refresh + await browser.refresh(); + await retry.tryForTime(5000, async () => { + // Temporary until URL state isn't implemented + await pageObjects.assetDetails.clickMetadataTab(); + await pageObjects.infraHome.waitForLoading(); + const removePinExist = await pageObjects.assetDetails.metadataRemovePinExists(); + expect(removePinExist).to.be(true); }); - it('preserves search term between page reloads', async () => { - const searchInput = await pageObjects.assetDetails.getMetadataSearchField(); + // Remove Pin + await pageObjects.assetDetails.clickRemoveMetadataPin(); + expect(await pageObjects.assetDetails.metadataRemovePinExists()).to.be(false); + }); - expect(await searchInput.getAttribute('value')).to.be(''); + it('preserves search term between page reloads', async () => { + const searchInput = await pageObjects.assetDetails.getMetadataSearchField(); - await searchInput.type('test'); - await refreshPageWithDelay(); + expect(await searchInput.getAttribute('value')).to.be(''); - await retry.try(async () => { - expect(await searchInput.getAttribute('value')).to.be('test'); - }); - await searchInput.clearValue(); + await searchInput.type('test'); + await refreshPageWithDelay(); + + await retry.tryForTime(5000, async () => { + expect(await searchInput.getAttribute('value')).to.be('test'); }); + await searchInput.clearValue(); }); + }); - describe('Metrics Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickMetricsTab(); - }); + describe('Metrics Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickMetricsTab(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) + ); + }); - [ - { metric: 'cpu', chartsCount: 4 }, - { metric: 'memory', chartsCount: 2 }, - { metric: 'disk', chartsCount: 3 }, - { metric: 'network', chartsCount: 1 }, - { metric: 'log', chartsCount: 1 }, - ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s)`, async () => { - const charts = await pageObjects.assetDetails.getMetricsTabHostCharts(metric); - expect(charts.length).to.equal(chartsCount); - }); + [ + { metric: 'cpu', chartsCount: 4 }, + { metric: 'memory', chartsCount: 2 }, + { metric: 'disk', chartsCount: 3 }, + { metric: 'network', chartsCount: 1 }, + { metric: 'log', chartsCount: 1 }, + ].forEach(({ metric, chartsCount }) => { + it(`should render ${chartsCount} ${metric} chart(s)`, async () => { + const charts = await pageObjects.assetDetails.getMetricsTabHostCharts(metric); + expect(charts.length).to.equal(chartsCount); + }); - it(`should render a quick access for ${metric} in the side panel`, async () => { - await pageObjects.assetDetails.quickAccessItemExists(metric); - }); + it(`should render a quick access for ${metric} in the side panel`, async () => { + await pageObjects.assetDetails.quickAccessItemExists(metric); }); }); + }); - describe('Processes Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickProcessesTab(); - await pageObjects.header.waitUntilLoadingHasFinished(); + describe('Processes Tab', () => { + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_hosts_processes'); + await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + await navigateToNodeDetails('Jennys-MBP.fritz.box', 'host', { + name: 'Jennys-MBP.fritz.box', }); + await pageObjects.assetDetails.clickProcessesTab(); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT), + END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT) + ); + }); + after(async () => { + await esArchiver.unload( + 'x-pack/test/functional/es_archives/infra/metrics_hosts_processes' + ); + await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); + await navigateToNodeDetails('host-1', 'host', { name: 'host-1' }); + }); - it('should render processes tab and with Total Value summary', async () => { - const processesTotalValue = - await pageObjects.assetDetails.getProcessesTabContentTotalValue(); - const processValue = await processesTotalValue.getVisibleText(); - expect(processValue).to.eql('313'); - }); + it('should render processes tab and with Total Value summary', async () => { + const processesTotalValue = + await pageObjects.assetDetails.getProcessesTabContentTotalValue(); + const processValue = await processesTotalValue.getVisibleText(); + expect(processValue).to.eql('313'); + }); - it('should expand processes table row', async () => { - await pageObjects.assetDetails.processesTableExists(); - await pageObjects.assetDetails.getProcessesTableBody(); - await pageObjects.assetDetails.clickProcessesTableExpandButton(); - }); + it('should expand processes table row', async () => { + await pageObjects.assetDetails.processesTableExists(); + await pageObjects.assetDetails.getProcessesTableBody(); + await pageObjects.assetDetails.clickProcessesTableExpandButton(); + }); - it('preserves search term between page reloads', async () => { - const searchInput = await pageObjects.assetDetails.getProcessesSearchField(); + it('preserves search term between page reloads', async () => { + const searchInput = await pageObjects.assetDetails.getProcessesSearchField(); - expect(await searchInput.getAttribute('value')).to.be(''); + expect(await searchInput.getAttribute('value')).to.be(''); - await searchInput.type('test'); - await refreshPageWithDelay(); + await searchInput.type('test'); + await refreshPageWithDelay(); - await retry.try(async () => { - expect(await searchInput.getAttribute('value')).to.be('test'); - }); - await searchInput.clearValue(); + await retry.tryForTime(5000, async () => { + expect(await searchInput.getAttribute('value')).to.be('test'); }); + await searchInput.clearValue(); + }); - it('shows an error message when typing invalid term into the search input', async () => { - const searchInput = await pageObjects.assetDetails.getProcessesSearchField(); + it('shows an error message when typing invalid term into the search input', async () => { + const searchInput = await pageObjects.assetDetails.getProcessesSearchField(); - await pageObjects.assetDetails.processesSearchInputErrorMissing(); - await searchInput.type(','); - await pageObjects.assetDetails.processesSearchInputErrorExists(); - }); + await pageObjects.assetDetails.processesSearchInputErrorMissing(); + await searchInput.type(','); + await pageObjects.assetDetails.processesSearchInputErrorExists(); }); + }); - describe('Logs Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickLogsTab(); - }); + describe('Logs Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickLogsTab(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) + ); + }); - it('should render logs tab', async () => { - await pageObjects.assetDetails.logsExists(); - }); + it('should render logs tab', async () => { + await pageObjects.assetDetails.logsExists(); + }); - it('preserves search term between page reloads', async () => { - const searchInput = await pageObjects.assetDetails.getLogsSearchField(); + it('preserves search term between page reloads', async () => { + const searchInput = await pageObjects.assetDetails.getLogsSearchField(); - expect(await searchInput.getAttribute('value')).to.be(''); + expect(await searchInput.getAttribute('value')).to.be(''); - await searchInput.type('test'); - await refreshPageWithDelay(); + await searchInput.type('test'); + await refreshPageWithDelay(); - await retry.try(async () => { - expect(await searchInput.getAttribute('value')).to.be('test'); - }); - await searchInput.clearValue(); + await retry.tryForTime(5000, async () => { + expect(await searchInput.getAttribute('value')).to.be('test'); }); + await searchInput.clearValue(); }); + }); - describe('Osquery Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickOsqueryTab(); - }); + describe('Osquery Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickOsqueryTab(); + }); - it('should show a date picker', async () => { - expect(await pageObjects.timePicker.timePickerExists()).to.be(false); - }); + it('should show a date picker', async () => { + expect(await pageObjects.timePicker.timePickerExists()).to.be(false); }); + }); - describe('Profiling tab', () => { - it('shows the Profiling tab if Profiling integration UI setting is enabled', async () => { - await setInfrastructureProfilingIntegrationUiSetting(true); - await pageObjects.assetDetails.profilingTabExists(); - }); + describe('Profiling tab', () => { + it('shows the Profiling tab if Profiling integration UI setting is enabled', async () => { + await setInfrastructureProfilingIntegrationUiSetting(true); + await pageObjects.assetDetails.profilingTabExists(); + }); - it('hides the Profiling tab if Profiling integration UI setting is disabled', async () => { - await setInfrastructureProfilingIntegrationUiSetting(false); - await pageObjects.assetDetails.profilingTabMissing(); - }); + it('hides the Profiling tab if Profiling integration UI setting is disabled', async () => { + await setInfrastructureProfilingIntegrationUiSetting(false); + await pageObjects.assetDetails.profilingTabMissing(); }); + }); - describe('Host with alerts and no processes', () => { - before(async () => { - await navigateToNodeDetails('demo-stack-mysql-01', 'host', { - name: 'demo-stack-mysql-01', + describe('Callouts', () => { + describe('Legacy alert metric callout', () => { + [{ metric: 'cpu' }, { metric: 'rx' }, { metric: 'tx' }].forEach(({ metric }) => { + it(`Should show for: ${metric}`, async () => { + await navigateToNodeDetails('host-1', 'host', { + name: 'host-1', + alertMetric: metric, + }); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await retry.tryForTime(5000, async () => { + expect(await pageObjects.assetDetails.legacyMetricAlertCalloutExists()).to.be(true); + }); }); - await pageObjects.timePicker.setAbsoluteRange( - START_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT), - END_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT) - ); }); - it('should render alerts count for a host inside a flyout', async () => { - await pageObjects.assetDetails.clickOverviewTab(); + [{ metric: 'cpuV2' }, { metric: 'rxV2' }, { metric: 'txV2' }].forEach(({ metric }) => { + it(`Should not show for: ${metric}`, async () => { + await navigateToNodeDetails('host-1', 'host', { + name: 'host-1', + alertMetric: metric, + }); - await retry.tryForTime(30 * 1000, async () => { - await observability.components.alertSummaryWidget.getFullSizeComponentSelectorOrFail(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await retry.tryForTime(5000, async () => { + expect(await pageObjects.assetDetails.legacyMetricAlertCalloutExists()).to.be( + false + ); + }); }); + }); + }); + }); + }); - const activeAlertsCount = - await observability.components.alertSummaryWidget.getActiveAlertCount(); - const totalAlertsCount = - await observability.components.alertSummaryWidget.getTotalAlertCount(); + describe('#Asset type: host with kubernetes section', () => { + before(async () => { + synthEsClient = await getInfraSynthtraceEsClient(esClient); + await synthEsClient.clean(); + await synthEsClient.index( + generateHostsWithK8sNodeData({ + from: DATE_WITH_HOSTS_DATA_FROM, + to: DATE_WITH_HOSTS_DATA_TO, + }) + ); + await navigateToNodeDetails('demo-stack-kubernetes-01', 'host', { + name: 'demo-stack-kubernetes-01', + }); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_HOST_DATE.format(DATE_PICKER_FORMAT), + END_HOST_DATE.format(DATE_PICKER_FORMAT) + ); + }); - expect(activeAlertsCount.trim()).to.equal('2'); - expect(totalAlertsCount.trim()).to.equal('3'); - }); + after(async () => { + await synthEsClient.clean(); + }); - it('should render "N/A" when processes summary is not available in flyout', async () => { - await pageObjects.assetDetails.clickProcessesTab(); - const processesTotalValue = - await pageObjects.assetDetails.getProcessesTabContentTotalValue(); - const processValue = await processesTotalValue.getVisibleText(); - expect(processValue).to.eql('N/A'); - }); + describe('Overview Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickOverviewTab(); }); - describe('#With Kubernetes section', () => { - before(async () => { - await navigateToNodeDetails('demo-stack-kubernetes-01', 'host', { - name: 'demo-stack-kubernetes-01', + [ + { metric: 'cpuUsage', value: '50.0%' }, + { metric: 'normalizedLoad1m', value: '18.8%' }, + { metric: 'memoryUsage', value: '35.0%' }, + { metric: 'diskUsage', value: '1,223.0%' }, + ].forEach(({ metric, value }) => { + it(`${metric} tile should show ${value}`, async () => { + await retry.tryForTime(3 * 1000, async () => { + const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(metric); + expect(tileValue).to.eql(value); }); - await pageObjects.header.waitUntilLoadingHasFinished(); }); + }); - describe('Overview Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickOverviewTab(); + [ + { metric: 'cpu', chartsCount: 2 }, + { metric: 'memory', chartsCount: 1 }, + { metric: 'disk', chartsCount: 2 }, + { metric: 'network', chartsCount: 1 }, + { metric: 'kubernetes', chartsCount: 2 }, + ].forEach(({ metric, chartsCount }) => { + it(`should render ${chartsCount} ${metric} chart`, async () => { + await retry.tryForTime(5000, async () => { + const charts = await (metric === 'kubernetes' + ? pageObjects.assetDetails.getOverviewTabKubernetesMetricCharts() + : pageObjects.assetDetails.getOverviewTabHostMetricCharts(metric)); - await pageObjects.timePicker.setAbsoluteRange( - START_HOST_KUBERNETES_SECTION_DATE.format(DATE_PICKER_FORMAT), - END_HOST_KUBERNETES_SECTION_DATE.format(DATE_PICKER_FORMAT) - ); + expect(charts.length).to.equal(chartsCount); }); + }); + }); + }); - [ - { metric: 'cpuUsage', value: '100.0%' }, - { metric: 'normalizedLoad1m', value: '1,300.3%' }, - { metric: 'memoryUsage', value: '42.2%' }, - { metric: 'diskUsage', value: '36.0%' }, - ].forEach(({ metric, value }) => { - it(`${metric} tile should show ${value}`, async () => { - await retry.tryForTime(3 * 1000, async () => { - const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue( - metric - ); - expect(tileValue).to.eql(value); - }); - }); - }); + describe('Metrics Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickMetricsTab(); + }); - [ - { metric: 'cpu', chartsCount: 2 }, - { metric: 'memory', chartsCount: 1 }, - { metric: 'disk', chartsCount: 2 }, - { metric: 'network', chartsCount: 1 }, - { metric: 'kubernetes', chartsCount: 2 }, - ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart`, async () => { - await retry.try(async () => { - const charts = await (metric === 'kubernetes' - ? pageObjects.assetDetails.getOverviewTabKubernetesMetricCharts() - : pageObjects.assetDetails.getOverviewTabHostMetricCharts(metric)); - - expect(charts.length).to.equal(chartsCount); - }); - }); - }); - }); + [ + { metric: 'cpu', chartsCount: 4 }, + { metric: 'memory', chartsCount: 2 }, + { metric: 'disk', chartsCount: 3 }, + { metric: 'network', chartsCount: 1 }, + { metric: 'log', chartsCount: 1 }, + { metric: 'kubernetes', chartsCount: 4 }, + ].forEach(({ metric, chartsCount }) => { + it(`should render ${chartsCount} ${metric} chart(s)`, async () => { + await retry.tryForTime(5000, async () => { + const charts = await (metric === 'kubernetes' + ? pageObjects.assetDetails.getMetricsTabKubernetesCharts() + : pageObjects.assetDetails.getMetricsTabHostCharts(metric)); - describe('Metrics Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickMetricsTab(); + expect(charts.length).to.equal(chartsCount); }); + }); - [ - { metric: 'cpu', chartsCount: 4 }, - { metric: 'memory', chartsCount: 2 }, - { metric: 'disk', chartsCount: 3 }, - { metric: 'network', chartsCount: 1 }, - { metric: 'log', chartsCount: 1 }, - { metric: 'kubernetes', chartsCount: 4 }, - ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s)`, async () => { - await retry.try(async () => { - const charts = await (metric === 'kubernetes' - ? pageObjects.assetDetails.getMetricsTabKubernetesCharts() - : pageObjects.assetDetails.getMetricsTabHostCharts(metric)); - - expect(charts.length).to.equal(chartsCount); - }); - }); - - it(`should render a quick access for ${metric} in the side panel`, async () => { - await retry.try(async () => { - await pageObjects.assetDetails.quickAccessItemExists(metric); - }); - }); + it(`should render a quick access for ${metric} in the side panel`, async () => { + await retry.tryForTime(5000, async () => { + await pageObjects.assetDetails.quickAccessItemExists(metric); }); }); }); + }); + }); - describe('Callouts', () => { - describe('Legacy alert metric callout', () => { - [{ metric: 'cpu' }, { metric: 'rx' }, { metric: 'tx' }].forEach(({ metric }) => { - it(`Should show for: ${metric}`, async () => { - await navigateToNodeDetails('Jennys-MBP.fritz.box', 'host', { - name: 'Jennys-MBP.fritz.box', - alertMetric: metric, - }); - await pageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async () => { - expect(await pageObjects.assetDetails.legacyMetricAlertCalloutExists()).to.be( - true - ); - }); - }); - }); + describe('#Asset Type: container', () => { + before(async () => { + synthEsClient = await getInfraSynthtraceEsClient(esClient); + await synthEsClient.clean(); + await synthEsClient.index( + generateDockerContainersData({ + from: DATE_WITH_DOCKER_DATA_FROM, + to: DATE_WITH_DOCKER_DATA_TO, + count: 1, + }) + ); + await navigateToNodeDetails('container-id-0', 'container', { name: 'container-id-0' }); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_CONTAINER_DATE.format(DATE_PICKER_FORMAT), + END_CONTAINER_DATE.format(DATE_PICKER_FORMAT) + ); + }); - [{ metric: 'cpuV2' }, { metric: 'rxV2' }, { metric: 'txV2' }].forEach(({ metric }) => { - it(`Should not show for: ${metric}`, async () => { - await navigateToNodeDetails('Jennys-MBP.fritz.box', 'host', { - name: 'Jennys-MBP.fritz.box', - alertMetric: metric, - }); + after(async () => { + await synthEsClient.clean(); + }); - await pageObjects.header.waitUntilLoadingHasFinished(); + describe('when container asset view is disabled', () => { + before(async () => { + await setInfrastructureContainerAssetViewUiSetting(false); + await navigateToNodeDetails('container-id-0', 'container', { name: 'container-id-0' }); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_CONTAINER_DATE.format(DATE_PICKER_FORMAT), + END_CONTAINER_DATE.format(DATE_PICKER_FORMAT) + ); + }); - await retry.try(async () => { - expect(await pageObjects.assetDetails.legacyMetricAlertCalloutExists()).to.be( - false - ); - }); - }); - }); - }); + it('should show old view of container details', async () => { + await testSubjects.find('metricsEmptyViewState'); }); }); - describe('#Asset Type: container', () => { - let synthEsClient: InfraSynthtraceEsClient; + describe('when container asset view is enabled', () => { before(async () => { - const version = await infraSynthtraceKibanaClient.fetchLatestSystemPackageVersion(); - await infraSynthtraceKibanaClient.installSystemPackage(version); - synthEsClient = await getInfraSynthtraceEsClient(esClient); - await synthEsClient.index( - generateDockerContainersData({ - from: DATE_WITH_DOCKER_DATA_FROM, - to: DATE_WITH_DOCKER_DATA_TO, - count: 1, - }) + await setInfrastructureContainerAssetViewUiSetting(true); + await navigateToNodeDetails('container-id-0', 'container', { name: 'container-id-0' }); + await pageObjects.header.waitUntilLoadingHasFinished(); + await pageObjects.timePicker.setAbsoluteRange( + START_CONTAINER_DATE.format(DATE_PICKER_FORMAT), + END_CONTAINER_DATE.format(DATE_PICKER_FORMAT) ); }); - - after(async () => { - await synthEsClient.clean(); + it('should show asset container details page', async () => { + await pageObjects.assetDetails.getOverviewTab(); }); - describe('when container asset view is disabled', () => { - it('should show old view of container details', async () => { - await setInfrastructureContainerAssetViewUiSetting(false); - await navigateToNodeDetails('container-id-0', 'container', { - name: 'container-id-0', + [ + { metric: 'cpuUsage', value: '25.0%' }, + { metric: 'memoryUsage', value: '20.0%' }, + ].forEach(({ metric, value }) => { + it(`${metric} tile should show ${value}`, async () => { + await retry.tryForTime(3 * 1000, async () => { + const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(metric); + expect(tileValue).to.eql(value); }); - await pageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.find('metricsEmptyViewState'); }); }); - describe('when container asset view is enabled', () => { - before(async () => { - await setInfrastructureContainerAssetViewUiSetting(true); - await navigateToNodeDetails('container-id-0', 'container', { - name: 'container-id-0', - }); - await pageObjects.header.waitUntilLoadingHasFinished(); - await pageObjects.timePicker.setAbsoluteRange( - START_CONTAINER_DATE.format(DATE_PICKER_FORMAT), - END_CONTAINER_DATE.format(DATE_PICKER_FORMAT) - ); - }); - it('should show asset container details page', async () => { - await pageObjects.assetDetails.getOverviewTab(); + [ + { metric: 'cpu', chartsCount: 1 }, + { metric: 'memory', chartsCount: 1 }, + { metric: 'disk', chartsCount: 1 }, + { metric: 'network', chartsCount: 1 }, + ].forEach(({ metric, chartsCount }) => { + it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { + const charts = await pageObjects.assetDetails.getOverviewTabDockerMetricCharts(metric); + expect(charts.length).to.equal(chartsCount); }); + }); - [ - { metric: 'cpu', chartsCount: 1 }, - { metric: 'memory', chartsCount: 1 }, - { metric: 'disk', chartsCount: 1 }, - { metric: 'network', chartsCount: 1 }, - ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s) in the Metrics section`, async () => { - const charts = await pageObjects.assetDetails.getOverviewTabDockerMetricCharts( - metric - ); - expect(charts.length).to.equal(chartsCount); - }); - }); + it('should show / hide alerts section with no alerts and show / hide closed section content', async () => { + await pageObjects.assetDetails.alertsSectionCollapsibleExist(); + // Collapsed by default + await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsExist(); + // Expand + await pageObjects.assetDetails.alertsSectionCollapsibleClick(); + await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsMissing(); + // Check if buttons exist + await pageObjects.assetDetails.overviewLinkToAlertsExist(); + await pageObjects.assetDetails.overviewOpenAlertsFlyoutExist(); + }); - it('should show / hide alerts section with no alerts and show / hide closed section content', async () => { - await pageObjects.assetDetails.alertsSectionCollapsibleExist(); - // Collapsed by default - await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsExist(); - // Expand - await pageObjects.assetDetails.alertsSectionCollapsibleClick(); - await pageObjects.assetDetails.alertsSectionClosedContentNoAlertsMissing(); - // Check if buttons exist - await pageObjects.assetDetails.overviewLinkToAlertsExist(); - await pageObjects.assetDetails.overviewOpenAlertsFlyoutExist(); + describe('Metadata Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickMetadataTab(); }); - describe('Metadata Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickMetadataTab(); - }); - - it('should show metadata table', async () => { - await pageObjects.assetDetails.metadataTableExists(); - }); + it('should show metadata table', async () => { + await pageObjects.assetDetails.metadataTableExists(); + }); + }); + describe('Logs Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickLogsTab(); }); - describe('Logs Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickLogsTab(); - }); - it('should render logs tab', async () => { - await pageObjects.assetDetails.logsExists(); - }); + it('should render logs tab', async () => { + await pageObjects.assetDetails.logsExists(); + }); - it('preserves search term between page reloads', async () => { - const searchInput = await pageObjects.assetDetails.getLogsSearchField(); + it('preserves search term between page reloads', async () => { + const searchInput = await pageObjects.assetDetails.getLogsSearchField(); - expect(await searchInput.getAttribute('value')).to.be(''); + expect(await searchInput.getAttribute('value')).to.be(''); - await searchInput.type('test'); - await refreshPageWithDelay(); + await searchInput.type('test'); + await refreshPageWithDelay(); - await retry.try(async () => { - expect(await searchInput.getAttribute('value')).to.be('test'); - }); - await searchInput.clearValue(); + await retry.tryForTime(5000, async () => { + expect(await searchInput.getAttribute('value')).to.be('test'); }); + await searchInput.clearValue(); }); + }); - describe('Metrics Tab', () => { - before(async () => { - await pageObjects.assetDetails.clickMetricsTab(); - }); + describe('Metrics Tab', () => { + before(async () => { + await pageObjects.assetDetails.clickMetricsTab(); + }); - [ - { metric: 'cpu', chartsCount: 1 }, - { metric: 'memory', chartsCount: 1 }, - { metric: 'disk', chartsCount: 1 }, - { metric: 'network', chartsCount: 1 }, - ].forEach(({ metric, chartsCount }) => { - it(`should render ${chartsCount} ${metric} chart(s)`, async () => { - const charts = await pageObjects.assetDetails.getMetricsTabDockerCharts(metric); - expect(charts.length).to.equal(chartsCount); - }); + [ + { metric: 'cpu', chartsCount: 1 }, + { metric: 'memory', chartsCount: 1 }, + { metric: 'disk', chartsCount: 1 }, + { metric: 'network', chartsCount: 1 }, + ].forEach(({ metric, chartsCount }) => { + it(`should render ${chartsCount} ${metric} chart(s)`, async () => { + const charts = await pageObjects.assetDetails.getMetricsTabDockerCharts(metric); + expect(charts.length).to.equal(chartsCount); + }); - it(`should render a quick access for ${metric} in the side panel`, async () => { - await pageObjects.assetDetails.quickAccessItemExists(metric); - }); + it(`should render a quick access for ${metric} in the side panel`, async () => { + await pageObjects.assetDetails.quickAccessItemExists(metric); }); }); }); diff --git a/x-pack/test/functional/page_objects/asset_details.ts b/x-pack/test/functional/page_objects/asset_details.ts index 4e3da871a91b6..95a7819fb11a6 100644 --- a/x-pack/test/functional/page_objects/asset_details.ts +++ b/x-pack/test/functional/page_objects/asset_details.ts @@ -202,8 +202,8 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) { async getMetadataAppliedFilter() { const filter = await testSubjects.find( `filter-badge-${stringHash( - 'host.architecture: arm64' - )} filter filter-enabled filter-key-host.architecture filter-value-arm64 filter-unpinned filter-id-0` + 'host.name: host-1' + )} filter filter-enabled filter-key-host.name filter-value-host-1 filter-unpinned filter-id-0` ); return filter.getVisibleText(); }, @@ -263,6 +263,10 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) { return processesListElements[index].findByCssSelector('dt'); }, + async processesContentExist() { + return testSubjects.existOrFail('infraAssetDetailsProcessesTabContent'); + }, + async getProcessesTabContentTotalValue() { const processesListElements = await testSubjects.findAll( 'infraAssetDetailsProcessesSummaryTableItem' diff --git a/x-pack/test/functional/page_objects/dataset_quality.ts b/x-pack/test/functional/page_objects/dataset_quality.ts index b2d07161ddbaa..8fdc021af79fc 100644 --- a/x-pack/test/functional/page_objects/dataset_quality.ts +++ b/x-pack/test/functional/page_objects/dataset_quality.ts @@ -7,12 +7,11 @@ import querystring from 'querystring'; import rison from '@kbn/rison'; -import expect from '@kbn/expect'; -import { TimeUnitId } from '@elastic/eui'; import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { DATA_QUALITY_URL_STATE_KEY, datasetQualityUrlSchemaV1, + datasetQualityDetailsUrlSchemaV1, } from '@kbn/data-quality-plugin/common'; import { DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, @@ -26,15 +25,18 @@ const defaultPageState: datasetQualityUrlSchemaV1.UrlSchema = { page: 0, }, filters: {}, - flyout: { - degradedFields: { - table: { - page: 0, - rowsPerPage: 10, - sort: { - field: DEFAULT_DEGRADED_FIELD_SORT_FIELD, - direction: DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, - }, +}; + +const defaultDetailsPageState: datasetQualityDetailsUrlSchemaV1.UrlSchema = { + v: 1, + dataStream: 'logs-synth.1-default', + degradedFields: { + table: { + page: 0, + rowsPerPage: 10, + sort: { + field: DEFAULT_DEGRADED_FIELD_SORT_FIELD, + direction: DEFAULT_DEGRADED_FIELD_SORT_DIRECTION, }, }, }, @@ -49,7 +51,10 @@ type SummaryPanelKpi = Record< string >; -type FlyoutKpi = Record<'docsCountTotal' | 'size' | 'services' | 'hosts' | 'degradedDocs', string>; +type SummaryPanelKPI = Record< + 'docsCountTotal' | 'size' | 'services' | 'hosts' | 'degradedDocs', + string +>; const texts = { noActivityText: 'No activity in the selected timeframe', @@ -58,7 +63,7 @@ const texts = { datasetHealthGood: 'Good', activeDatasets: 'Active Data Sets', estimatedData: 'Estimated Data', - docsCountTotal: 'Docs count (total)', + docsCountTotal: 'Total count', size: 'Size', services: 'Services', hosts: 'Hosts', @@ -86,20 +91,16 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv datasetQualityTable: 'datasetQualityTable', datasetQualityFiltersContainer: 'datasetQualityFiltersContainer', datasetQualityExpandButton: 'datasetQualityExpandButton', - datasetQualityFlyout: 'datasetQualityFlyout', - datasetQualityFlyoutBody: 'datasetQualityFlyoutBody', - datasetQualityFlyoutTitle: 'datasetQualityFlyoutTitle', - datasetQualityFlyoutDegradedFieldTable: 'datasetQualityFlyoutDegradedFieldTable', - datasetQualityFlyoutDegradedTableNoData: 'datasetQualityFlyoutDegradedTableNoData', + datasetDetailsContainer: 'datasetDetailsContainer', + datasetQualityDetailsTitle: 'datasetQualityDetailsTitle', + datasetQualityDetailsDegradedFieldTable: 'datasetQualityDetailsDegradedFieldTable', + datasetQualityDetailsDegradedTableNoData: 'datasetQualityDetailsDegradedTableNoData', datasetQualitySparkPlot: 'datasetQualitySparkPlot', - datasetQualityHeaderButton: 'datasetQualityHeaderButton', - datasetQualityFlyoutFieldValue: 'datasetQualityFlyoutFieldValue', - datasetQualityFlyoutFieldsListIntegrationDetails: - 'datasetQualityFlyoutFieldsList-integration_details', - datasetQualityFlyoutIntegrationLoading: 'datasetQualityFlyoutIntegrationLoading', - datasetQualityFlyoutIntegrationActionsButton: 'datasetQualityFlyoutIntegrationActionsButton', - datasetQualityFlyoutIntegrationAction: (action: string) => - `datasetQualityFlyoutIntegrationAction${action}`, + datasetQualityDetailsHeaderButton: 'datasetQualityDetailsHeaderButton', + datasetQualityDetailsIntegrationLoading: 'datasetQualityDetailsIntegrationLoading', + datasetQualityDetailsIntegrationActionsButton: 'datasetQualityDetailsIntegrationActionsButton', + datasetQualityDetailsIntegrationAction: (action: string) => + `datasetQualityDetailsIntegrationAction${action}`, datasetQualityFilterBarFieldSearch: 'datasetQualityFilterBarFieldSearch', datasetQualityIntegrationsSelectable: 'datasetQualityIntegrationsSelectable', datasetQualityIntegrationsSelectableButton: 'datasetQualityIntegrationsSelectableButton', @@ -107,9 +108,13 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv datasetQualityNamespacesSelectableButton: 'datasetQualityNamespacesSelectableButton', datasetQualityQualitiesSelectable: 'datasetQualityQualitiesSelectable', datasetQualityQualitiesSelectableButton: 'datasetQualityQualitiesSelectableButton', + datasetQualityDetailsEmptyPrompt: 'datasetQualityDetailsEmptyPrompt', + datasetQualityDetailsEmptyPromptBody: 'datasetQualityDetailsEmptyPromptBody', datasetQualityDatasetHealthKpi: 'datasetQualityDatasetHealthKpi', - datasetQualityFlyoutKpiValue: 'datasetQualityFlyoutKpiValue', - datasetQualityFlyoutKpiLink: 'datasetQualityFlyoutKpiLink', + datasetQualityDetailsSummaryKpiValue: 'datasetQualityDetailsSummaryKpiValue', + datasetQualityDetailsIntegrationRowIntegration: 'datasetQualityDetailsFieldsList-integration', + datasetQualityDetailsIntegrationRowVersion: 'datasetQualityDetailsFieldsList-version', + datasetQualityDetailsLinkToDiscover: 'datasetQualityDetailsLinkToDiscover', datasetQualityInsufficientPrivileges: 'datasetQualityInsufficientPrivileges', datasetQualityNoDataEmptyState: 'datasetQualityNoDataEmptyState', datasetQualityNoPrivilegesEmptyState: 'datasetQualityNoPrivilegesEmptyState', @@ -117,7 +122,6 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv superDatePickerToggleQuickMenuButton: 'superDatePickerToggleQuickMenuButton', superDatePickerApplyTimeButton: 'superDatePickerApplyTimeButton', superDatePickerQuickMenu: 'superDatePickerQuickMenu', - euiFlyoutCloseButton: 'euiFlyoutCloseButton', unifiedHistogramBreakdownSelectorButton: 'unifiedHistogramBreakdownSelectorButton', unifiedHistogramBreakdownSelectorSelectorSearch: 'unifiedHistogramBreakdownSelectorSelectorSearch', @@ -156,19 +160,30 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv ); }, - async waitUntilTableLoaded() { - await find.waitForDeletedByCssSelector('.euiBasicTable-loading', 20 * 1000); - }, + async navigateToDetails(pageState: datasetQualityDetailsUrlSchemaV1.UrlSchema) { + const queryStringParams = querystring.stringify({ + [DATA_QUALITY_URL_STATE_KEY]: rison.encode( + datasetQualityDetailsUrlSchemaV1.urlSchemaRT.encode({ + ...defaultDetailsPageState, + ...pageState, + }) + ), + }); - async waitUntilTableInFlyoutLoaded() { - await find.waitForDeletedByCssSelector('.euiFlyoutBody .euiBasicTable-loading', 20 * 1000); + return PageObjects.common.navigateToUrlWithBrowserHistory( + 'management', + '/data/data_quality/details', + queryStringParams, + { + // the check sometimes is too slow for the page so it misses the point + // in time before the app rewrites the URL + ensureCurrentUrl: false, + } + ); }, - async waitUntilIntegrationsInFlyoutLoaded() { - await find.waitForDeletedByCssSelector( - '.euiSkeletonTitle .datasetQualityFlyoutIntegrationLoading', - 10 * 1000 - ); + async waitUntilTableLoaded() { + await find.waitForDeletedByCssSelector('.euiBasicTable-loading', 20 * 1000); }, async waitUntilSummaryPanelLoaded(isStateful: boolean = true) { @@ -213,14 +228,14 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv return testSubjects.find(testSubjectSelectors.datasetQualityTable); }, - getDatasetQualityFlyoutDegradedFieldTable(): Promise { - return testSubjects.find(testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable); + getDatasetQualityDetailsDegradedFieldTable(): Promise { + return testSubjects.find(testSubjectSelectors.datasetQualityDetailsDegradedFieldTable); }, - async getDatasetQualityFlyoutDegradedFieldTableRows(): Promise { - await this.waitUntilTableInFlyoutLoaded(); + async getDatasetQualityDetailsDegradedFieldTableRows(): Promise { + await this.waitUntilTableLoaded(); const table = await testSubjects.find( - testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable + testSubjectSelectors.datasetQualityDetailsDegradedFieldTable ); const tBody = await table.findByTagName('tbody'); return tBody.findAllByTagName('tr'); @@ -265,8 +280,8 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv }, async parseDegradedFieldTable() { - await this.waitUntilTableInFlyoutLoaded(); - const table = await this.getDatasetQualityFlyoutDegradedFieldTable(); + await this.waitUntilTableLoaded(); + const table = await this.getDatasetQualityDetailsDegradedFieldTable(); return this.parseTable(table, ['Field', 'Docs count', 'Last Occurrence']); }, @@ -302,46 +317,11 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv return find.clickByCssSelector(selectors.showFullDatasetNamesSwitch); }, - async openDatasetFlyout(datasetName: string) { - await this.waitUntilTableLoaded(); - const cols = await this.parseDatasetTable(); - const datasetNameCol = cols['Data Set Name']; - const datasetNameColCellTexts = await datasetNameCol.getCellTexts(); - const testDatasetRowIndex = datasetNameColCellTexts.findIndex( - (dName) => dName === datasetName + async refreshDetailsPageData() { + const datasetDetailsContainer: WebElementWrapper = await testSubjects.find( + testSubjectSelectors.datasetDetailsContainer ); - - expect(testDatasetRowIndex).to.be.greaterThan(-1); - - const expandColumn = cols['0']; - const expandButtons = await expandColumn.getCellChildren( - `[data-test-subj=${testSubjectSelectors.datasetQualityExpandButton}]` - ); - - expect(expandButtons.length).to.be.greaterThan(0); - - const datasetExpandButton = expandButtons[testDatasetRowIndex]; - - // Check if 'title' attribute is "Expand" or "Collapse" - const isCollapsed = (await datasetExpandButton.getAttribute('title')) === 'Expand'; - - // Open if collapsed - if (isCollapsed) { - await datasetExpandButton.click(); - } - - await this.waitUntilIntegrationsInFlyoutLoaded(); - }, - - async closeFlyout() { - return testSubjects.click(testSubjectSelectors.euiFlyoutCloseButton); - }, - - async refreshFlyout() { - const flyoutContainer: WebElementWrapper = await testSubjects.find( - testSubjectSelectors.datasetQualityFlyoutBody - ); - const refreshButton = await flyoutContainer.findByTestSubject( + const refreshButton = await datasetDetailsContainer.findByTestSubject( testSubjectSelectors.superDatePickerApplyTimeButton ); return refreshButton.click(); @@ -357,27 +337,27 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv return false; }, - getFlyoutLogsExplorerButton() { - return testSubjects.find(testSubjectSelectors.datasetQualityHeaderButton); + getDatasetQualityDetailsHeaderButton() { + return testSubjects.find(testSubjectSelectors.datasetQualityDetailsHeaderButton); }, openIntegrationActionsMenu() { - return testSubjects.click(testSubjectSelectors.datasetQualityFlyoutIntegrationActionsButton); + return testSubjects.click(testSubjectSelectors.datasetQualityDetailsIntegrationActionsButton); }, getIntegrationActionButtonByAction(action: string) { - return testSubjects.find(testSubjectSelectors.datasetQualityFlyoutIntegrationAction(action)); + return testSubjects.find(testSubjectSelectors.datasetQualityDetailsIntegrationAction(action)); }, getIntegrationDashboardButtons() { return testSubjects.findAll( - testSubjectSelectors.datasetQualityFlyoutIntegrationAction('Dashboard') + testSubjectSelectors.datasetQualityDetailsIntegrationAction('Dashboard') ); }, // `excludeKeys` needed to circumvent `_stats` not available in Serverless https://github.com/elastic/kibana/issues/178954 // TODO: Remove `excludeKeys` when `_stats` is available in Serverless - async parseFlyoutKpis(excludeKeys: string[] = []): Promise { + async parseOverviewSummaryPanelKpis(excludeKeys: string[] = []): Promise { const kpiTitleAndKeys = [ { title: texts.docsCountTotal, key: 'docsCountTotal' }, { title: texts.size, key: 'size' }, @@ -390,7 +370,7 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv kpiTitleAndKeys.map(async ({ title, key }) => ({ key, value: await testSubjects.getVisibleText( - `${testSubjectSelectors.datasetQualityFlyoutKpiValue}-${title}` + `${testSubjectSelectors.datasetQualityDetailsSummaryKpiValue}-${title}` ), })) ); @@ -400,52 +380,10 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv ...acc, [key]: value, }), - {} as FlyoutKpi + {} as SummaryPanelKPI ); }, - async setDatePickerLastXUnits( - container: WebElementWrapper, - timeValue: number, - unit: TimeUnitId - ) { - // Only click the menu button found under the provided container - const datePickerToggleQuickMenuButton = await container.findByTestSubject( - testSubjectSelectors.superDatePickerToggleQuickMenuButton - ); - await datePickerToggleQuickMenuButton.click(); - - const datePickerQuickMenu = await testSubjects.find( - testSubjectSelectors.superDatePickerQuickMenu - ); - - const timeTenseSelect = await datePickerQuickMenu.findByCssSelector( - `select[aria-label="Time tense"]` - ); - const timeValueInput = await datePickerQuickMenu.findByCssSelector( - `input[aria-label="Time value"]` - ); - const timeUnitSelect = await datePickerQuickMenu.findByCssSelector( - `select[aria-label="Time unit"]` - ); - - await timeTenseSelect.focus(); - await timeTenseSelect.type('Last'); - - await timeValueInput.focus(); - await timeValueInput.clearValue(); - await timeValueInput.type(timeValue.toString()); - - await timeUnitSelect.focus(); - await timeUnitSelect.type(unit); - - await ( - await datePickerQuickMenu.findByCssSelector(selectors.superDatePickerApplyButton) - ).click(); - - return testSubjects.missingOrFail(testSubjectSelectors.superDatePickerQuickMenu); - }, - /** * Selects a breakdown field from the unified histogram breakdown selector * @param fieldText The text of the field to select. Use 'No breakdown' to clear the selection diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index ec7908d916e9b..0a85972f48d9f 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -37,7 +37,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide }, async getWaffleMap() { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const element = await testSubjects.find('waffleMap'); if (!element) { throw new Error(); @@ -98,13 +98,13 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide }, async clickOnGoToNodeDetails() { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await testSubjects.click('viewAssetDetailsContextMenuItem'); }); }, async clickOnNodeDetailsFlyoutOpenAsPage() { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { await testSubjects.click('infraAssetDetailsOpenAsPageButton'); }); }, @@ -139,7 +139,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide // wait for input value to echo the input before submitting // this ensures the React state has caught up with the events - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const value = await input.getAttribute('value'); expect(value).to.eql(query); }); diff --git a/x-pack/test/functional/page_objects/infra_hosts_view.ts b/x-pack/test/functional/page_objects/infra_hosts_view.ts index d92cf51892a5f..86c7f330e081c 100644 --- a/x-pack/test/functional/page_objects/infra_hosts_view.ts +++ b/x-pack/test/functional/page_objects/infra_hosts_view.ts @@ -57,7 +57,7 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { return table.findAllByTestSubject('hostsView-tableRow'); }, - async getHostsRowData(row: WebElementWrapper) { + async getHostsRowDataWithAlerts(row: WebElementWrapper) { // Find all the row cells const cells = await row.findAllByCssSelector('[data-test-subj*="hostsView-tableRow-"]'); @@ -87,6 +87,26 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { }; }, + async getHostsRowData(row: WebElementWrapper) { + // Find all the row cells + const cells = await row.findAllByCssSelector('[data-test-subj*="hostsView-tableRow-"]'); + + // Retrieve content for each cell + const [title, cpuUsage, normalizedLoad, memoryUsage, memoryFree, diskSpaceUsage, rx, tx] = + await Promise.all(cells.map((cell) => this.getHostsCellContent(cell))); + + return { + title, + cpuUsage, + normalizedLoad, + memoryUsage, + memoryFree, + diskSpaceUsage, + rx, + tx, + }; + }, + async getHostsCellContent(cell: WebElementWrapper) { const cellContent = await cell.findByClassName('euiTableCellContent'); return cellContent.getVisibleText(); @@ -247,17 +267,17 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) { }, // Sorting - getMemoryHeader() { - return testSubjects.find('tableHeaderCell_memory_5'); + getCpuHeader() { + return testSubjects.find('tableHeaderCell_cpuV2_2'); }, getTitleHeader() { - return testSubjects.find('tableHeaderCell_title_2'); + return testSubjects.find('tableHeaderCell_title_1'); }, - async sortByMemoryUsage() { - const memory = await this.getMemoryHeader(); - const button = await testSubjects.findDescendant('tableHeaderSortButton', memory); + async sortByCpuUsage() { + const cpu = await this.getCpuHeader(); + const button = await testSubjects.findDescendant('tableHeaderSortButton', cpu); await button.click(); }, diff --git a/x-pack/test/functional/page_objects/infra_saved_views.ts b/x-pack/test/functional/page_objects/infra_saved_views.ts index 3a843974043c2..2f19c959f355f 100644 --- a/x-pack/test/functional/page_objects/infra_saved_views.ts +++ b/x-pack/test/functional/page_objects/infra_saved_views.ts @@ -71,7 +71,7 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) { }, async ensureViewIsLoaded(name: string) { - await retry.try(async () => { + await retry.tryForTime(5000, async () => { const subject = await testSubjects.find('savedViews-openPopover'); expect(await subject.getVisibleText()).to.be(name); }); diff --git a/x-pack/test/functional_solution_sidenav/config.ts b/x-pack/test/functional_solution_sidenav/config.ts new file mode 100644 index 0000000000000..f997aaea7c5e2 --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/config.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 { FtrConfigProviderContext } from '@kbn/test'; + +/** + * NOTE: The solution view is currently only available in the cloud environment. + * This test suite fakes a cloud environement by setting the cloud.id and cloud.base_url + */ + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../functional/config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + kbnTestServer: { + ...functionalConfig.get('kbnTestServer'), + serverArgs: [ + ...functionalConfig.get('kbnTestServer.serverArgs'), + // Note: the base64 string in the cloud.id config contains the ES endpoint required in the functional tests + '--xpack.cloud.id=ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=', + '--xpack.cloud.base_url=https://cloud.elastic.co', + ], + }, + }; +} diff --git a/x-pack/test/functional_solution_sidenav/ftr_provider_context.ts b/x-pack/test/functional_solution_sidenav/ftr_provider_context.ts new file mode 100644 index 0000000000000..d6c0afa5ceffd --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/ftr_provider_context.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { GenericFtrProviderContext } from '@kbn/test'; +import { pageObjects } from '../functional/page_objects'; +import { services } from './services'; + +export type FtrProviderContext = GenericFtrProviderContext; +export { pageObjects }; diff --git a/x-pack/test/functional_solution_sidenav/index.ts b/x-pack/test/functional_solution_sidenav/index.ts new file mode 100644 index 0000000000000..9056551e235d5 --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +/* eslint-disable import/no-default-export */ + +import { FtrProviderContext } from './ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext): void => { + describe('Solution navigation smoke tests', function () { + loadTestFile(require.resolve('./tests/observability_sidenav')); + loadTestFile(require.resolve('./tests/search_sidenav')); + loadTestFile(require.resolve('./tests/security_sidenav')); + }); +}; diff --git a/x-pack/test/functional_solution_sidenav/services.ts b/x-pack/test/functional_solution_sidenav/services.ts new file mode 100644 index 0000000000000..9508ce5eba16d --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/services.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { services as functionalServices } from '../functional/services'; + +export const services = functionalServices; diff --git a/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts new file mode 100644 index 0000000000000..9e4db0c33da52 --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts @@ -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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']); + const spaces = getService('spaces'); + const browser = getService('browser'); + + describe('observability solution', () => { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + + // Create a space with the observability solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'oblt' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + }); + + describe('sidenav & breadcrumbs', () => { + it('renders the correct nav and navigate to links', async () => { + const expectNoPageReload = await solutionNavigation.createNoPageReloadCheck(); + + await solutionNavigation.expectExists(); + await solutionNavigation.breadcrumbs.expectExists(); + + // check side nav links + await solutionNavigation.sidenav.expectSectionExists('observability_project_nav'); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'observabilityOnboarding', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'observabilityOnboarding', + }); + + // check the AI & ML subsection + await solutionNavigation.sidenav.openSection('observability_project_nav.aiMl'); // open AI & ML subsection + await solutionNavigation.sidenav.clickLink({ deepLinkId: 'ml:anomalyDetection' }); + await solutionNavigation.sidenav.expectLinkActive({ deepLinkId: 'ml:anomalyDetection' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AI & ML' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'ml:anomalyDetection', + }); + + // navigate to a different section + await solutionNavigation.sidenav.openSection('project_settings_project_nav'); + await solutionNavigation.sidenav.clickLink({ deepLinkId: 'management' }); + await solutionNavigation.sidenav.expectLinkActive({ deepLinkId: 'management' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'management' }); + + // navigate back to the home page using header logo + await solutionNavigation.clickLogo(); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'observabilityOnboarding', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'observabilityOnboarding', + }); + + await expectNoPageReload(); + }); + }); + }); +} diff --git a/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts new file mode 100644 index 0000000000000..bf1dfe993e1ae --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']); + const spaces = getService('spaces'); + const browser = getService('browser'); + + describe('search solution', () => { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + + // Create a space with the search solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'es' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + }); + + describe('sidenav & breadcrumbs', () => { + it('renders the correct nav and navigate to links', async () => { + const expectNoPageReload = await solutionNavigation.createNoPageReloadCheck(); + + await solutionNavigation.expectExists(); + await solutionNavigation.breadcrumbs.expectExists(); + + // check side nav links + await solutionNavigation.sidenav.expectSectionExists('search_project_nav'); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearch', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearch', + }); + + // check the Content > Indices section + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Indices' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearchContent:searchIndices', + }); + + // navigate to a different section + await solutionNavigation.sidenav.openSection('project_settings_project_nav'); + await solutionNavigation.sidenav.clickLink({ deepLinkId: 'management' }); + await solutionNavigation.sidenav.expectLinkActive({ deepLinkId: 'management' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'management' }); + + // navigate back to the home page using header logo + await solutionNavigation.clickLogo(); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'enterpriseSearch', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'enterpriseSearch', + }); + + await expectNoPageReload(); + }); + }); + }); +} diff --git a/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts new file mode 100644 index 0000000000000..153c809ff715b --- /dev/null +++ b/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']); + const spaces = getService('spaces'); + const browser = getService('browser'); + const testSubjects = getService('testSubjects'); + + describe('security solution', () => { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + + // Create a space with the security solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'security' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + }); + + describe('sidenav & breadcrumbs', () => { + it('renders the correct nav and navigate to links', async () => { + const expectNoPageReload = await solutionNavigation.createNoPageReloadCheck(); + + await solutionNavigation.expectExists(); + await solutionNavigation.breadcrumbs.expectExists(); + + // check side nav links + await solutionNavigation.sidenav.expectSectionExists('security_solution_nav'); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'securitySolutionUI:get_started', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'securitySolutionUI:get_started', + }); + + // check the Investigations subsection + await solutionNavigation.sidenav.openPanel('investigations'); // open Investigations panel + await testSubjects.click(`~solutionSideNavPanelLink-timelines`); + await solutionNavigation.sidenav.expectLinkActive({ navId: 'investigations' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Timelines' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'securitySolutionUI:timelines', + }); + + // navigate back to the home page using header logo + await solutionNavigation.clickLogo(); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'securitySolutionUI:get_started', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'securitySolutionUI:get_started', + }); + + await expectNoPageReload(); + }); + }); + }); +} diff --git a/x-pack/test/observability_ai_assistant_functional/tests/feature_controls/settings_security.spec.ts b/x-pack/test/observability_ai_assistant_functional/tests/feature_controls/settings_security.spec.ts index cea40d3ad10ce..7c2262008d8a2 100644 --- a/x-pack/test/observability_ai_assistant_functional/tests/feature_controls/settings_security.spec.ts +++ b/x-pack/test/observability_ai_assistant_functional/tests/feature_controls/settings_security.spec.ts @@ -20,7 +20,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const toasts = getService('toasts'); describe('ai assistant management privileges', () => { - describe('all privileges', () => { + // FLAKY: https://github.com/elastic/kibana/issues/190637 + describe.skip('all privileges', () => { before(async () => { await createAndLoginUserWithCustomRole(getPageObjects, getService, { // we need all these privileges to view and modify Obs AI Assistant settings view diff --git a/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts b/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts index 6a30645c60b06..415e3e165cff3 100644 --- a/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts +++ b/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts @@ -13,7 +13,7 @@ // I fixed this as a drive-by, but opened an issue to do something later, // if needed: https://github.com/elastic/kibana/issues/144557 -import { type Subject, ReplaySubject } from 'rxjs'; +import { type Subject, ReplaySubject, of } from 'rxjs'; import type { ElasticsearchClient, Logger, LogMeta } from '@kbn/core/server'; import sinon from 'sinon'; import expect from '@kbn/expect'; @@ -70,6 +70,7 @@ export default function createLifecycleExecutorApiTest({ getService }: FtrProvid describe('createLifecycleExecutor', () => { let ruleDataClient: IRuleDataClient; let pluginStop$: Subject; + const elasticsearchAndSOAvailability$ = of(true); before(async () => { // First we need to setup the data service. This happens within the @@ -89,6 +90,7 @@ export default function createLifecycleExecutorApiTest({ getService }: FtrProvid }, pluginStop$, dataStreamAdapter, + elasticsearchAndSOAvailability$, }); // This initializes the service. This happens immediately after the creation diff --git a/x-pack/test/tsconfig.json b/x-pack/test/tsconfig.json index 160aa0a3d81f6..1173ef6b4d492 100644 --- a/x-pack/test/tsconfig.json +++ b/x-pack/test/tsconfig.json @@ -179,6 +179,7 @@ "@kbn/cases-api-integration-test-plugin", "@kbn/security-solution-plugin/public/management/cypress", "@kbn/management-settings-ids", - "@kbn/mock-idp-utils" + "@kbn/mock-idp-utils", + "@kbn/cloud-security-posture-common" ] } diff --git a/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts index 87064adf39d9f..3126619ae60ee 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/config.feature_flags.ts @@ -18,7 +18,10 @@ export default createTestConfig({ }, suiteTags: { exclude: ['skipSvlSearch'] }, // add feature flags - kbnServerArgs: ['--xpack.security.roleManagementEnabled=true'], + kbnServerArgs: [ + '--xpack.security.roleManagementEnabled=true', + `--xpack.searchIndices.enabled=true`, // global empty state FF + ], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], diff --git a/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts index a757df76f10f3..a4a99f1e42641 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/index.feature_flags.ts @@ -9,6 +9,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Serverless search API - feature flags', function () { + loadTestFile(require.resolve('./search_indices')); loadTestFile(require.resolve('./platform_security')); loadTestFile(require.resolve('../common/platform_security/roles_routes_feature_flag.ts')); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/search/search_indices/index.ts b/x-pack/test_serverless/api_integration/test_suites/search/search_indices/index.ts new file mode 100644 index 0000000000000..b48985faaecd5 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/search_indices/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('search indices APIs', function () { + loadTestFile(require.resolve('./status')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/search/search_indices/status.ts b/x-pack/test_serverless/api_integration/test_suites/search/search_indices/status.ts new file mode 100644 index 0000000000000..b9e9fedbb0396 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/search/search_indices/status.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 svlCommonApi = getService('svlCommonApi'); + const svlUserManager = getService('svlUserManager'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + let credentials: { Cookie: string }; + + describe('search_indices Status APIs', function () { + describe('indices status', function () { + before(async () => { + // get auth header for Viewer role + credentials = await svlUserManager.getM2MApiCredentialsWithRoleScope('developer'); + }); + it('returns list of index names', async () => { + const { body } = await supertestWithoutAuth + .get('/internal/search_indices/status') + .set(svlCommonApi.getInternalRequestHeader()) + .set(credentials) + .expect(200); + + expect(body.indexNames).toBeDefined(); + expect(Array.isArray(body.indexNames)).toBe(true); + }); + }); + describe('user privileges', function () { + // GET /internal/search_indices/start_privileges + describe('developer', function () { + before(async () => { + // get auth header for Viewer role + credentials = await svlUserManager.getM2MApiCredentialsWithRoleScope('developer'); + }); + + it('returns expected privileges', async () => { + const { body } = await supertestWithoutAuth + .get('/internal/search_indices/start_privileges') + .set(svlCommonApi.getInternalRequestHeader()) + .set(credentials) + .expect(200); + + expect(body).toEqual({ + privileges: { + canCreateApiKeys: true, + canCreateIndex: true, + }, + }); + }); + }); + describe('viewer', function () { + before(async () => { + // get auth header for Viewer role + credentials = await svlUserManager.getM2MApiCredentialsWithRoleScope('viewer'); + }); + + it('returns expected privileges', async () => { + const { body } = await supertestWithoutAuth + .get('/internal/search_indices/start_privileges') + .set(svlCommonApi.getInternalRequestHeader()) + .set(credentials) + .expect(200); + + expect(body).toEqual({ + privileges: { + canCreateApiKeys: false, + canCreateIndex: false, + }, + }); + }); + }); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts index 1b44c42ecb22e..ff0208459856f 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexed.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { FINDINGS_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_DEFAULT_NS, diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts index 4e81938a597e9..80a07bd6ee79c 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_indexing.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { FINDINGS_INDEX_DEFAULT_NS, LATEST_FINDINGS_INDEX_DEFAULT_NS, diff --git a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts index eb7b6f4424c0d..d3510ea98b7bb 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/status/status_not_deployed_not_installed.ts @@ -5,7 +5,7 @@ * 2.0. */ import expect from '@kbn/expect'; -import type { CspSetupStatus } from '@kbn/cloud-security-posture-plugin/common/types_old'; +import type { CspSetupStatus } from '@kbn/cloud-security-posture-common'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; import { createPackagePolicy } from '@kbn/test-suites-xpack/api_integration/apis/cloud_security_posture/helper'; import { FtrProviderContext } from '../../../../ftr_provider_context'; diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts index 4b8cad3b2c2ef..72c98a41b85f7 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @@ -5,334 +5,17 @@ * 2.0. */ -import expect from '@kbn/expect'; -import type { AppDeepLinkId } from '@kbn/core-chrome-browser'; +import { SolutionNavigationProvider } from '@kbn/test-suites-src/functional/page_objects'; -import type { NavigationID as MlNavId } from '@kbn/default-nav-ml'; -import type { NavigationID as AlNavId } from '@kbn/default-nav-analytics'; -import type { NavigationID as MgmtNavId } from '@kbn/default-nav-management'; -import type { NavigationID as DevNavId } from '@kbn/default-nav-devtools'; - -// use this for nicer type suggestions, but allow any string anyway -type NavigationId = MlNavId | AlNavId | MgmtNavId | DevNavId | string; - -import type { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; import { NavigationalSearchPageObject } from '@kbn/test-suites-xpack/functional/page_objects/navigational_search'; import type { FtrProviderContext } from '../ftr_provider_context'; -const getSectionIdTestSubj = (sectionId: NavigationId) => `~nav-item-${sectionId}`; - export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { - const testSubjects = ctx.getService('testSubjects'); - const browser = ctx.getService('browser'); - const retry = ctx.getService('retry'); - const log = ctx.getService('log'); - - async function getByVisibleText( - selector: string | (() => Promise), - text: string - ) { - const subjects = - typeof selector === 'string' ? await testSubjects.findAll(selector) : await selector(); - let found: WebElementWrapper | null = null; - for (const subject of subjects) { - const visibleText = await subject.getVisibleText(); - if (visibleText === text) { - found = subject; - break; - } - } - return found; - } + const solutionNavigation = SolutionNavigationProvider(ctx); return { - // check that chrome ui is in the serverless (project) mode - async expectExists() { - await testSubjects.existOrFail('kibanaProjectHeader'); - }, - async clickLogo() { - await testSubjects.click('nav-header-logo'); - }, - // side nav related actions - sidenav: { - async expectLinkExists( - by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } - ) { - if ('deepLinkId' in by) { - await testSubjects.existOrFail(`~nav-item-deepLinkId-${by.deepLinkId}`); - } else if ('navId' in by) { - await testSubjects.existOrFail(`~nav-item-id-${by.navId}`); - } else { - expect(await getByVisibleText('~nav-item', by.text)).not.be(null); - } - }, - async expectLinkMissing( - by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } - ) { - if ('deepLinkId' in by) { - await testSubjects.missingOrFail(`~nav-item-deepLinkId-${by.deepLinkId}`); - } else if ('navId' in by) { - await testSubjects.missingOrFail(`~nav-item-id-${by.navId}`); - } else { - expect(await getByVisibleText('~nav-item', by.text)).be(null); - } - }, - async expectLinkActive( - by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } - ) { - await this.expectLinkExists(by); - if ('deepLinkId' in by) { - await testSubjects.existOrFail( - `~nav-item-deepLinkId-${by.deepLinkId} & ~nav-item-isActive` - ); - } else if ('navId' in by) { - await testSubjects.existOrFail(`~nav-item-id-${by.navId} & ~nav-item-isActive`); - } else { - await retry.try(async () => { - const link = await getByVisibleText('~nav-item', by.text); - expect(await link!.elementHasClass(`nav-item-isActive`)).to.be(true); - }); - } - }, - async clickLink(by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string }) { - await this.expectLinkExists(by); - if ('deepLinkId' in by) { - await testSubjects.click(`~nav-item-deepLinkId-${by.deepLinkId}`); - } else if ('navId' in by) { - await testSubjects.click(`~nav-item-id-${by.navId}`); - } else { - await retry.try(async () => { - const link = await getByVisibleText('~nav-item', by.text); - await link!.click(); - }); - } - }, - async findLink(by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string }) { - await this.expectLinkExists(by); - if ('deepLinkId' in by) { - return testSubjects.find(`~nav-item-deepLinkId-${by.deepLinkId}`); - } else if ('navId' in by) { - return testSubjects.find(`~nav-item-id-${by.navId}`); - } else { - return retry.try(async () => { - const link = await getByVisibleText('~nav-item', by.text); - return link; - }); - } - }, - async expectSectionExists(sectionId: NavigationId) { - log.debug('ServerlessCommonNavigation.sidenav.expectSectionExists', sectionId); - await testSubjects.existOrFail(getSectionIdTestSubj(sectionId)); - }, - async isSectionOpen(sectionId: NavigationId) { - await this.expectSectionExists(sectionId); - const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); - const isExpanded = await collapseBtn.getAttribute('aria-expanded'); - return isExpanded === 'true'; - }, - async expectSectionOpen(sectionId: NavigationId) { - log.debug('ServerlessCommonNavigation.sidenav.expectSectionOpen', sectionId); - await this.expectSectionExists(sectionId); - await retry.waitFor(`section ${sectionId} to be open`, async () => { - const isOpen = await this.isSectionOpen(sectionId); - return isOpen; - }); - }, - async expectSectionClosed(sectionId: NavigationId) { - await this.expectSectionExists(sectionId); - await retry.waitFor(`section ${sectionId} to be closed`, async () => { - const isOpen = await this.isSectionOpen(sectionId); - return !isOpen; - }); - }, - async openSection(sectionId: NavigationId) { - log.debug('ServerlessCommonNavigation.sidenav.openSection', sectionId); - await this.expectSectionExists(sectionId); - const isOpen = await this.isSectionOpen(sectionId); - if (isOpen) return; - const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); - await collapseBtn.click(); - await this.expectSectionOpen(sectionId); - }, - async closeSection(sectionId: NavigationId) { - await this.expectSectionExists(sectionId); - const isOpen = await this.isSectionOpen(sectionId); - if (!isOpen) return; - const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); - await collapseBtn.click(); - await this.expectSectionClosed(sectionId); - }, - async isCollapsed() { - const collapseNavBtn = await testSubjects.find('euiCollapsibleNavButton'); - return (await collapseNavBtn.getAttribute('aria-expanded')) === 'false'; - }, - async isExpanded() { - return !(await this.isCollapsed()); - }, - /** - * Toggles collapsed state of sidenav - */ - async toggle(collapsed?: boolean) { - const currentlyCollapsed = await this.isCollapsed(); - const shouldBeCollapsed = collapsed ?? !currentlyCollapsed; - - if (currentlyCollapsed !== shouldBeCollapsed) { - log.debug( - 'ServerlessCommonNavigation.sidenav.toggle', - shouldBeCollapsed ? 'Collapsing' : 'Expanding' - ); - - const collapseNavBtn = await testSubjects.find('euiCollapsibleNavButton'); - await collapseNavBtn.click(); - } - }, - }, - breadcrumbs: { - async expectExists() { - await testSubjects.existOrFail('breadcrumbs'); - }, - async clickBreadcrumb(by: { deepLinkId: AppDeepLinkId } | { text: string }) { - if ('deepLinkId' in by) { - await testSubjects.click(`~breadcrumb-deepLinkId-${by.deepLinkId}`); - } else { - await (await getByVisibleText('~breadcrumb', by.text))?.click(); - } - }, - getBreadcrumb(by: { deepLinkId: AppDeepLinkId } | { text: string }) { - if ('deepLinkId' in by) { - return testSubjects.find(`~breadcrumb-deepLinkId-${by.deepLinkId}`); - } else { - return getByVisibleText('~breadcrumb', by.text); - } - }, - async expectBreadcrumbExists(by: { deepLinkId: AppDeepLinkId } | { text: string }) { - log.debug( - 'ServerlessCommonNavigation.breadcrumbs.expectBreadcrumbExists', - JSON.stringify(by) - ); - if ('deepLinkId' in by) { - await testSubjects.existOrFail(`~breadcrumb-deepLinkId-${by.deepLinkId}`); - } else { - await retry.try(async () => { - expect(await getByVisibleText('~breadcrumb', by.text)).not.be(null); - }); - } - }, - async expectBreadcrumbMissing(by: { deepLinkId: AppDeepLinkId } | { text: string }) { - if ('deepLinkId' in by) { - await testSubjects.missingOrFail(`~breadcrumb-deepLinkId-${by.deepLinkId}`); - } else { - await retry.try(async () => { - expect(await getByVisibleText('~breadcrumb', by.text)).be(null); - }); - } - }, - async expectBreadcrumbTexts(expectedBreadcrumbTexts: string[]) { - log.debug( - 'ServerlessCommonNavigation.breadcrumbs.expectBreadcrumbTexts', - JSON.stringify(expectedBreadcrumbTexts) - ); - await retry.try(async () => { - const breadcrumbsContainer = await testSubjects.find('breadcrumbs'); - const breadcrumbs = await breadcrumbsContainer.findAllByTestSubject('~breadcrumb'); - breadcrumbs.shift(); // remove home - expect(expectedBreadcrumbTexts.length).to.eql(breadcrumbs.length); - const texts = await Promise.all(breadcrumbs.map((b) => b.getVisibleText())); - expect(expectedBreadcrumbTexts).to.eql(texts); - }); - }, - }, + ...solutionNavigation, search: new SvlNavigationSearchPageObject(ctx), - recent: { - async expectExists() { - await testSubjects.existOrFail('nav-item-recentlyAccessed'); - }, - async expectHidden() { - await testSubjects.missingOrFail('nav-item-recentlyAccessed', { timeout: 1000 }); - }, - async expectLinkExists(text: string) { - await this.expectExists(); - let foundLink: WebElementWrapper | null = null; - await retry.try(async () => { - foundLink = await getByVisibleText( - async () => - (await testSubjects.find('nav-item-recentlyAccessed')).findAllByTagName('a'), - text - ); - expect(!!foundLink).to.be(true); - }); - - return foundLink!; - }, - async clickLink(text: string) { - const link = await this.expectLinkExists(text); - await link!.click(); - }, - }, - - // helper to assert that the page did not reload - async createNoPageReloadCheck() { - const trackReloadTs = Date.now(); - await browser.execute( - ({ ts }) => { - // @ts-ignore - window.__testTrackReload__ = ts; - }, - { - ts: trackReloadTs, - } - ); - - return async () => { - const noReload = await browser.execute( - ({ ts }) => { - // @ts-ignore - return window.__testTrackReload__ && window.__testTrackReload__ === ts; - }, - { - ts: trackReloadTs, - } - ); - expect(noReload).to.be(true); - }; - }, - - // embedded dev console - devConsole: { - async expectEmbeddedConsoleControlBarExists() { - await testSubjects.existOrFail('consoleEmbeddedSection'); - }, - async expectEmbeddedConsoleToBeOpen() { - await testSubjects.existOrFail('consoleEmbeddedBody'); - }, - async expectEmbeddedConsoleToBeClosed() { - await testSubjects.missingOrFail('consoleEmbeddedBody'); - }, - async clickEmbeddedConsoleControlBar() { - await testSubjects.click('consoleEmbeddedControlBar'); - }, - async expectEmbeddedConsoleNotebooksButtonExists() { - await testSubjects.existOrFail('consoleEmbeddedNotebooksButton'); - }, - async clickEmbeddedConsoleNotebooksButton() { - await testSubjects.click('consoleEmbeddedNotebooksButton'); - }, - async expectEmbeddedConsoleNotebooksToBeOpen() { - await testSubjects.existOrFail('consoleEmbeddedNotebooksContainer'); - }, - async expectEmbeddedConsoleNotebooksToBeClosed() { - await testSubjects.missingOrFail('consoleEmbeddedNotebooksContainer'); - }, - async expectEmbeddedConsoleNotebookListItemToBeAvailable(id: string) { - await testSubjects.existOrFail(`console-embedded-notebook-select-btn-${id}`); - }, - async clickEmbeddedConsoleNotebook(id: string) { - await testSubjects.click(`console-embedded-notebook-select-btn-${id}`); - }, - async expectEmbeddedConsoleNotebookToBeAvailable(id: string) { - await testSubjects.click(`console-embedded-notebook-select-btn-${id}`); - }, - }, }; } diff --git a/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts b/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts index d53759ddc4e29..dccd6723507d5 100644 --- a/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/common/context/_discover_navigation.ts @@ -35,7 +35,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const kibanaServer = getService('kibanaServer'); - describe('context link in discover', () => { + describe('context link in discover', function () { + // flaky on MKI, see https://github.com/elastic/kibana/issues/191237 + this.tags(['failsOnMKI']); + before(async () => { await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update({ diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts index 7203793330590..1755d386d4554 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts @@ -132,7 +132,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - describe('data view mode', () => { + // FLAKY: https://github.com/elastic/kibana/issues/191260 + describe.skip('data view mode', () => { it('should render default columns and row height', async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts index 97ace2684cb85..15da3d48d9037 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group2/open_in_lens/agg_based/goal.ts @@ -21,6 +21,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); describe('Goal', function describeIndexTests() { + // fails on MKI, see https://github.com/elastic/kibana/issues/191238 + this.tags(['failsOnMKI']); + const fixture = 'x-pack/test_serverless/functional/fixtures/kbn_archiver/lens/open_in_lens/agg_based/goal.json'; 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_details.ts similarity index 69% rename from x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts rename to x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts index fda145ebfea7f..bca31c506a770 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_details.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { defaultNamespace } from '@kbn/test-suites-xpack/functional/apps/dataset_quality/data'; import { FtrProviderContext } from '../../../ftr_provider_context'; import { datasetNames, @@ -38,7 +39,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const excludeKeysFromServerless = ['size']; // https://github.com/elastic/kibana/issues/178954 const apacheAccessDatasetName = 'apache.access'; - const apacheAccessDatasetHumanName = 'Apache access logs'; + const apacheAccessDataStreamName = `logs-${apacheAccessDatasetName}-${productionNamespace}`; const apacheIntegrationId = 'apache'; const apachePkg = { name: 'apache', @@ -46,13 +47,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }; const bitbucketDatasetName = 'atlassian_bitbucket.audit'; - const bitbucketDatasetHumanName = 'Bitbucket Audit Logs'; + const bitbucketAuditDataStreamName = `logs-${bitbucketDatasetName}-${defaultNamespace}`; const bitbucketPkg = { name: 'atlassian_bitbucket', version: '1.14.0', }; + const regularDatasetName = datasetNames[0]; + const regularDataStreamName = `logs-${datasetNames[0]}-${defaultNamespace}`; const degradedDatasetName = datasetNames[2]; + const degradedDataStreamName = `logs-${degradedDatasetName}-${defaultNamespace}`; describe('Flyout', function () { before(async () => { @@ -91,8 +95,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ]); await PageObjects.svlCommonPage.loginWithPrivilegedRole(); - - await PageObjects.datasetQuality.navigateTo(); }); after(async () => { @@ -101,21 +103,49 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await synthtrace.clean(); }); - describe('open flyout', () => { - it('should open the flyout for the right dataset', async () => { - const testDatasetName = datasetNames[1]; + describe('navigate to dataset details', () => { + it('should navigate to right dataset', async () => { + await PageObjects.datasetQuality.navigateToDetails({ dataStream: regularDataStreamName }); + + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle + ); + }); + + it('should navigate to details page from a main page', async () => { + await PageObjects.datasetQuality.navigateTo(); + + const synthDataset = await testSubjects.find( + 'datasetQualityTableDetailsLink-logs-synth.1-default', + 20 * 1000 + ); + + await synthDataset.click(); + + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle + ); + }); - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + it('should show an empty prompt with error message when the dataset is not found', async () => { + const nonExistentDataStreamName = 'logs-non.existent-production'; + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: nonExistentDataStreamName, + }); await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutTitle + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPrompt + ); + + const emptyPromptBody = await testSubjects.getVisibleText( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPromptBody ); - await PageObjects.datasetQuality.closeFlyout(); + expect(emptyPromptBody).to.contain(nonExistentDataStreamName); }); it('reflects the breakdown field state in url', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDataStreamName }); const breakdownField = 'service.name'; await PageObjects.datasetQuality.selectBreakdownField(breakdownField); @@ -134,46 +164,71 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const currentUrl = await browser.getCurrentUrl(); expect(currentUrl).to.not.contain('breakdownField'); }); - await PageObjects.datasetQuality.closeFlyout(); }); }); - describe('integrations', () => { - it('should hide the integration section for non integrations', async () => { - const testDatasetName = datasetNames[1]; + describe('overview summary panel', () => { + it('should show summary KPIs', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + const { docsCountTotal, degradedDocs, services, hosts } = + await PageObjects.datasetQuality.parseOverviewSummaryPanelKpis(excludeKeysFromServerless); + expect(parseInt(docsCountTotal, 10)).to.be(226); + expect(parseInt(degradedDocs, 10)).to.be(1); + expect(parseInt(services, 10)).to.be(3); + expect(parseInt(hosts, 10)).to.be(52); + }); + }); + describe('overview integrations', () => { + it('should hide the integration section for non integrations', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); + + // The Integration row should not be present await testSubjects.missingOrFail( PageObjects.datasetQuality.testSubjectSelectors - .datasetQualityFlyoutFieldsListIntegrationDetails + .datasetQualityDetailsIntegrationRowIntegration ); - await PageObjects.datasetQuality.closeFlyout(); + // The Version row should not be present + await testSubjects.missingOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion + ); }); it('should shows the integration section for integrations', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors - .datasetQualityFlyoutFieldsListIntegrationDetails + .datasetQualityDetailsIntegrationRowIntegration + ); + + await testSubjects.existOrFail( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion ); await retry.tryForTime(5000, async () => { const integrationNameExists = await PageObjects.datasetQuality.doesTextExist( PageObjects.datasetQuality.testSubjectSelectors - .datasetQualityFlyoutFieldsListIntegrationDetails, + .datasetQualityDetailsIntegrationRowIntegration, apacheIntegrationId ); expect(integrationNameExists).to.be(true); }); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should show the integration actions menu with correct actions', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); const actions = await Promise.all( @@ -183,23 +238,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); expect(actions.length).to.eql(3); - await PageObjects.datasetQuality.closeFlyout(); }); it('should hide integration dashboard for integrations without dashboards', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: bitbucketAuditDataStreamName, + }); + await PageObjects.datasetQuality.openIntegrationActionsMenu(); await testSubjects.missingOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction( integrationActions.viewDashboards ) ); - await PageObjects.datasetQuality.closeFlyout(); }); it('Should navigate to integration overview page on clicking integration overview action', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: bitbucketAuditDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( @@ -214,12 +272,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket'); }); - - await PageObjects.datasetQuality.navigateTo(); }); it('should navigate to index template page in clicking Integration template', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( @@ -235,11 +293,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { `/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}` ); }); - await PageObjects.datasetQuality.navigateTo(); }); it('should navigate to the selected dashboard on clicking integration dashboard action ', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); await PageObjects.datasetQuality.openIntegrationActionsMenu(); const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction( @@ -257,118 +316,87 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last'); expect(breadcrumbText).to.eql(dashboardText); - - await PageObjects.datasetQuality.navigateTo(); - }); - }); - - describe('summary panel', () => { - it('should show summary KPIs', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - - const { docsCountTotal, degradedDocs, services, hosts } = - await PageObjects.datasetQuality.parseFlyoutKpis(excludeKeysFromServerless); - expect(parseInt(docsCountTotal, 10)).to.be(226); - expect(parseInt(degradedDocs, 10)).to.be(1); - expect(parseInt(services, 10)).to.be(3); - expect(parseInt(hosts, 10)).to.be(52); - - await PageObjects.datasetQuality.closeFlyout(); }); }); describe('navigation', () => { - afterEach(async () => { - // Navigate back to dataset quality page after each test - await PageObjects.datasetQuality.navigateTo(); - }); - it('should go to log explorer page when the open in log explorer button is clicked', async () => { - const testDatasetName = datasetNames[2]; - await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); - const logExplorerButton = await PageObjects.datasetQuality.getFlyoutLogsExplorerButton(); + const logExplorerButton = + await PageObjects.datasetQuality.getDatasetQualityDetailsHeaderButton(); await logExplorerButton.click(); // Confirm dataset selector text in observability logs explorer const datasetSelectorText = await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); - expect(datasetSelectorText).to.eql(testDatasetName); + expect(datasetSelectorText).to.eql(regularDatasetName); }); - it('should go log explorer for degraded docs when the show all button is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); + it('should go log explorer for degraded docs when the button next to breakdown selector is clicked', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apacheAccessDataStreamName, + }); - const degradedDocsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.degradedDocs}`; - await testSubjects.click(degradedDocsShowAllSelector); + await testSubjects.click( + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsLinkToDiscover + ); // Confirm dataset selector text in observability logs explorer const datasetSelectorText = await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText(); expect(datasetSelectorText).to.contain(apacheAccessDatasetName); }); - - // Blocked by https://github.com/elastic/kibana/issues/181705 - // Its a test written ahead of its time. - it.skip('goes to infra hosts for hosts when show all is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName); - - const hostsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.hosts}`; - await testSubjects.click(hostsShowAllSelector); - - // Confirm url contains metrics/hosts - await retry.tryForTime(5000, async () => { - const currentUrl = await browser.getCurrentUrl(); - const parsedUrl = new URL(currentUrl); - expect(parsedUrl.pathname).to.contain('/app/metrics/hosts'); - }); - }); }); describe('degraded fields table', () => { it(' should show empty degraded fields table when no degraded fields are present', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(datasetNames[0]); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: regularDataStreamName, + }); await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedTableNoData ); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should show the degraded fields table with data when present', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); await testSubjects.existOrFail( - PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable + PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedFieldTable ); const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); + await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); expect(rows.length).to.eql(2); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should display Spark Plot for every row of degraded fields', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const rows = - await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows(); + await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); const sparkPlots = await testSubjects.findAll( PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot ); expect(rows.length).to.be(sparkPlots.length); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should sort the table when the count table header is clicked', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); @@ -379,12 +407,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const sortedCellTexts = await countColumn.getCellTexts(); expect(cellTexts.reverse()).to.eql(sortedCellTexts); - - await PageObjects.datasetQuality.closeFlyout(); }); it('should update the URL when the table is sorted', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); const countColumn = table['Docs count']; @@ -410,8 +438,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'sort:(direction:asc,field:count)' ); }); - - await PageObjects.datasetQuality.closeFlyout(); }); // This is the only test which ingest data during the test. @@ -419,7 +445,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // Even though this test ingest data, it can also be freely moved inside // this describe block, and it won't affect any of the existing tests it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => { - await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName); + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: degradedDataStreamName, + }); const table = await PageObjects.datasetQuality.parseDegradedFieldTable(); @@ -434,7 +462,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }), ]); - await PageObjects.datasetQuality.refreshFlyout(); + await PageObjects.datasetQuality.refreshDetailsPageData(); const updatedTable = await PageObjects.datasetQuality.parseDegradedFieldTable(); const updatedCountColumn = updatedTable['Docs count']; @@ -445,8 +473,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const singleValueNow = parseInt(updatedCellTexts[0], 10); expect(singleValueNow).to.be.greaterThan(singleValuePreviously); - - await PageObjects.datasetQuality.closeFlyout(); }); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts index 30547ceb941b3..683c879ae4e3d 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts @@ -13,7 +13,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./dataset_quality_summary')); loadTestFile(require.resolve('./dataset_quality_table')); loadTestFile(require.resolve('./dataset_quality_table_filters')); - loadTestFile(require.resolve('./dataset_quality_flyout')); loadTestFile(require.resolve('./dataset_quality_privileges')); + loadTestFile(require.resolve('./dataset_quality_details')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts index ee652f0f7eb2d..05eb6136bf008 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.feature_flags.ts @@ -25,6 +25,7 @@ export default createTestConfig({ `--xpack.cloud.organization_url='/account/members'`, `--xpack.security.roleManagementEnabled=true`, `--xpack.spaces.maxSpaces=100`, // enables spaces UI capabilities + `--xpack.searchIndices.enabled=true`, // global empty state FF ], // load tests in the index file testFiles: [require.resolve('./index.feature_flags.ts')], diff --git a/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts b/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts index bc9879a032357..5ada9a50d45c3 100644 --- a/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/connectors/connectors_overview.ts @@ -14,6 +14,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'svlCommonNavigation', 'common', 'svlSearchConnectorsPage', + 'embeddedConsole', ]); const testSubjects = getService('testSubjects'); const browser = getService('browser'); diff --git a/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts b/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts index 696e1fd693ae7..5cf4a4ceeb856 100644 --- a/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts +++ b/x-pack/test_serverless/functional/test_suites/search/console_notebooks.ts @@ -7,8 +7,8 @@ import { FtrProviderContext } from '../../ftr_provider_context'; -export default function ({ getPageObjects, getService }: FtrProviderContext) { - const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']); +export default function ({ getPageObjects }: FtrProviderContext) { + const pageObjects = getPageObjects(['svlCommonPage', 'embeddedConsole']); describe('Console Notebooks', function () { before(async () => { @@ -17,39 +17,39 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('has notebooks view available', async () => { // Expect Console Bar & Notebooks button to exist - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleControlBarExists(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksButtonExists(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleControlBarExists(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksButtonExists(); // Click the Notebooks button to open console to See Notebooks - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleNotebooksButton(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleNotebooksButton(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksToBeOpen(); // Click the Notebooks button again to switch to the dev console - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleNotebooksButton(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeOpen(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksToBeClosed(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleNotebooksButton(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeOpen(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksToBeClosed(); // Clicking control bar should close the console - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleControlBar(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksToBeClosed(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksToBeClosed(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); // Re-open console and then open Notebooks - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleControlBar(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeOpen(); - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleNotebooksButton(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleNotebooksButton(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksToBeOpen(); // Close the console - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleControlBar(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksToBeClosed(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksToBeClosed(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); }); it('can open notebooks', async () => { // Click the Notebooks button to open console to See Notebooks - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleNotebooksButton(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebooksToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleNotebooksButton(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebooksToBeOpen(); const defaultNotebooks = [ '00_quick_start', @@ -59,13 +59,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { '04_multilingual', ]; for (const notebookId of defaultNotebooks) { - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebookListItemToBeAvailable( - notebookId - ); - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleNotebook(notebookId); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleNotebookToBeAvailable( + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebookListItemToBeAvailable( notebookId ); + await pageObjects.embeddedConsole.clickEmbeddedConsoleNotebook(notebookId); + await pageObjects.embeddedConsole.expectEmbeddedConsoleNotebookToBeAvailable(notebookId); } }); }); diff --git a/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts new file mode 100644 index 0000000000000..5b5adf48319db --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/elasticsearch_start.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({}: FtrProviderContext) { + describe('Elasticsearch Start [Onboarding Empty State]', function () {}); +} diff --git a/x-pack/test_serverless/functional/test_suites/search/embedded_console.ts b/x-pack/test_serverless/functional/test_suites/search/embedded_console.ts index 9ae2c37b6075c..2a14fab24f81a 100644 --- a/x-pack/test_serverless/functional/test_suites/search/embedded_console.ts +++ b/x-pack/test_serverless/functional/test_suites/search/embedded_console.ts @@ -7,13 +7,13 @@ import { FtrProviderContext } from '../../ftr_provider_context'; -type PageObjects = Pick, 'svlCommonNavigation'>; +type PageObjects = Pick, 'embeddedConsole'>; export async function testHasEmbeddedConsole(pageObjects: PageObjects) { - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleControlBarExists(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeClosed(); - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleControlBar(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeOpen(); - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleControlBar(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleControlBarExists(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); } diff --git a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts index acf3e6f98b7db..44cd17a0c9fd3 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.feature_flags.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('serverless search UI - feature flags', function () { // add tests that require feature flags, defined in config.feature_flags.ts + loadTestFile(require.resolve('./elasticsearch_start.ts')); loadTestFile(require.resolve('../common/platform_security/navigation/management_nav_cards.ts')); loadTestFile(require.resolve('../common/platform_security/roles.ts')); loadTestFile(require.resolve('../common/spaces/spaces_selection_enabled.ts')); diff --git a/x-pack/test_serverless/functional/test_suites/search/index_management.ts b/x-pack/test_serverless/functional/test_suites/search/index_management.ts index dc8d147c9d348..7d8464bf5b128 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index_management.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index_management.ts @@ -12,7 +12,7 @@ import { testHasEmbeddedConsole } from './embedded_console'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects([ 'svlCommonPage', - 'svlCommonNavigation', + 'embeddedConsole', 'common', 'header', 'indexManagement', diff --git a/x-pack/test_serverless/functional/test_suites/search/landing_page.ts b/x-pack/test_serverless/functional/test_suites/search/landing_page.ts index 0bac8fc80f111..643d163bf7672 100644 --- a/x-pack/test_serverless/functional/test_suites/search/landing_page.ts +++ b/x-pack/test_serverless/functional/test_suites/search/landing_page.ts @@ -10,11 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { testHasEmbeddedConsole } from './embedded_console'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const pageObjects = getPageObjects([ - 'svlSearchLandingPage', - 'svlCommonPage', - 'svlCommonNavigation', - ]); + const pageObjects = getPageObjects(['svlSearchLandingPage', 'svlCommonPage', 'embeddedConsole']); const svlSearchNavigation = getService('svlSearchNavigation'); describe('landing page', function () { diff --git a/x-pack/test_serverless/functional/test_suites/search/pipelines.ts b/x-pack/test_serverless/functional/test_suites/search/pipelines.ts index 6f7c52af51f83..9cb53310e5405 100644 --- a/x-pack/test_serverless/functional/test_suites/search/pipelines.ts +++ b/x-pack/test_serverless/functional/test_suites/search/pipelines.ts @@ -14,6 +14,7 @@ export default function ({ getPageObjects }: FtrProviderContext) { 'common', 'svlIngestPipelines', 'svlManagementPage', + 'embeddedConsole', ]); describe('ingest pipelines', function () { before(async () => { diff --git a/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts b/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts index 868413cc3b7b5..036751ef970da 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_homepage.ts @@ -11,7 +11,12 @@ import { RoleCredentials } from '../../../shared/services'; import { testHasEmbeddedConsole } from './embedded_console'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'svlSearchHomePage']); + const pageObjects = getPageObjects([ + 'svlCommonPage', + 'svlCommonNavigation', + 'svlSearchHomePage', + 'embeddedConsole', + ]); const svlUserManager = getService('svlUserManager'); const uiSettings = getService('uiSettings'); let roleAuthc: RoleCredentials; @@ -56,11 +61,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('has console quickstart link on page', async () => { await pageObjects.svlSearchHomePage.expectConsoleLinkExists(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); await pageObjects.svlSearchHomePage.clickConsoleLink(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeOpen(); - await pageObjects.svlCommonNavigation.devConsole.clickEmbeddedConsoleControlBar(); - await pageObjects.svlCommonNavigation.devConsole.expectEmbeddedConsoleToBeClosed(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeOpen(); + await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); + await pageObjects.embeddedConsole.expectEmbeddedConsoleToBeClosed(); }); it('has endpoints link and flyout', async () => { diff --git a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts index 476b47b060b2c..9545707c51540 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts @@ -15,7 +15,12 @@ import { createLlmProxy, LlmProxy } from './utils/create_llm_proxy'; const esArchiveIndex = 'test/api_integration/fixtures/es_archiver/index_patterns/basic_index'; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'searchPlayground']); + const pageObjects = getPageObjects([ + 'svlCommonPage', + 'svlCommonNavigation', + 'searchPlayground', + 'embeddedConsole', + ]); const svlCommonApi = getService('svlCommonApi'); const svlUserManager = getService('svlUserManager'); const supertestWithoutAuth = getService('supertestWithoutAuth'); diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index b1f73748b5e0d..7a7747a964caa 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -39,10 +39,6 @@ "@kbn/apm-plugin", "@kbn/server-route-repository", "@kbn/core-chrome-browser", - "@kbn/default-nav-ml", - "@kbn/default-nav-analytics", - "@kbn/default-nav-management", - "@kbn/default-nav-devtools", "@kbn/security-plugin", "@kbn/security-solution-plugin", "@kbn/security-solution-plugin/public/management/cypress", @@ -101,5 +97,6 @@ "@kbn/ml-trained-models-utils", "@kbn/test-suites-src", "@kbn/console-plugin", + "@kbn/cloud-security-posture-common", ] } diff --git a/yarn.lock b/yarn.lock index c1855e9acef09..15ae0b8e5fcee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -163,7 +163,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.24.7", "@babel/core@^7.7.5": +"@babel/core@^7.1.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.24.7", "@babel/core@^7.7.5": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== @@ -435,7 +435,7 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.3", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.23.0", "@babel/parser@^7.24.7": +"@babel/parser@^7.1.0", "@babel/parser@^7.10.3", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.8", "@babel/parser@^7.23.0", "@babel/parser@^7.23.9", "@babel/parser@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== @@ -1449,36 +1449,6 @@ "@types/tough-cookie" "^4.0.5" tough-cookie "^4.1.4" -"@cbor-extract/cbor-extract-darwin-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.0.0.tgz#cf0667e4c22111c9d45e16c29964892b12460a76" - integrity sha512-jebtLrruvsBbGMsUn0QxZW/8Z7caS9OkszVKZ64WTWajUkyohmolUdKL2nbfaTyyi3ABJrxVNM4YO1pvMsNI1g== - -"@cbor-extract/cbor-extract-darwin-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.0.0.tgz#7bc01e7911b97eee4c78ae074bd3108f2ff208c3" - integrity sha512-LGYjdlyqANBqCDzBujCqXpPcK70rvaQgw98/aquzBuEmK0KXS7i579CoVG1yS/eb3bMqiVPevBri45jbR6Tlsg== - -"@cbor-extract/cbor-extract-linux-arm64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.0.0.tgz#e40608afed5f373091560fa9dcd19c7f52f510b0" - integrity sha512-c1rbQcSF01yVgbG60zEfHNsUkXiEEQRNdYqm5qpqEAkLx4gA6DDU91IQbalkqXfwDuQzcMovOc1TC3uJJIi2OQ== - -"@cbor-extract/cbor-extract-linux-arm@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.0.0.tgz#f52a7580fb23e305370e66ae9ff136de3729c4b8" - integrity sha512-cOGHEIif5rPbpix6qhpuatrZzm6HeC5rT0nXt8ynLTc7PzfXmovswD9x6d9h5NcHswkV5y3PbkNbpel/tLADYg== - -"@cbor-extract/cbor-extract-linux-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.0.0.tgz#8c936b8a93f915bf3c2459d5b4b78d244bda0f26" - integrity sha512-WYeE1b5WGf9pbbQH3qeNBXq710gGsuVFUiP148RY8In+2pCp/fxjBpe701ngam9/fF5D+gJs8B1i5wv/PN7JZA== - -"@cbor-extract/cbor-extract-win32-x64@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.0.0.tgz#4d4ad91527a8313c3db1e2167a8821dfae9d6211" - integrity sha512-XqVuJEnE0jpl/RkuSp04FF2UE73gY52Y4nZaIE6j9GAeSH2cHYU5CCd4TaVMDi2M18ZpZv7XhL/k+nneQzyJpQ== - "@cfaester/enzyme-adapter-react-18@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cfaester/enzyme-adapter-react-18/-/enzyme-adapter-react-18-0.8.0.tgz#313814eb79658a6e74209f9f1743bcefff14a46f" @@ -2991,114 +2961,114 @@ dependencies: "@istanbuljs/schema" "^0.1.2" -"@istanbuljs/schema@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" - integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.1.tgz#b48ba7b9c34b51483e6d590f46e5837f1ab5f639" - integrity sha512-Aj772AYgwTSr5w8qnyoJ0eDYvN6bMsH3ORH1ivMotrInHLKdUz6BDlaEXHdM6kODaBIkNIyQGzsMvRdOv7VG7Q== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.6.1" - jest-util "^29.6.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.1.tgz#fac0d9ddf320490c93356ba201451825231e95f6" - integrity sha512-CcowHypRSm5oYQ1obz1wfvkjZZ2qoQlrKKvlfPwh5jUXVU12TWr2qMeH8chLMuTFzHh5a1g2yaqlqDICbr+ukQ== - dependencies: - "@jest/console" "^29.6.1" - "@jest/reporters" "^29.6.1" - "@jest/test-result" "^29.6.1" - "@jest/transform" "^29.6.1" - "@jest/types" "^29.6.1" +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^29.5.0" - jest-config "^29.6.1" - jest-haste-map "^29.6.1" - jest-message-util "^29.6.1" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.1" - jest-resolve-dependencies "^29.6.1" - jest-runner "^29.6.1" - jest-runtime "^29.6.1" - jest-snapshot "^29.6.1" - jest-util "^29.6.1" - jest-validate "^29.6.1" - jest-watcher "^29.6.1" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" micromatch "^4.0.4" - pretty-format "^29.6.1" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.1.tgz#ee358fff2f68168394b4a50f18c68278a21fe82f" - integrity sha512-RMMXx4ws+Gbvw3DfLSuo2cfQlK7IwGbpuEWXCqyYDcqYTI+9Ju3a5hDnXaxjNsa6uKh9PQF2v+qg+RLe63tz5A== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: - "@jest/fake-timers" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.6.1" + jest-mock "^29.7.0" -"@jest/expect-utils@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.1.tgz#ab83b27a15cdd203fe5f68230ea22767d5c3acc5" - integrity sha512-o319vIf5pEMx0LmzSxxkYYxo4wrRLKHq9dP1yJU7FoPTB0LfAKSz8SWD6D/6U3v/O52t9cF5t+MeJiRsfk7zMw== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" -"@jest/expect@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.1.tgz#fef18265188f6a97601f1ea0a2912d81a85b4657" - integrity sha512-N5xlPrAYaRNyFgVf2s9Uyyvr795jnB6rObuPx4QFvNJz8aAjpZUDfO4bh5G/xuplMID8PrnuF1+SfSyDxhsgYg== +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: - expect "^29.6.1" - jest-snapshot "^29.6.1" + expect "^29.7.0" + jest-snapshot "^29.7.0" -"@jest/fake-timers@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.1.tgz#c773efddbc61e1d2efcccac008139f621de57c69" - integrity sha512-RdgHgbXyosCDMVYmj7lLpUwXA4c69vcNzhrt69dJJdf8azUrpRh3ckFCaTPNjsEeRi27Cig0oKDGxy5j7hOgHg== +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^29.6.1" - jest-mock "^29.6.1" - jest-util "^29.6.1" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.1.tgz#c8a8923e05efd757308082cc22893d82b8aa138f" - integrity sha512-2VjpaGy78JY9n9370H8zGRCFbYVWwjY6RdDMhoJHa1sYfwe6XM/azGN0SjY8kk7BOZApIejQ1BFPyH7FPG0w3A== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^29.6.1" - "@jest/expect" "^29.6.1" - "@jest/types" "^29.6.1" - jest-mock "^29.6.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.1.tgz#3325a89c9ead3cf97ad93df3a427549d16179863" - integrity sha512-9zuaI9QKr9JnoZtFQlw4GREQbxgmNYXU6QuWtmuODvk5nvPUeBYapVR/VYMyi2WSx3jXTLJTJji8rN6+Cm4+FA== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.6.1" - "@jest/test-result" "^29.6.1" - "@jest/transform" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" @@ -3107,52 +3077,52 @@ glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.6.1" - jest-util "^29.6.1" - jest-worker "^29.6.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^29.6.0", "@jest/schemas@^29.6.3": +"@jest/schemas@^29.6.3": version "29.6.3" resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.6.0": - version "29.6.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" - integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.1.tgz#850e565a3f58ee8ca6ec424db00cb0f2d83c36ba" - integrity sha512-Ynr13ZRcpX6INak0TPUukU8GWRfm/vAytE3JbJNGAvINySWYdfE7dGZMbk36oVuK4CigpbhMn8eg1dixZ7ZJOw== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.1.tgz#e3e582ee074dd24ea9687d7d1aaf05ee3a9b068e" - integrity sha512-oBkC36PCDf/wb6dWeQIhaviU0l5u6VCsXa119yqdUosYAt7/FbQU2M2UoziO3igj/HBDEgp57ONQ3fm0v9uyyg== +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: - "@jest/test-result" "^29.6.1" + "@jest/test-result" "^29.7.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.1" + jest-haste-map "^29.7.0" slash "^3.0.0" "@jest/transform@^26.6.2": @@ -3176,22 +3146,22 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/transform@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.1.tgz#acb5606019a197cb99beda3c05404b851f441c92" - integrity sha512-URnTneIU3ZjRSaf906cvf6Hpox3hIeJXRnz3VDSw5/X93gR8ycdfSIEy19FlVx8NFmpN7fe3Gb1xF+NjXaQLWg== +"@jest/transform@^29.6.1", "@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.1" - jest-regex-util "^29.4.3" - jest-util "^29.6.1" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" @@ -3208,12 +3178,12 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@jest/types@^29.6.1": - version "29.6.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" - integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: - "@jest/schemas" "^29.6.0" + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" @@ -3545,6 +3515,10 @@ version "0.0.0" uid "" +"@kbn/cbor@link:packages/kbn-cbor": + version "0.0.0" + uid "" + "@kbn/cell-actions@link:packages/kbn-cell-actions": version "0.0.0" uid "" @@ -3565,6 +3539,10 @@ version "0.0.0" uid "" +"@kbn/check-prod-native-modules-cli@link:packages/kbn-check-prod-native-modules-cli": + version "0.0.0" + uid "" + "@kbn/ci-stats-core@link:packages/kbn-ci-stats-core": version "0.0.0" uid "" @@ -4965,6 +4943,10 @@ version "0.0.0" uid "" +"@kbn/eui-provider-dev-warning@link:test/plugin_functional/plugins/eui_provider_dev_warning": + version "0.0.0" + uid "" + "@kbn/event-annotation-common@link:packages/kbn-event-annotation-common": version "0.0.0" uid "" @@ -5237,6 +5219,10 @@ version "0.0.0" uid "" +"@kbn/hardening-plugin@link:test/plugin_functional/plugins/hardening": + version "0.0.0" + uid "" + "@kbn/health-gateway-server@link:packages/kbn-health-gateway-server": version "0.0.0" uid "" @@ -6305,6 +6291,10 @@ version "0.0.0" uid "" +"@kbn/security-solution-common@link:x-pack/packages/security-solution/common": + version "0.0.0" + uid "" + "@kbn/security-solution-distribution-bar@link:x-pack/packages/security-solution/distribution_bar": version "0.0.0" uid "" @@ -8604,6 +8594,11 @@ "@smithy/util-buffer-from" "^3.0.0" tslib "^2.6.2" +"@sovpro/delimited-stream@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@sovpro/delimited-stream/-/delimited-stream-1.1.0.tgz#4334bba7ee241036e580fdd99c019377630d26b4" + integrity sha512-kQpk267uxB19X3X2T1mvNMjyvIEonpNSHrMlK5ZaBU6aZxw7wPbpgKJOjHN3+/GPVpXgAV9soVT2oyHpLkLtyw== + "@statoscope/extensions@5.28.1": version "5.28.1" resolved "https://registry.yarnpkg.com/@statoscope/extensions/-/extensions-5.28.1.tgz#bc270f9366c4b2c13342f1a0d138520cf607a5bb" @@ -10993,7 +10988,7 @@ dependencies: "@types/node" "*" -"@types/prettier@^2.0.0", "@types/prettier@^2.1.5": +"@types/prettier@^2.0.0": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== @@ -12870,15 +12865,15 @@ b4a@^1.6.4: resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== -babel-jest@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.1.tgz#a7141ad1ed5ec50238f3cd36127636823111233a" - integrity sha512-qu+3bdPEQC6KZSPz+4Fyjbga5OODNcp49j6GKzG1EKbkfyJBxEYGVUmVGpwCSeGouG52R4EgYMLb6p9YeEEQ4A== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: - "@jest/transform" "^29.6.1" + "@jest/transform" "^29.7.0" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.5.0" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -12945,10 +12940,10 @@ babel-plugin-istanbul@^6.0.0, babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" - integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -13074,12 +13069,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" - integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^29.5.0" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" babel-runtime@6.x, babel-runtime@^6.26.0: @@ -13369,6 +13364,19 @@ boolbase@^1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= +borc@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/borc/-/borc-3.0.0.tgz#49ada1be84de86f57bb1bb89789f34c186dfa4fe" + integrity sha512-ec4JmVC46kE0+layfnwM3l15O70MlFiEbmQHY/vpqIKiUtPVntv4BY4NVnz3N4vb21edV3mY97XVckFvYHWF9g== + dependencies: + bignumber.js "^9.0.0" + buffer "^6.0.3" + commander "^2.15.0" + ieee754 "^1.1.13" + iso-url "^1.1.5" + json-text-sequence "~0.3.0" + readable-stream "^3.6.0" + bowser@^1.7.3: version "1.9.4" resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a" @@ -13914,27 +13922,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -cbor-extract@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/cbor-extract/-/cbor-extract-2.0.2.tgz#8e45339627fb8b47071e8e71138c630019125939" - integrity sha512-QoLGEgPff03ad/L66P91ci5Zmf7Woq8bh4H5XT3+D5annlrPH5ObHf2Yvo53eDQaDkQtF9tJwMKSWANGXDmwUA== - dependencies: - node-gyp-build-optional-packages "5.0.3" - optionalDependencies: - "@cbor-extract/cbor-extract-darwin-arm64" "2.0.0" - "@cbor-extract/cbor-extract-darwin-x64" "2.0.0" - "@cbor-extract/cbor-extract-linux-arm" "2.0.0" - "@cbor-extract/cbor-extract-linux-arm64" "2.0.0" - "@cbor-extract/cbor-extract-linux-x64" "2.0.0" - "@cbor-extract/cbor-extract-win32-x64" "2.0.0" - -cbor-x@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/cbor-x/-/cbor-x-1.3.3.tgz#5ba0f6d3f6720ea5ba38804e583c020bccf2f762" - integrity sha512-y3V8GlypWM01t3NtYvXmDehuU3bt4q3tewCrvj5EMfUYT6v9HjRu4NHYH3EgbzJCOaZFroAhzci9PHvIIDuOEQ== - optionalDependencies: - cbor-extract "^2.0.2" - ccount@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17" @@ -14500,7 +14487,7 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@2, commander@^2.19.0, commander@^2.20.0, commander@^2.7.1: +commander@2, commander@^2.15.0, commander@^2.19.0, commander@^2.20.0, commander@^2.7.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -14894,6 +14881,19 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -15730,6 +15730,11 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + deep-equal@^1.0.0, deep-equal@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" @@ -17611,17 +17616,16 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" -expect@^29.0.0, expect@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.1.tgz#64dd1c8f75e2c0b209418f2b8d36a07921adfdf1" - integrity sha512-XEdDLonERCU1n9uR56/Stx9OqojaLAQtZf9PrCHH9Hl8YXiEIka3H4NXJ3NOIBmQJTg7+j7buh34PMHfJujc8g== +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: - "@jest/expect-utils" "^29.6.1" - "@types/node" "*" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.6.1" - jest-message-util "^29.6.1" - jest-util "^29.6.1" + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" expiry-js@0.1.7: version "0.1.7" @@ -20718,6 +20722,11 @@ isnumber@~1.0.0: resolved "https://registry.yarnpkg.com/isnumber/-/isnumber-1.0.0.tgz#0e3f9759b581d99dd85086f0ec2a74909cfadd01" integrity sha1-Dj+XWbWB2Z3YUIbw7Cp0kJz63QE= +iso-url@^1.1.5: + version "1.2.1" + resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-1.2.1.tgz#db96a49d8d9a64a1c889fc07cc525d093afb1811" + integrity sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng== + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -20770,7 +20779,7 @@ istanbul-lib-instrument@^4.0.0: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.1.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== @@ -20781,6 +20790,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-processinfo@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz#e1426514662244b2f25df728e8fd1ba35fe53b9c" @@ -20851,83 +20871,83 @@ jest-canvas-mock@^2.5.2: cssfontparser "^1.2.1" moo-color "^1.0.2" -jest-changed-files@^29.5.0: - version "29.5.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" - integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" + jest-util "^29.7.0" p-limit "^3.1.0" -jest-circus@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.1.tgz#861dab37e71a89907d1c0fabc54a0019738ed824" - integrity sha512-tPbYLEiBU4MYAL2XoZme/bgfUeotpDBd81lgHLCbDZZFaGmECk0b+/xejPFtmiBP87GgP/y4jplcRpbH+fgCzQ== +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: - "@jest/environment" "^29.6.1" - "@jest/expect" "^29.6.1" - "@jest/test-result" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - dedent "^0.7.0" + dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^29.6.1" - jest-matcher-utils "^29.6.1" - jest-message-util "^29.6.1" - jest-runtime "^29.6.1" - jest-snapshot "^29.6.1" - jest-util "^29.6.1" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" p-limit "^3.1.0" - pretty-format "^29.6.1" + pretty-format "^29.7.0" pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.1.tgz#99d9afa7449538221c71f358f0fdd3e9c6e89f72" - integrity sha512-607dSgTA4ODIN6go9w6xY3EYkyPFGicx51a69H7yfvt7lN53xNswEVLovq+E77VsTRi5fWprLH0yl4DJgE8Ing== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@jest/core" "^29.6.1" - "@jest/test-result" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" + create-jest "^29.7.0" exit "^0.1.2" - graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.6.1" - jest-util "^29.6.1" - jest-validate "^29.6.1" - prompts "^2.0.1" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" yargs "^17.3.1" -jest-config@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.1.tgz#d785344509065d53a238224c6cdc0ed8e2f2f0dd" - integrity sha512-XdjYV2fy2xYixUiV2Wc54t3Z4oxYPAELUzWnV6+mcbq0rh742X2p52pii5A3oeRzYjLnQxCsZmp0qpI6klE2cQ== +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.6.1" - "@jest/types" "^29.6.1" - babel-jest "^29.6.1" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.6.1" - jest-environment-node "^29.6.1" - jest-get-type "^29.4.3" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.1" - jest-runner "^29.6.1" - jest-util "^29.6.1" - jest-validate "^29.6.1" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.6.1" + pretty-format "^29.7.0" slash "^3.0.0" strip-json-comments "^3.1.1" @@ -20941,7 +20961,7 @@ jest-diff@^26.0.0, jest-diff@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-diff@^29.0.3, jest-diff@^29.6.1: +jest-diff@^29.0.3, jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== @@ -20951,56 +20971,56 @@ jest-diff@^29.0.3, jest-diff@^29.6.1: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-docblock@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" - integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" -jest-each@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.1.tgz#975058e5b8f55c6780beab8b6ab214921815c89c" - integrity sha512-n5eoj5eiTHpKQCAVcNTT7DRqeUmJ01hsAL0Q1SMiBHcBcvTKDELixQOGMCpqhbIuTcfC4kMfSnpmDqRgRJcLNQ== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" chalk "^4.0.0" - jest-get-type "^29.4.3" - jest-util "^29.6.1" - pretty-format "^29.6.1" - -jest-environment-jsdom@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.6.1.tgz#480bce658aa31589309c82ca510351fd7c683bbb" - integrity sha512-PoY+yLaHzVRhVEjcVKSfJ7wXmJW4UqPYNhR05h7u/TK0ouf6DmRNZFBL/Z00zgQMyWGMBXn69/FmOvhEJu8cIw== - dependencies: - "@jest/environment" "^29.6.1" - "@jest/fake-timers" "^29.6.1" - "@jest/types" "^29.6.1" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-jsdom@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f" + integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/jsdom" "^20.0.0" "@types/node" "*" - jest-mock "^29.6.1" - jest-util "^29.6.1" + jest-mock "^29.7.0" + jest-util "^29.7.0" jsdom "^20.0.0" -jest-environment-node@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.1.tgz#08a122dece39e58bc388da815a2166c58b4abec6" - integrity sha512-ZNIfAiE+foBog24W+2caIldl4Irh8Lx1PUhg/GZ0odM1d/h2qORAsejiFc7zb+SEmYPn1yDZzEDSU5PmDkmVLQ== +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== dependencies: - "@jest/environment" "^29.6.1" - "@jest/fake-timers" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.6.1" - jest-util "^29.6.1" + jest-mock "^29.7.0" + jest-util "^29.7.0" jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-get-type@^29.4.3, jest-get-type@^29.6.3: +jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== @@ -21026,32 +21046,32 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" -jest-haste-map@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.1.tgz#62655c7a1c1b349a3206441330fb2dbdb4b63803" - integrity sha512-0m7f9PZXxOCk1gRACiVgX85knUKPKLPg4oRCjLoqIm9brTHXaorMA0JpmtmVkQiT8nmXyIVoZd/nnH1cfC33ig== +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^29.4.3" - jest-util "^29.6.1" - jest-worker "^29.6.1" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.1.tgz#66a902c81318e66e694df7d096a95466cb962f8e" - integrity sha512-OrxMNyZirpOEwkF3UHnIkAiZbtkBWiye+hhBweCHkVbCgyEy71Mwbb5zgeTNYWJBi1qgDVfPC1IwO9dVEeTLwQ== +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - jest-get-type "^29.4.3" - pretty-format "^29.6.1" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" jest-matcher-utils@^26.6.2: version "26.6.2" @@ -21063,15 +21083,15 @@ jest-matcher-utils@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-matcher-utils@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.1.tgz#6c60075d84655d6300c5d5128f46531848160b53" - integrity sha512-SLaztw9d2mfQQKHmJXKM0HCbl2PPVld/t9Xa6P9sgiExijviSp7TnZZpw2Fpt+OI3nwUO/slJbOfzfUMKKC5QA== +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" - jest-diff "^29.6.1" - jest-get-type "^29.4.3" - pretty-format "^29.6.1" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" jest-message-util@^26.6.2: version "26.6.2" @@ -21088,29 +21108,29 @@ jest-message-util@^26.6.2: slash "^3.0.0" stack-utils "^2.0.2" -jest-message-util@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.1.tgz#d0b21d87f117e1b9e165e24f245befd2ff34ff8d" - integrity sha512-KoAW2zAmNSd3Gk88uJ56qXUWbFk787QKmjjJVOjtGFmmGSZgDBrlIL4AfQw1xyMYPNVD7dNInfIbur9B2rd/wQ== +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.6.1" + pretty-format "^29.7.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.1.tgz#049ee26aea8cbf54c764af649070910607316517" - integrity sha512-brovyV9HBkjXAEdRooaTQK42n8usKoSRR3gihzUpYeV/vwqgSoNfrksO7UfSACnPmxasO/8TmHM3w9Hp3G1dgw== +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-util "^29.6.1" + jest-util "^29.7.0" jest-pnp-resolver@^1.2.2: version "1.2.2" @@ -21122,18 +21142,18 @@ jest-regex-util@^26.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-regex-util@^29.4.3: - version "29.4.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" - integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.1.tgz#b85b06670f987a62515bbf625d54a499e3d708f5" - integrity sha512-BbFvxLXtcldaFOhNMXmHRWx1nXQO5LoXiKSGQcA1LxxirYceZT6ch8KTE1bK3X31TNG/JbkI7OkS/ABexVahiw== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - jest-regex-util "^29.4.3" - jest-snapshot "^29.6.1" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" jest-resolve@^26.6.2: version "26.6.2" @@ -21149,73 +21169,73 @@ jest-resolve@^26.6.2: resolve "^1.18.1" slash "^3.0.0" -jest-resolve@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.1.tgz#4c3324b993a85e300add2f8609f51b80ddea39ee" - integrity sha512-AeRkyS8g37UyJiP9w3mmI/VXU/q8l/IH52vj/cDAyScDcemRbSBhfX/NMYIGilQgSVwsjxrCHf3XJu4f+lxCMg== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.6.1" + jest-haste-map "^29.7.0" jest-pnp-resolver "^1.2.2" - jest-util "^29.6.1" - jest-validate "^29.6.1" + jest-util "^29.7.0" + jest-validate "^29.7.0" resolve "^1.20.0" resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.1.tgz#54557087e7972d345540d622ab5bfc3d8f34688c" - integrity sha512-tw0wb2Q9yhjAQ2w8rHRDxteryyIck7gIzQE4Reu3JuOBpGp96xWgF0nY8MDdejzrLCZKDcp8JlZrBN/EtkQvPQ== - dependencies: - "@jest/console" "^29.6.1" - "@jest/environment" "^29.6.1" - "@jest/test-result" "^29.6.1" - "@jest/transform" "^29.6.1" - "@jest/types" "^29.6.1" +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^29.4.3" - jest-environment-node "^29.6.1" - jest-haste-map "^29.6.1" - jest-leak-detector "^29.6.1" - jest-message-util "^29.6.1" - jest-resolve "^29.6.1" - jest-runtime "^29.6.1" - jest-util "^29.6.1" - jest-watcher "^29.6.1" - jest-worker "^29.6.1" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.1.tgz#8a0fc9274ef277f3d70ba19d238e64334958a0dc" - integrity sha512-D6/AYOA+Lhs5e5il8+5pSLemjtJezUr+8zx+Sn8xlmOux3XOqx4d8l/2udBea8CRPqqrzhsKUsN/gBDE/IcaPQ== - dependencies: - "@jest/environment" "^29.6.1" - "@jest/fake-timers" "^29.6.1" - "@jest/globals" "^29.6.1" - "@jest/source-map" "^29.6.0" - "@jest/test-result" "^29.6.1" - "@jest/transform" "^29.6.1" - "@jest/types" "^29.6.1" +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.6.1" - jest-message-util "^29.6.1" - jest-mock "^29.6.1" - jest-regex-util "^29.4.3" - jest-resolve "^29.6.1" - jest-snapshot "^29.6.1" - jest-util "^29.6.1" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" @@ -21249,31 +21269,30 @@ jest-snapshot@^26.3.0: pretty-format "^26.6.2" semver "^7.3.2" -jest-snapshot@^29.0.0, jest-snapshot@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.1.tgz#0d083cb7de716d5d5cdbe80d598ed2fbafac0239" - integrity sha512-G4UQE1QQ6OaCgfY+A0uR1W2AY0tGXUPQpoUClhWHq1Xdnx1H6JOrC2nH5lqnOEqaDgbHFgIwZ7bNq24HpB180A== +jest-snapshot@^29.0.0, jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.6.1" - "@jest/transform" "^29.6.1" - "@jest/types" "^29.6.1" - "@types/prettier" "^2.1.5" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.6.1" + expect "^29.7.0" graceful-fs "^4.2.9" - jest-diff "^29.6.1" - jest-get-type "^29.4.3" - jest-matcher-utils "^29.6.1" - jest-message-util "^29.6.1" - jest-util "^29.6.1" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^29.6.1" + pretty-format "^29.7.0" semver "^7.5.3" jest-specific-snapshot@^4.0.0: @@ -21309,42 +21328,42 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" -jest-util@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.1.tgz#c9e29a87a6edbf1e39e6dee2b4689b8a146679cb" - integrity sha512-NRFCcjc+/uO3ijUVyNOQJluf8PtGCe/W6cix36+M3cTFgiYqFOOW5MgN4JOOcvbUhcKTYVd1CvHz/LWi8d16Mg== +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.1.tgz#765e684af6e2c86dce950aebefbbcd4546d69f7b" - integrity sha512-r3Ds69/0KCN4vx4sYAbGL1EVpZ7MSS0vLmd3gV78O+NAx3PDQQukRU5hNHPXlyqCgFY8XUk7EuTMLugh0KzahA== +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: - "@jest/types" "^29.6.1" + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^29.4.3" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^29.6.1" + pretty-format "^29.7.0" -jest-watcher@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.1.tgz#7c0c43ddd52418af134c551c92c9ea31e5ec942e" - integrity sha512-d4wpjWTS7HEZPaaj8m36QiaP856JthRZkrgcIY/7ISoUWPIillrXM23WPboZVLbiwZBt4/qn2Jke84Sla6JhFA== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.13.1" - jest-util "^29.6.1" + jest-util "^29.7.0" string-length "^4.0.1" jest-worker@^26.5.0, jest-worker@^26.6.2: @@ -21365,25 +21384,25 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest-worker@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.1.tgz#64b015f0e985ef3a8ad049b61fe92b3db74a5319" - integrity sha512-U+Wrbca7S8ZAxAe9L6nb6g8kPdia5hj32Puu5iOqBCMTMWFHXuK6dOV2IFrpedbTV8fjMFLdWNttQTBL6u2MRA== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" - jest-util "^29.6.1" + jest-util "^29.7.0" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.6.1: - version "29.6.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.1.tgz#74be1cb719c3abe439f2d94aeb18e6540a5b02ad" - integrity sha512-Nirw5B4nn69rVUZtemCQhwxOBhm0nsp3hmtF4rzCeWD7BkjAXRIji7xWQfnTNbz9g0aVsBX6aZK3n+23LM6uDw== +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^29.6.1" - "@jest/types" "^29.6.1" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^29.6.1" + jest-cli "^29.7.0" joi-to-json@^4.3.0: version "4.3.0" @@ -21606,6 +21625,13 @@ json-stringify-safe@5.0.1, json-stringify-safe@^5.0.1, json-stringify-safe@~5.0. resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json-text-sequence@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/json-text-sequence/-/json-text-sequence-0.3.0.tgz#6603e0ee45da41f949669fd18744b97fb209e6ce" + integrity sha512-7khKIYPKwXQem4lWXfpIN/FEnhztCeRPSxH4qm3fVlqulwujrRDD54xAwDDn/qVKpFtV550+QAkcWJcufzqQuA== + dependencies: + "@sovpro/delimited-stream" "^1.1.0" + json5@*, json5@^2.1.2, json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -23894,11 +23920,6 @@ node-forge@^1, node-forge@^1.2.1, node-forge@^1.3.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-gyp-build-optional-packages@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" - integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== - node-gyp-build-optional-packages@5.0.7: version "5.0.7" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" @@ -25743,7 +25764,7 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -pretty-format@^29.0.0, pretty-format@^29.6.1, pretty-format@^29.7.0: +pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==