diff --git a/.buildkite/hooks/post-command b/.buildkite/hooks/post-command index d9a8ad668da0b..13e0f4d795828 100755 --- a/.buildkite/hooks/post-command +++ b/.buildkite/hooks/post-command @@ -1,3 +1,7 @@ #!/usr/bin/env bash -.buildkite/scripts/lifecycle/post_command.sh +if [[ "$BUILDKITE_AGENT_NAME" =~ ^bk-agent ]]; then + echo "Pipeline file triggered from outside the kibana executors, skipping post_command" +else + .buildkite/scripts/lifecycle/post_command.sh +fi diff --git a/.buildkite/hooks/pre-command b/.buildkite/hooks/pre-command index 58a2c5f0b499d..95e2975d094c3 100644 --- a/.buildkite/hooks/pre-command +++ b/.buildkite/hooks/pre-command @@ -1,3 +1,7 @@ #!/usr/bin/env bash -source .buildkite/scripts/lifecycle/pre_command.sh +if [[ "$BUILDKITE_AGENT_NAME" =~ ^bk-agent ]]; then + echo "Pipeline file triggered from outside the kibana executors, skipping pre_command" +else + source .buildkite/scripts/lifecycle/pre_command.sh +fi diff --git a/.buildkite/pipelines/on_merge_unsupported_ftrs.yml b/.buildkite/pipelines/on_merge_unsupported_ftrs.yml index 30e7929fd6e19..5ee55e63c1408 100644 --- a/.buildkite/pipelines/on_merge_unsupported_ftrs.yml +++ b/.buildkite/pipelines/on_merge_unsupported_ftrs.yml @@ -96,8 +96,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" - command: .buildkite/scripts/steps/functional/osquery_cypress.sh label: 'Osquery Cypress Tests' @@ -110,8 +108,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-osquery/**/*" - command: .buildkite/scripts/steps/functional/synthetics_plugin.sh label: 'Synthetics @elastic/synthetics Tests' diff --git a/.buildkite/pipelines/pipeline.kibana-serverless-release.yaml b/.buildkite/pipelines/pipeline.kibana-serverless-release.yaml index 59fe89cc69e4a..6bceff183662a 100644 --- a/.buildkite/pipelines/pipeline.kibana-serverless-release.yaml +++ b/.buildkite/pipelines/pipeline.kibana-serverless-release.yaml @@ -6,4 +6,4 @@ steps: build: env: SERVICE_COMMIT_HASH: "${BUILDKITE_COMMIT:0:12}" - REMOTE_SERVICE_CONFIG: https://raw.githubusercontent.com/elastic/serverless-gitops/main/gen/gpctl/kibana/tagged-release.yaml + REMOTE_SERVICE_CONFIG: https://raw.githubusercontent.com/elastic/serverless-gitops/main/gen/gpctl/kibana/config.yaml diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index 7a4291fab7003..522d2e34e5682 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -146,8 +146,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" # status_exception: Native role management is not enabled in this Elasticsearch instance # - command: .buildkite/scripts/steps/functional/security_serverless_defend_workflows.sh @@ -161,8 +159,6 @@ steps: # automatic: # - exit_status: '*' # limit: 1 - # artifact_paths: - # - "target/kibana-security-solution/**/*" - command: .buildkite/scripts/steps/functional/security_serverless_investigations.sh label: 'Serverless Security Investigations Cypress Tests' @@ -176,8 +172,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" - command: .buildkite/scripts/steps/functional/security_serverless_explore.sh label: 'Serverless Security Explore Cypress Tests' @@ -191,8 +185,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" - command: .buildkite/scripts/steps/lint.sh label: 'Linting' diff --git a/.buildkite/pipelines/pull_request/defend_workflows.yml b/.buildkite/pipelines/pull_request/defend_workflows.yml index 3a50e3ece206e..00f701c4e16d9 100644 --- a/.buildkite/pipelines/pull_request/defend_workflows.yml +++ b/.buildkite/pipelines/pull_request/defend_workflows.yml @@ -10,8 +10,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" - command: .buildkite/scripts/steps/functional/defend_workflows_vagrant.sh label: 'Defend Workflows Endpoint Cypress Tests' @@ -24,5 +22,3 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" diff --git a/.buildkite/pipelines/pull_request/osquery_cypress.yml b/.buildkite/pipelines/pull_request/osquery_cypress.yml index c56d94524f60d..50c4dd4a3faa5 100644 --- a/.buildkite/pipelines/pull_request/osquery_cypress.yml +++ b/.buildkite/pipelines/pull_request/osquery_cypress.yml @@ -10,8 +10,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-osquery/**/*" - command: .buildkite/scripts/steps/functional/osquery_cypress_burn.sh label: 'Osquery Cypress Tests, burning changed specs' @@ -22,8 +20,6 @@ steps: soft_fail: true retry: automatic: false - artifact_paths: - - "target/kibana-osquery/**/*" # Error: self-signed certificate in certificate chain # - command: .buildkite/scripts/steps/functional/security_serverless_osquery.sh @@ -37,5 +33,3 @@ steps: # automatic: # - exit_status: '*' # limit: 1 - # artifact_paths: - # - "target/kibana-osquery/**/*" diff --git a/.buildkite/pipelines/pull_request/response_ops.yml b/.buildkite/pipelines/pull_request/response_ops.yml index b2ef5199fab91..38ca242949d86 100644 --- a/.buildkite/pipelines/pull_request/response_ops.yml +++ b/.buildkite/pipelines/pull_request/response_ops.yml @@ -10,5 +10,3 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" diff --git a/.buildkite/pipelines/pull_request/response_ops_cases.yml b/.buildkite/pipelines/pull_request/response_ops_cases.yml index af2e58b65ab34..312c62c01c732 100644 --- a/.buildkite/pipelines/pull_request/response_ops_cases.yml +++ b/.buildkite/pipelines/pull_request/response_ops_cases.yml @@ -9,5 +9,3 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-solution/**/*" diff --git a/.buildkite/pipelines/pull_request/security_solution.yml b/.buildkite/pipelines/pull_request/security_solution.yml index 58b416548ec5f..2b7a6faaf212c 100644 --- a/.buildkite/pipelines/pull_request/security_solution.yml +++ b/.buildkite/pipelines/pull_request/security_solution.yml @@ -10,8 +10,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - 'target/kibana-security-solution/**/*' - command: .buildkite/scripts/steps/functional/security_solution_explore.sh label: 'Explore - Security Solution Cypress Tests' @@ -24,8 +22,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - 'target/kibana-security-solution/**/*' - command: .buildkite/scripts/steps/functional/security_solution_investigations.sh label: 'Investigations - Security Solution Cypress Tests' @@ -38,8 +34,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - 'target/kibana-security-solution/**/*' - command: .buildkite/scripts/steps/functional/security_solution_burn.sh label: 'Security Solution Cypress tests, burning changed specs' @@ -51,8 +45,6 @@ steps: retry: automatic: false soft_fail: true - artifact_paths: - - 'target/kibana-security-solution/**/*' - command: .buildkite/scripts/steps/code_generation/security_solution_codegen.sh label: 'Security Solution OpenAPI codegen' diff --git a/.buildkite/pipelines/pull_request/threat_intelligence.yml b/.buildkite/pipelines/pull_request/threat_intelligence.yml index f9b9050d28d95..b91be5faffdec 100644 --- a/.buildkite/pipelines/pull_request/threat_intelligence.yml +++ b/.buildkite/pipelines/pull_request/threat_intelligence.yml @@ -10,5 +10,3 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-threat-intelligence/**/*" diff --git a/.buildkite/pipelines/quality-gates/pipeline.kibana-tests.yaml b/.buildkite/pipelines/quality-gates/pipeline.kibana-tests.yaml index 27e55dfced9d7..0acdb66f8d5f2 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.kibana-tests.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.kibana-tests.yaml @@ -1,4 +1,17 @@ +# This pipeline serves as the entry point for your service's quality gates definitions. When +# properly configured, it will be invoked automatically as part of the automated +# promotion process once a new version was rolled out in one of the various cloud stages. +# +# The updated environment is provided via ENVIRONMENT variable. The seedling +# step will branch and execute pipeline snippets at the following location: +# pipeline.tests-qa.yaml +# pipeline.tests-staging.yaml +# pipeline.tests-production.yaml +# +# Docs: https://docs.elastic.dev/serverless/qualitygates + env: + TEAM_CHANNEL: "#kibana-mission-control" ENVIRONMENT: ${ENVIRONMENT?} steps: @@ -8,3 +21,7 @@ steps: command: "make -C /agent run-environment-tests" agents: image: "docker.elastic.co/ci-agent-images/quality-gate-seedling:0.0.2" + +notify: + - slack: "${TEAM_CHANNEL?}" + if: build.branch == "main" && build.state == "failed" diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml index 5a0738ead7d9c..1c30a7f734df4 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-production.yaml @@ -1,10 +1,29 @@ +# These pipeline steps constitute the quality gate for your service within the production +# environment. Incorporate any necessary additional logic to validate the service's integrity. +# A failure in this pipeline build will prevent further progression to the subsequent stage. + steps: - label: ":pipeline::fleet::seedling: Trigger Observability Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Observability specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" - label: ":pipeline::lock::seedling: Trigger Security Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Security specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" + + - label: ":rocket: Run cp e2e tests" + trigger: "ess-k8s-production-e2e-tests" + build: + message: "${BUILDKITE_MESSAGE}" + env: + REGION_ID: aws-us-east-1 + NAME_PREFIX: ci_test_${SERVICE}-promotion_ + + - wait: ~ + + - label: ":judge::seedling: Trigger Manual Tests Phase" + command: "make -C /agent trigger-manual-verification-phase" + agents: + image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2" diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml index 669b306bc2ceb..e03e986f65833 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml @@ -1,20 +1,39 @@ +# These pipeline steps constitute the quality gate for your service within the QA environment. +# Incorporate any necessary additional logic to validate the service's integrity. A failure in +# this pipeline build will prevent further progression to the subsequent stage. + steps: - label: ":pipeline::kibana::seedling: Trigger Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Kibana specific tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" - label: ":pipeline::fleet::seedling: Trigger Fleet Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Fleet specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" - label: ":pipeline::lock::seedling: Trigger Security Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Security specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" - label: ":pipeline::lock::seedling: Trigger Control Plane Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Control Plane specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" + + - label: ":rocket: Run cp e2e tests" + trigger: "ess-k8s-qa-e2e-tests-daily" + build: + message: "${BUILDKITE_MESSAGE}" + env: + REGION_ID: aws-eu-west-1 + NAME_PREFIX: ci_test_kibana-promotion_ + + - wait: ~ + + - label: ":judge::seedling: Trigger Manual Tests Phase" + command: "make -C /agent trigger-manual-verification-phase" + agents: + image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2" diff --git a/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml b/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml index 5a0738ead7d9c..83bfd0d27e34c 100644 --- a/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml +++ b/.buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml @@ -1,10 +1,29 @@ +# These pipeline steps constitute the quality gate for your service within the staging environment. +# Incorporate any necessary additional logic to validate the service's integrity. A failure in +# this pipeline build will prevent further progression to the subsequent stage. + steps: - label: ":pipeline::fleet::seedling: Trigger Observability Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Observability specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" - label: ":pipeline::lock::seedling: Trigger Security Kibana Tests for ${ENVIRONMENT}" command: echo "replace me with Security specific Kibana tests" - agent: + agents: image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364" + + - label: ":rocket: Run cp e2e tests" + trigger: "ess-k8s-staging-e2e-tests" + build: + message: "${BUILDKITE_MESSAGE}" + env: + REGION_ID: aws-us-east-1 + NAME_PREFIX: ci_test_kibana-promotion_ + + - wait: ~ + + - label: ":judge::seedling: Trigger Manual Tests Phase" + command: "make -C /agent trigger-manual-verification-phase" + agents: + image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2" diff --git a/.buildkite/pipelines/serverless.yml b/.buildkite/pipelines/serverless.yml index be9816545e2bf..10d1090521adb 100644 --- a/.buildkite/pipelines/serverless.yml +++ b/.buildkite/pipelines/serverless.yml @@ -110,8 +110,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-serverless/**/*" - command: .buildkite/scripts/steps/functional/security_serverless_explore.sh label: 'Serverless Explore - Security Solution Cypress Tests' @@ -124,8 +122,6 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-serverless/**/*" - command: .buildkite/scripts/steps/functional/security_serverless_investigations.sh label: 'Serverless Investigations - Security Solution Cypress Tests' @@ -138,5 +134,3 @@ steps: automatic: - exit_status: '*' limit: 1 - artifact_paths: - - "target/kibana-security-serverless/**/*" diff --git a/.buildkite/scripts/pipelines/pull_request/pipeline.ts b/.buildkite/scripts/pipelines/pull_request/pipeline.ts index cadfa23b53f9d..6fe1bb1b251e1 100644 --- a/.buildkite/scripts/pipelines/pull_request/pipeline.ts +++ b/.buildkite/scripts/pipelines/pull_request/pipeline.ts @@ -119,6 +119,15 @@ const uploadPipeline = (pipelineContent: string | object) => { pipeline.push(getPipeline('.buildkite/pipelines/pull_request/apm_cypress.yml')); } + if ( + (await doAnyChangesMatch([/^x-pack\/plugins\/observability_onboarding/])) || + GITHUB_PR_LABELS.includes('ci:all-cypress-suites') + ) { + pipeline.push( + getPipeline('.buildkite/pipelines/pull_request/observability_onboarding_cypress.yml') + ); + } + if ( (await doAnyChangesMatch([/^x-pack\/plugins\/profiling/])) || GITHUB_PR_LABELS.includes('ci:all-cypress-suites') diff --git a/.buildkite/scripts/steps/artifacts/docker_image.sh b/.buildkite/scripts/steps/artifacts/docker_image.sh index 3743aedfdc655..6a0c23384ef65 100755 --- a/.buildkite/scripts/steps/artifacts/docker_image.sh +++ b/.buildkite/scripts/steps/artifacts/docker_image.sh @@ -98,12 +98,14 @@ steps: - label: ":argo: Update kibana image tag for kibana-controller using gpctl" async: true branches: main - trigger: gpctl-promote + trigger: gpctl-promote-with-e2e-tests build: env: SERVICE_COMMIT_HASH: "$GIT_ABBREV_COMMIT" - REMOTE_SERVICE_CONFIG: https://raw.githubusercontent.com/elastic/serverless-gitops/main/gen/gpctl/kibana/config.yaml - + SERVICE: kibana-controller + NAMESPACE: kibana-ci + IMAGE_NAME: kibana-serverless + REMOTE_SERVICE_CONFIG: https://raw.githubusercontent.com/elastic/serverless-gitops/main/gen/gpctl/kibana/dev.yaml EOF else diff --git a/.buildkite/scripts/steps/functional/defend_workflows.sh b/.buildkite/scripts/steps/functional/defend_workflows.sh index 555d6cba2d374..111fa6a23d289 100755 --- a/.buildkite/scripts/steps/functional/defend_workflows.sh +++ b/.buildkite/scripts/steps/functional/defend_workflows.sh @@ -12,4 +12,5 @@ echo "--- Defend Workflows Cypress tests" cd x-pack/plugins/security_solution +set +e yarn cypress:dw:run; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/defend_workflows_vagrant.sh b/.buildkite/scripts/steps/functional/defend_workflows_vagrant.sh index 57b7b43163400..0dfabadb90687 100755 --- a/.buildkite/scripts/steps/functional/defend_workflows_vagrant.sh +++ b/.buildkite/scripts/steps/functional/defend_workflows_vagrant.sh @@ -12,4 +12,5 @@ echo "--- Defend Workflows Endpoint Cypress tests" cd x-pack/plugins/security_solution +set +e yarn cypress:dw:endpoint:run; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/osquery_cypress.sh b/.buildkite/scripts/steps/functional/osquery_cypress.sh index c6cc98d71ce07..eab0f808b7352 100755 --- a/.buildkite/scripts/steps/functional/osquery_cypress.sh +++ b/.buildkite/scripts/steps/functional/osquery_cypress.sh @@ -12,4 +12,7 @@ export JOB=kibana-osquery-cypress echo "--- Osquery Cypress tests" -yarn --cwd x-pack/plugins/osquery cypress:run +cd x-pack/plugins/osquery + +set +e +yarn cypress:run; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/osquery_cypress_burn.sh b/.buildkite/scripts/steps/functional/osquery_cypress_burn.sh index b7fd648e53939..ed59007086e16 100755 --- a/.buildkite/scripts/steps/functional/osquery_cypress_burn.sh +++ b/.buildkite/scripts/steps/functional/osquery_cypress_burn.sh @@ -14,4 +14,5 @@ buildkite-agent meta-data set "${BUILDKITE_JOB_ID}_is_test_execution_step" 'fals echo "--- Osquery Cypress tests, burning changed specs (Chrome)" -yarn --cwd x-pack/plugins/osquery cypress:changed-specs-only +set +e +yarn cypress:changed-specs-only; status=$?; yarn junit:merge && exit $status \ No newline at end of file diff --git a/.buildkite/scripts/steps/functional/response_ops.sh b/.buildkite/scripts/steps/functional/response_ops.sh index 1c065b2373b66..05e740bbf8d55 100755 --- a/.buildkite/scripts/steps/functional/response_ops.sh +++ b/.buildkite/scripts/steps/functional/response_ops.sh @@ -12,4 +12,5 @@ echo "--- Response Ops Cypress Tests on Security Solution" cd x-pack/test/security_solution_cypress +set +e yarn cypress:run:respops:ess; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/response_ops_cases.sh b/.buildkite/scripts/steps/functional/response_ops_cases.sh index 52eb3fce1985e..895edf0395dd0 100755 --- a/.buildkite/scripts/steps/functional/response_ops_cases.sh +++ b/.buildkite/scripts/steps/functional/response_ops_cases.sh @@ -12,4 +12,5 @@ echo "--- Response Ops Cases Cypress Tests on Security Solution" cd x-pack/test/security_solution_cypress +set +e yarn cypress:run:cases:ess; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/security_serverless.sh b/.buildkite/scripts/steps/functional/security_serverless.sh index 0a14478414bf3..984697ba6129b 100644 --- a/.buildkite/scripts/steps/functional/security_serverless.sh +++ b/.buildkite/scripts/steps/functional/security_serverless.sh @@ -12,4 +12,5 @@ echo "--- Security Serverless Cypress Tests" cd x-pack/test/security_solution_cypress +set +e yarn cypress:run:serverless; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/security_serverless_explore.sh b/.buildkite/scripts/steps/functional/security_serverless_explore.sh index 805f4fe147180..64cd304a4bff2 100644 --- a/.buildkite/scripts/steps/functional/security_serverless_explore.sh +++ b/.buildkite/scripts/steps/functional/security_serverless_explore.sh @@ -12,4 +12,5 @@ echo "--- Explore - Security Solution Cypress Tests" cd x-pack/test/security_solution_cypress +set +e yarn cypress:explore:run:serverless; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/security_serverless_investigations.sh b/.buildkite/scripts/steps/functional/security_serverless_investigations.sh index 15f249d474c40..49a9392f23de1 100644 --- a/.buildkite/scripts/steps/functional/security_serverless_investigations.sh +++ b/.buildkite/scripts/steps/functional/security_serverless_investigations.sh @@ -12,4 +12,5 @@ echo "--- Investigations Cypress Tests on Serverless" cd x-pack/test/security_solution_cypress +set +e yarn cypress:investigations:run:serverless; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/security_solution.sh b/.buildkite/scripts/steps/functional/security_solution.sh index f02419a0b6f8c..ffd82a3601ba4 100755 --- a/.buildkite/scripts/steps/functional/security_solution.sh +++ b/.buildkite/scripts/steps/functional/security_solution.sh @@ -12,4 +12,5 @@ echo "--- Security Solution Cypress tests (Chrome)" cd x-pack/test/security_solution_cypress +set +e yarn cypress:run:ess; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/security_solution_explore.sh b/.buildkite/scripts/steps/functional/security_solution_explore.sh index e7d21b61f7209..03295b993dafd 100644 --- a/.buildkite/scripts/steps/functional/security_solution_explore.sh +++ b/.buildkite/scripts/steps/functional/security_solution_explore.sh @@ -12,4 +12,5 @@ echo "--- Explore Cypress Tests on Security Solution" cd x-pack/test/security_solution_cypress +set +e yarn cypress:explore:run:ess; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/functional/security_solution_investigations.sh b/.buildkite/scripts/steps/functional/security_solution_investigations.sh index 217e79bc9ecfc..11e0d1fb7fea7 100644 --- a/.buildkite/scripts/steps/functional/security_solution_investigations.sh +++ b/.buildkite/scripts/steps/functional/security_solution_investigations.sh @@ -12,4 +12,5 @@ echo "--- Investigations - Security Solution Cypress Tests" cd x-pack/test/security_solution_cypress +set +e yarn cypress:investigations:run:ess; status=$?; yarn junit:merge && exit $status diff --git a/.buildkite/scripts/steps/test/jest_integration.sh b/.buildkite/scripts/steps/test/jest_integration.sh index fd7b9a1d6ad54..6ebff3ae984b8 100755 --- a/.buildkite/scripts/steps/test/jest_integration.sh +++ b/.buildkite/scripts/steps/test/jest_integration.sh @@ -8,5 +8,9 @@ is_test_execution_step .buildkite/scripts/bootstrap.sh +echo '--- Docker login' +echo "$KIBANA_DOCKER_PASSWORD" | docker login -u "$KIBANA_DOCKER_USERNAME" --password-stdin docker.elastic.co +trap 'docker logout docker.elastic.co' EXIT + echo '--- Jest Integration Tests' .buildkite/scripts/steps/test/jest_parallel.sh jest.integration.config.js diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d0dc397e6b6ed..cd4fe15e8827c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -545,6 +545,7 @@ packages/kbn-plugin-helpers @elastic/kibana-operations examples/portable_dashboards_example @elastic/kibana-presentation examples/preboot_example @elastic/kibana-security @elastic/kibana-core src/plugins/presentation_util @elastic/kibana-presentation +x-pack/plugins/profiling_data_access @elastic/profiling-ui x-pack/plugins/profiling @elastic/profiling-ui x-pack/packages/kbn-random-sampling @elastic/kibana-visualizations packages/kbn-react-field @elastic/kibana-data-discovery @@ -750,6 +751,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-doc-viewer @elastic/kibana-data-discovery examples/unified_doc_viewer @elastic/kibana-core src/plugins/unified_doc_viewer @elastic/kibana-data-discovery diff --git a/.github/workflows/create-deploy-tag.yml b/.github/workflows/create-deploy-tag.yml index a2c0bd0539984..d91df87fd547a 100644 --- a/.github/workflows/create-deploy-tag.yml +++ b/.github/workflows/create-deploy-tag.yml @@ -19,7 +19,7 @@ concurrency: jobs: create-deploy-tag: # Temporary, we need a way to limit this to a GitHub team instead of specific users - if: contains('["watson","clintandrewhall","kobelb","lukeelmers","thomasneirynck"]', github.triggering_actor) + if: contains('["watson","clintandrewhall","kobelb","lukeelmers","thomasneirynck","jbudz","mistic","delanni","Ikuni17"]', github.triggering_actor) runs-on: ubuntu-latest permissions: contents: write @@ -77,6 +77,10 @@ jobs: "type": "mrkdwn", "text": "*Workflow run:*\n" }, + { + "type": "mrkdwn", + "text": "*Commit:*\n" + }, { "type": "mrkdwn", "text": "*Git tag:*\n" @@ -103,7 +107,7 @@ jobs: "type": "section", "text": { "type": "mrkdwn", - "text": "*Useful links:*\n\n • \n • " + "text": "*Useful links:*\n\n • \n • " } }, { @@ -162,6 +166,10 @@ jobs: { "type": "mrkdwn", "text": "*Workflow run:*\n" + }, + { + "type": "mrkdwn", + "text": "*Commit:*\n" } ] }, diff --git a/.i18nrc.json b/.i18nrc.json index 7b2d9f423c6a2..eb098a7011a15 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -125,7 +125,8 @@ "unifiedDocViewer": ["src/plugins/unified_doc_viewer", "packages/kbn-unified-doc-viewer"], "unifiedSearch": "src/plugins/unified_search", "unifiedFieldList": "packages/kbn-unified-field-list", - "unifiedHistogram": "src/plugins/unified_histogram" + "unifiedHistogram": "src/plugins/unified_histogram", + "unifiedDataTable": "packages/kbn-unified-data-table" }, "translations": [] } diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 9e00a4bb2b49a..1675e5db1912c 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: 2023-08-31 +date: 2023-09-05 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 4401ed9fbf670..17d00954ff5e6 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index a8e8744a274bb..e69040bbcb687 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: 2023-08-31 +date: 2023-09-05 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 389d01d2ec502..74220f3e48d63 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index e1b038257f9bf..8bd384647c099 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -408,7 +408,7 @@ "label": "APIEndpoint", "description": [], "signature": [ - "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/samples\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search 2023-10-31\" | \"POST /api/apm/services/{serviceName}/annotation 2023-10-31\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/services/{serviceName}/alerts_count\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service-group/counts\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"POST /internal/apm/traces/aggregated_critical_path\" | \"GET /internal/apm/traces/{traceId}/transactions/{transactionId}\" | \"GET /internal/apm/traces/{traceId}/spans/{spanId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /api/apm/settings/agent-configuration 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/view 2023-10-31\" | \"DELETE /api/apm/settings/agent-configuration 2023-10-31\" | \"PUT /api/apm/settings/agent-configuration 2023-10-31\" | \"POST /api/apm/settings/agent-configuration/search 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/environments 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/agent_name 2023-10-31\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps 2023-10-31\" | \"POST /api/apm/sourcemaps 2023-10-31\" | \"DELETE /api/apm/sourcemaps/{id} 2023-10-31\" | \"POST /api/apm/androidmaps 2023-10-31\" | \"POST /internal/apm/sourcemaps/migrate_fleet_artifacts\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema 2023-10-31\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys 2023-10-31\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\" | \"GET /internal/apm/get_agents_per_service\" | \"GET /internal/apm/get_latest_agent_versions\" | \"GET /internal/apm/services/{serviceName}/agent_instances\" | \"GET /internal/apm/services/{serviceName}/mobile/filters\" | \"GET /internal/apm/mobile-services/{serviceName}/most_used_charts\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/sessions\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/http_requests\" | \"GET /internal/apm/mobile-services/{serviceName}/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/location/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/terms\" | \"GET /internal/apm/mobile-services/{serviceName}/main_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/detailed_statistics\" | \"GET /internal/apm/diagnostics\" | \"POST /internal/apm/assistant/get_apm_timeseries\" | \"GET /internal/apm/assistant/get_service_summary\" | \"GET /internal/apm/assistant/get_error_document\" | \"POST /internal/apm/assistant/get_correlation_values\" | \"GET /internal/apm/assistant/get_downstream_dependencies\" | \"GET /internal/apm/assistant/get_services_list\"" + "\"POST /internal/apm/data_view/static\" | \"GET /internal/apm/data_view/title\" | \"GET /internal/apm/environments\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/groups/main_statistics_by_transaction_name\" | \"POST /internal/apm/services/{serviceName}/errors/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/samples\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/error/{errorId}\" | \"GET /internal/apm/services/{serviceName}/errors/distribution\" | \"GET /internal/apm/services/{serviceName}/errors/{groupId}/top_erroneous_transactions\" | \"POST /internal/apm/latency/overall_distribution/transactions\" | \"GET /internal/apm/services/{serviceName}/metrics/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/nodes\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/charts\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/summary\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/functions_overview\" | \"GET /internal/apm/services/{serviceName}/metrics/serverless/active_instances\" | \"GET /internal/apm/observability_overview\" | \"GET /internal/apm/observability_overview/has_data\" | \"GET /internal/apm/service-map\" | \"GET /internal/apm/service-map/service/{serviceName}\" | \"GET /internal/apm/service-map/dependency\" | \"GET /internal/apm/services\" | \"POST /internal/apm/services/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/metadata/details\" | \"GET /internal/apm/services/{serviceName}/metadata/icons\" | \"GET /internal/apm/services/{serviceName}/agent\" | \"GET /internal/apm/services/{serviceName}/transaction_types\" | \"GET /internal/apm/services/{serviceName}/node/{serviceNodeName}/metadata\" | \"GET /api/apm/services/{serviceName}/annotation/search 2023-10-31\" | \"POST /api/apm/services/{serviceName}/annotation 2023-10-31\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/details/{serviceNodeName}\" | \"GET /internal/apm/services/{serviceName}/throughput\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics\" | \"GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/dependencies\" | \"GET /internal/apm/services/{serviceName}/dependencies/breakdown\" | \"GET /internal/apm/services/{serviceName}/anomaly_charts\" | \"GET /internal/apm/services/{serviceName}/alerts_count\" | \"GET /internal/apm/service-groups\" | \"GET /internal/apm/service-group\" | \"POST /internal/apm/service-group\" | \"DELETE /internal/apm/service-group\" | \"GET /internal/apm/service-group/services\" | \"GET /internal/apm/service-group/counts\" | \"GET /internal/apm/suggestions\" | \"GET /internal/apm/traces/{traceId}\" | \"GET /internal/apm/traces\" | \"GET /internal/apm/traces/{traceId}/root_transaction\" | \"GET /internal/apm/transactions/{transactionId}\" | \"GET /internal/apm/traces/find\" | \"POST /internal/apm/traces/aggregated_critical_path\" | \"GET /internal/apm/traces/{traceId}/transactions/{transactionId}\" | \"GET /internal/apm/traces/{traceId}/spans/{spanId}\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/main_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/groups/detailed_statistics\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/latency\" | \"GET /internal/apm/services/{serviceName}/transactions/traces/samples\" | \"GET /internal/apm/services/{serviceName}/transaction/charts/breakdown\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/error_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate\" | \"GET /internal/apm/services/{serviceName}/transactions/charts/coldstart_rate_by_transaction_name\" | \"GET /internal/apm/rule_types/transaction_error_rate/chart_preview\" | \"GET /internal/apm/rule_types/error_count/chart_preview\" | \"GET /internal/apm/rule_types/transaction_duration/chart_preview\" | \"GET /api/apm/settings/agent-configuration 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/view 2023-10-31\" | \"DELETE /api/apm/settings/agent-configuration 2023-10-31\" | \"PUT /api/apm/settings/agent-configuration 2023-10-31\" | \"POST /api/apm/settings/agent-configuration/search 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/environments 2023-10-31\" | \"GET /api/apm/settings/agent-configuration/agent_name 2023-10-31\" | \"GET /internal/apm/settings/anomaly-detection/jobs\" | \"POST /internal/apm/settings/anomaly-detection/jobs\" | \"GET /internal/apm/settings/anomaly-detection/environments\" | \"POST /internal/apm/settings/anomaly-detection/update_to_v3\" | \"GET /internal/apm/settings/apm-index-settings\" | \"GET /internal/apm/settings/apm-indices\" | \"POST /internal/apm/settings/apm-indices/save\" | \"GET /internal/apm/settings/custom_links/transaction\" | \"GET /internal/apm/settings/custom_links\" | \"POST /internal/apm/settings/custom_links\" | \"PUT /internal/apm/settings/custom_links/{id}\" | \"DELETE /internal/apm/settings/custom_links/{id}\" | \"GET /api/apm/sourcemaps 2023-10-31\" | \"POST /api/apm/sourcemaps 2023-10-31\" | \"DELETE /api/apm/sourcemaps/{id} 2023-10-31\" | \"POST /internal/apm/sourcemaps/migrate_fleet_artifacts\" | \"GET /internal/apm/fleet/has_apm_policies\" | \"GET /internal/apm/fleet/agents\" | \"POST /api/apm/fleet/apm_server_schema 2023-10-31\" | \"GET /internal/apm/fleet/apm_server_schema/unsupported\" | \"GET /internal/apm/fleet/migration_check\" | \"POST /internal/apm/fleet/cloud_apm_package_policy\" | \"GET /internal/apm/fleet/java_agent_versions\" | \"GET /internal/apm/dependencies/top_dependencies\" | \"GET /internal/apm/dependencies/upstream_services\" | \"GET /internal/apm/dependencies/metadata\" | \"GET /internal/apm/dependencies/charts/latency\" | \"GET /internal/apm/dependencies/charts/throughput\" | \"GET /internal/apm/dependencies/charts/error_rate\" | \"GET /internal/apm/dependencies/operations\" | \"GET /internal/apm/dependencies/charts/distribution\" | \"GET /internal/apm/dependencies/operations/spans\" | \"GET /internal/apm/correlations/field_candidates/transactions\" | \"GET /internal/apm/correlations/field_value_stats/transactions\" | \"POST /internal/apm/correlations/field_value_pairs/transactions\" | \"POST /internal/apm/correlations/significant_correlations/transactions\" | \"POST /internal/apm/correlations/p_values/transactions\" | \"GET /internal/apm/fallback_to_transactions\" | \"GET /internal/apm/has_data\" | \"GET /internal/apm/event_metadata/{processorEvent}/{id}\" | \"GET /internal/apm/agent_keys\" | \"GET /internal/apm/agent_keys/privileges\" | \"POST /internal/apm/api_key/invalidate\" | \"POST /api/apm/agent_keys 2023-10-31\" | \"GET /internal/apm/storage_explorer\" | \"GET /internal/apm/services/{serviceName}/storage_details\" | \"GET /internal/apm/storage_chart\" | \"GET /internal/apm/storage_explorer/privileges\" | \"GET /internal/apm/storage_explorer_summary_stats\" | \"GET /internal/apm/storage_explorer/is_cross_cluster_search\" | \"GET /internal/apm/storage_explorer/get_services\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/parents\" | \"GET /internal/apm/traces/{traceId}/span_links/{spanId}/children\" | \"GET /internal/apm/services/{serviceName}/infrastructure_attributes\" | \"GET /internal/apm/debug-telemetry\" | \"GET /internal/apm/time_range_metadata\" | \"GET /internal/apm/settings/labs\" | \"GET /internal/apm/get_agents_per_service\" | \"GET /internal/apm/get_latest_agent_versions\" | \"GET /internal/apm/services/{serviceName}/agent_instances\" | \"GET /internal/apm/services/{serviceName}/mobile/filters\" | \"GET /internal/apm/mobile-services/{serviceName}/most_used_charts\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/sessions\" | \"GET /internal/apm/mobile-services/{serviceName}/transactions/charts/http_requests\" | \"GET /internal/apm/mobile-services/{serviceName}/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/location/stats\" | \"GET /internal/apm/mobile-services/{serviceName}/terms\" | \"GET /internal/apm/mobile-services/{serviceName}/main_statistics\" | \"GET /internal/apm/mobile-services/{serviceName}/detailed_statistics\" | \"GET /internal/apm/diagnostics\" | \"POST /internal/apm/assistant/get_apm_timeseries\" | \"GET /internal/apm/assistant/get_service_summary\" | \"GET /internal/apm/assistant/get_error_document\" | \"POST /internal/apm/assistant/get_correlation_values\" | \"GET /internal/apm/assistant/get_downstream_dependencies\" | \"POST /internal/apm/assistant/get_services_list\"" ], "path": "x-pack/plugins/apm/server/routes/apm_routes/get_global_apm_server_route_repository.ts", "deprecated": false, @@ -455,9 +455,9 @@ "label": "APMServerRouteRepository", "description": [], "signature": [ - "{ \"GET /internal/apm/assistant/get_services_list\": { endpoint: \"GET /internal/apm/assistant/get_services_list\"; params?: ", + "{ \"POST /internal/apm/assistant/get_services_list\": { endpoint: \"POST /internal/apm/assistant/get_services_list\"; params?: ", "TypeC", - "<{ query: ", + "<{ body: ", "IntersectionC", "<[", "TypeC", @@ -468,24 +468,8 @@ "; }>, ", "PartialC", "<{ 'service.environment': ", - "UnionC", - "<[", - "LiteralC", - "<\"ENVIRONMENT_NOT_DEFINED\">, ", - "LiteralC", - "<\"ENVIRONMENT_ALL\">, ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">]>; healthStatus: ", + "; healthStatus: ", "ArrayC", "<", "UnionC", @@ -507,17 +491,7 @@ "ServiceHealthStatus", ".critical>]>>; }>]>; }> | undefined; handler: ({}: ", "APMRouteHandlerResources", - " & { params: { query: { start: string; end: string; } & { 'service.environment'?: \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", - "Branded", - " | undefined; healthStatus?: ", + " & { params: { body: { start: string; end: string; } & { 'service.environment'?: string | undefined; healthStatus?: ", "ServiceHealthStatus", "[] | undefined; }; }; }) => Promise<{ content: ApmServicesListContent; }>; } & ", "APMRouteCreateOptions", @@ -711,25 +685,7 @@ "IntersectionC", "<[", "TypeC", - "<{ 'service.environment': ", - "UnionC", - "<[", - "LiteralC", - "<\"ENVIRONMENT_NOT_DEFINED\">, ", - "LiteralC", - "<\"ENVIRONMENT_ALL\">, ", - "BrandC", - "<", - "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">]>; 'service.name': ", + "<{ 'service.name': ", "StringC", "; title: ", "StringC", @@ -813,23 +769,15 @@ "StringC", "; offset: ", "StringC", + "; 'service.environment': ", + "StringC", "; }>]>>; start: ", "StringC", "; end: ", "StringC", "; }>; }> | undefined; handler: ({}: ", "APMRouteHandlerResources", - " & { params: { body: { stats: ({ 'service.environment': \"ENVIRONMENT_NOT_DEFINED\" | \"ENVIRONMENT_ALL\" | ", - "Branded", - "; 'service.name': string; title: string; timeseries: ({ name: ", + " & { params: { body: { stats: ({ 'service.name': string; title: string; timeseries: ({ name: ", "ApmTimeseriesType", ".transactionThroughput | ", "ApmTimeseriesType", @@ -845,7 +793,7 @@ "LatencyAggregationType", "; } & { 'transaction.type'?: string | undefined; }) | { name: ", "ApmTimeseriesType", - ".errorEventRate; }; } & { filter?: string | undefined; offset?: string | undefined; })[]; start: string; end: string; }; }; }) => Promise<{ content: Omit<", + ".errorEventRate; }; } & { filter?: string | undefined; offset?: string | undefined; 'service.environment'?: string | undefined; })[]; start: string; end: string; }; }; }) => Promise<{ content: Omit<", "ApmTimeseries", ", \"data\">[]; data: ", "ApmTimeseries", @@ -3193,28 +3141,6 @@ "APMRouteHandlerResources", ") => Promise; } & ", "APMRouteCreateOptions", - "; \"POST /api/apm/androidmaps 2023-10-31\": { endpoint: \"POST /api/apm/androidmaps 2023-10-31\"; params?: ", - "TypeC", - "<{ body: ", - "TypeC", - "<{ service_name: ", - "StringC", - "; service_version: ", - "StringC", - "; map_file: ", - "Type", - "; }>; }> | undefined; handler: ({}: ", - "APMRouteHandlerResources", - " & { params: { body: { service_name: string; service_version: string; map_file: string; }; }; }) => Promise<", - { - "pluginId": "fleet", - "scope": "server", - "docId": "kibFleetPluginApi", - "section": "def-server.Artifact", - "text": "Artifact" - }, - " | undefined>; } & ", - "APMRouteCreateOptions", "; \"DELETE /api/apm/sourcemaps/{id} 2023-10-31\": { endpoint: \"DELETE /api/apm/sourcemaps/{id} 2023-10-31\"; params?: ", "TypeC", "<{ path: ", diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index d8e50b0782113..1f3e0da71d41a 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 4b3bcd2d2ae4e..7e0cb19b76349 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index 1c921b0135d29..7c9e072b32a5a 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 2d20ae08d90ab..b095e025ebb25 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: 2023-08-31 +date: 2023-09-05 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 23886a991e581..b35d2c259da58 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: 2023-08-31 +date: 2023-09-05 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 2f3b23becc49d..391741661db72 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.devdocs.json b/api_docs/cases.devdocs.json index 15f422cdf22ba..5d00886d09ee8 100644 --- a/api_docs/cases.devdocs.json +++ b/api_docs/cases.devdocs.json @@ -1091,7 +1091,14 @@ "\nReturn the UI capabilities for each type of operation. These strings must match the values defined in the UI\nhere: x-pack/plugins/cases/public/client/helpers/capabilities.ts" ], "signature": [ - "() => { all: readonly [\"create_cases\", \"read_cases\", \"update_cases\", \"push_cases\", \"cases_connectors\"]; read: readonly [\"read_cases\", \"cases_connectors\"]; delete: readonly [\"delete_cases\"]; }" + "() => ", + { + "pluginId": "cases", + "scope": "common", + "docId": "kibCasesPluginApi", + "section": "def-common.CasesUiCapabilities", + "text": "CasesUiCapabilities" + } ], "path": "x-pack/plugins/cases/common/utils/capabilities.ts", "deprecated": false, @@ -1108,7 +1115,14 @@ "label": "getApiTags", "description": [], "signature": [ - "(owner: \"cases\" | \"observability\" | \"securitySolution\") => { all: readonly [\"casesSuggestUserProfiles\", \"bulkGetUserProfiles\", \"casesGetConnectorsConfigure\", string, string]; read: readonly [\"casesSuggestUserProfiles\", \"bulkGetUserProfiles\", \"casesGetConnectorsConfigure\", string]; delete: readonly [string]; }" + "(owner: \"cases\" | \"observability\" | \"securitySolution\") => ", + { + "pluginId": "cases", + "scope": "common", + "docId": "kibCasesPluginApi", + "section": "def-common.CasesApiTags", + "text": "CasesApiTags" + } ], "path": "x-pack/plugins/cases/common/utils/api_tags.ts", "deprecated": false, @@ -1236,6 +1250,62 @@ } ], "interfaces": [ + { + "parentPluginId": "cases", + "id": "def-common.CasesApiTags", + "type": "Interface", + "tags": [], + "label": "CasesApiTags", + "description": [], + "path": "x-pack/plugins/cases/common/utils/api_tags.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "cases", + "id": "def-common.CasesApiTags.all", + "type": "Object", + "tags": [], + "label": "all", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/api_tags.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesApiTags.read", + "type": "Object", + "tags": [], + "label": "read", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/api_tags.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesApiTags.delete", + "type": "Object", + "tags": [], + "label": "delete", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/api_tags.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.CasesPermissions", @@ -1327,6 +1397,62 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "cases", + "id": "def-common.CasesUiCapabilities", + "type": "Interface", + "tags": [], + "label": "CasesUiCapabilities", + "description": [], + "path": "x-pack/plugins/cases/common/utils/capabilities.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "cases", + "id": "def-common.CasesUiCapabilities.all", + "type": "Object", + "tags": [], + "label": "all", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/capabilities.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesUiCapabilities.read", + "type": "Object", + "tags": [], + "label": "read", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/capabilities.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cases", + "id": "def-common.CasesUiCapabilities.delete", + "type": "Object", + "tags": [], + "label": "delete", + "description": [], + "signature": [ + "readonly string[]" + ], + "path": "x-pack/plugins/cases/common/utils/capabilities.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.Ecs", @@ -2031,6 +2157,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "cases", + "id": "def-common.CASES_CONNECTORS_CAPABILITY", + "type": "string", + "tags": [], + "label": "CASES_CONNECTORS_CAPABILITY", + "description": [], + "signature": [ + "\"cases_connectors\"" + ], + "path": "x-pack/plugins/cases/common/constants/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.CASES_URL", @@ -2651,6 +2792,23 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "cases", + "id": "def-common.GET_CONNECTORS_CONFIGURE_API_TAG", + "type": "string", + "tags": [], + "label": "GET_CONNECTORS_CONFIGURE_API_TAG", + "description": [ + "\nThis tag is registered for the connectors (configure) get API" + ], + "signature": [ + "\"casesGetConnectorsConfigure\"" + ], + "path": "x-pack/plugins/cases/common/constants/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "cases", "id": "def-common.GetRelatedCasesByAlertResponse", diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index a913aa0945465..34f1b185e06bc 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.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 | |-------------------|-----------|------------------------|-----------------| -| 94 | 0 | 75 | 27 | +| 104 | 0 | 84 | 27 | ## Client diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index d5a1edb002467..80664fabad87d 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: 2023-08-31 +date: 2023-09-05 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 7aae586da2bf1..73b5ef4c2517e 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx index c6ef27a4028fe..8b0f6a65ddd8e 100644 --- a/api_docs/cloud_chat.mdx +++ b/api_docs/cloud_chat.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChat title: "cloudChat" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChat plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] --- import cloudChatObj from './cloud_chat.devdocs.json'; diff --git a/api_docs/cloud_chat_provider.mdx b/api_docs/cloud_chat_provider.mdx index 0b0dbf26b397e..89e27b560261f 100644 --- a/api_docs/cloud_chat_provider.mdx +++ b/api_docs/cloud_chat_provider.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudChatProvider title: "cloudChatProvider" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudChatProvider plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChatProvider'] --- import cloudChatProviderObj from './cloud_chat_provider.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 02ad60cf1a945..5410157a3a4e8 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: 2023-08-31 +date: 2023-09-05 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 00833fb50673a..765d3226f9c3a 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: 2023-08-31 +date: 2023-09-05 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 79a3fadafe3b1..e0b54f328ba2c 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: 2023-08-31 +date: 2023-09-05 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 b2729c117f55e..113f43f209db5 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: 2023-08-31 +date: 2023-09-05 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 cf0bc5870fc3f..6318a4faa542c 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: 2023-08-31 +date: 2023-09-05 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 6b2585a637149..9886b7a3ea00b 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: 2023-08-31 +date: 2023-09-05 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 52e16d4727595..a5dd74b6330d1 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: 2023-08-31 +date: 2023-09-05 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 d0dd1b4d42fe6..66ba3a87e78bb 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: 2023-08-31 +date: 2023-09-05 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 eef050e768f79..91b1eb51f287b 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: 2023-08-31 +date: 2023-09-05 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 5b5b9823e115b..a45b5025b2fe9 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: 2023-08-31 +date: 2023-09-05 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 a637553e5a090..31a0b4ae7ada9 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -13679,6 +13679,10 @@ "plugin": "@kbn/unified-field-list", "path": "packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts" }, + { + "plugin": "@kbn/unified-field-list", + "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" + }, { "plugin": "@kbn/event-annotation-components", "path": "packages/kbn-event-annotation-components/components/group_editor_controls/group_editor_controls.tsx" @@ -13691,10 +13695,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.ts" }, - { - "plugin": "@kbn/unified-field-list", - "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx" @@ -13969,15 +13969,15 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" + "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" + "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/services/es_index_service.ts" + "path": "x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts" }, { "plugin": "transform", @@ -21444,6 +21444,10 @@ "plugin": "@kbn/unified-field-list", "path": "packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts" }, + { + "plugin": "@kbn/unified-field-list", + "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" + }, { "plugin": "@kbn/event-annotation-components", "path": "packages/kbn-event-annotation-components/components/group_editor_controls/group_editor_controls.tsx" @@ -21456,10 +21460,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.ts" }, - { - "plugin": "@kbn/unified-field-list", - "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx" @@ -21734,15 +21734,15 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" + "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" + "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/services/es_index_service.ts" + "path": "x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts" }, { "plugin": "transform", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 2911aebd8a829..70949b17f4987 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3310 | 33 | 2583 | 26 | +| 3311 | 33 | 2584 | 26 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index a24f30fead3d0..62d0861bbbf19 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3310 | 33 | 2583 | 26 | +| 3311 | 33 | 2584 | 26 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 3b5cd7151721e..ceb9136800672 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -32457,6 +32457,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.ESQL_SEARCH_STRATEGY", + "type": "string", + "tags": [], + "label": "ESQL_SEARCH_STRATEGY", + "description": [], + "signature": [ + "\"esql\"" + ], + "path": "src/plugins/data/common/search/strategies/esql_search/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.EsQuerySearchAfter", diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 64ca58d97572f..fde4b2f40f862 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3310 | 33 | 2583 | 26 | +| 3311 | 33 | 2584 | 26 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 526aaff115ec6..d2fa815d40409 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: 2023-08-31 +date: 2023-09-05 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 d406e99e7bf6e..c10490b5d7a9a 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: 2023-08-31 +date: 2023-09-05 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 88364eb00b359..6e41bcc12d78a 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: 2023-08-31 +date: 2023-09-05 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 4a845a6057727..347f1f24fed09 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -367,6 +367,10 @@ "plugin": "@kbn/unified-field-list", "path": "packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts" }, + { + "plugin": "@kbn/unified-field-list", + "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" + }, { "plugin": "@kbn/event-annotation-components", "path": "packages/kbn-event-annotation-components/components/group_editor_controls/group_editor_controls.tsx" @@ -379,10 +383,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.ts" }, - { - "plugin": "@kbn/unified-field-list", - "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx" @@ -657,15 +657,15 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" + "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" + "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/services/es_index_service.ts" + "path": "x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts" }, { "plugin": "transform", @@ -8331,6 +8331,10 @@ "plugin": "@kbn/unified-field-list", "path": "packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts" }, + { + "plugin": "@kbn/unified-field-list", + "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" + }, { "plugin": "@kbn/event-annotation-components", "path": "packages/kbn-event-annotation-components/components/group_editor_controls/group_editor_controls.tsx" @@ -8343,10 +8347,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.ts" }, - { - "plugin": "@kbn/unified-field-list", - "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx" @@ -8621,15 +8621,15 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" + "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" + "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/services/es_index_service.ts" + "path": "x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts" }, { "plugin": "transform", @@ -15405,6 +15405,10 @@ "plugin": "@kbn/unified-field-list", "path": "packages/kbn-unified-field-list/src/hooks/use_existing_fields.ts" }, + { + "plugin": "@kbn/unified-field-list", + "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" + }, { "plugin": "@kbn/event-annotation-components", "path": "packages/kbn-event-annotation-components/components/group_editor_controls/group_editor_controls.tsx" @@ -15417,10 +15421,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/data_views_service/loader.ts" }, - { - "plugin": "@kbn/unified-field-list", - "path": "packages/kbn-unified-field-list/src/services/field_stats/load_field_stats.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx" @@ -15695,15 +15695,15 @@ }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" + "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts" + "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx" }, { "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/services/es_index_service.ts" + "path": "x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts" }, { "plugin": "transform", diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 894fa34f5c587..0d85b10f37cbd 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: 2023-08-31 +date: 2023-09-05 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 60b95dfb340ea..dec5ec2987ed8 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index b96f1f5177af6..a01b818334271 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -22,7 +22,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, dataViews, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, visTypeTimeseries, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega, data | - | | | @kbn/es-query, @kbn/visualization-ui-components, securitySolution, observability, timelines, lists, threatIntelligence, savedSearch, data, logsShared, savedObjectsManagement, unifiedSearch, controls, @kbn/unified-field-list, @kbn/event-annotation-components, lens, triggersActionsUi, dataVisualizer, ml, visTypeTimeseries, apm, exploratoryView, fleet, stackAlerts, infra, canvas, enterpriseSearch, graph, transform, upgradeAssistant, uptime, ux, maps, dataViewManagement, inputControlVis, visDefaultEditor, presentationUtil, visTypeTimelion, visTypeVega | - | | | home, data, esUiShared, savedObjectsManagement, ml, exploratoryView, fleet, observability, apm, indexLifecycleManagement, observabilityOnboarding, synthetics, upgradeAssistant, uptime, ux, kibanaOverview | - | -| | share, uiActions, guidedOnboarding, home, management, spaces, security, savedObjects, serverless, visualizations, controls, dashboard, savedObjectsTagging, expressionXY, lens, expressionMetricVis, expressionGauge, alerting, triggersActionsUi, cases, licenseManagement, advancedSettings, maps, dataVisualizer, aiops, ml, exploratoryView, fleet, observability, infra, profiling, apm, expressionImage, expressionMetric, expressionError, expressionRevealImage, expressionRepeatImage, expressionShape, indexManagement, crossClusterReplication, enterpriseSearch, globalSearchBar, graph, grokdebugger, indexLifecycleManagement, ingestPipelines, logstash, monitoring, observabilityOnboarding, osquery, devTools, painlessLab, remoteClusters, rollup, searchprofiler, newsfeed, securitySolution, snapshotRestore, synthetics, transform, upgradeAssistant, uptime, ux, watcher, cloudDataMigration, console, filesManagement, kibanaOverview, visDefaultEditor, expressionHeatmap, expressionLegacyMetricVis, expressionPartitionVis, expressionTagcloud, visTypeTable, visTypeTimelion, visTypeTimeseries, visTypeVega, visTypeVislib | - | +| | share, uiActions, guidedOnboarding, home, management, spaces, security, savedObjects, indexManagement, serverless, visualizations, controls, dashboard, savedObjectsTagging, expressionXY, lens, expressionMetricVis, expressionGauge, alerting, triggersActionsUi, cases, licenseManagement, advancedSettings, maps, dataVisualizer, aiops, ml, exploratoryView, fleet, observability, infra, profiling, apm, expressionImage, expressionMetric, expressionError, expressionRevealImage, expressionRepeatImage, expressionShape, crossClusterReplication, enterpriseSearch, globalSearchBar, graph, grokdebugger, indexLifecycleManagement, ingestPipelines, logstash, monitoring, observabilityOnboarding, osquery, devTools, painlessLab, remoteClusters, rollup, searchprofiler, newsfeed, securitySolution, snapshotRestore, synthetics, transform, upgradeAssistant, uptime, ux, watcher, cloudDataMigration, console, filesManagement, kibanaOverview, visDefaultEditor, expressionHeatmap, expressionLegacyMetricVis, expressionPartitionVis, expressionTagcloud, visTypeTable, visTypeTimelion, visTypeTimeseries, visTypeVega, visTypeVislib | - | | | encryptedSavedObjects, actions, data, ml, securitySolution, logstash, cloudChat | - | | | actions, ml, savedObjectsTagging, enterpriseSearch | - | | | @kbn/core-saved-objects-browser-internal, @kbn/core, savedObjects, presentationUtil, visualizations, dataVisualizer, ml, aiops, dashboardEnhanced, graph, lens, securitySolution, eventAnnotation, @kbn/core-saved-objects-browser-mocks | - | @@ -36,7 +36,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-api-server-internal, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, home, fleet, osquery, securitySolution, @kbn/core-saved-objects-browser-mocks, graph, lists, alerting | - | | | alerting, discover, securitySolution | - | | | securitySolution | - | -| | inspector, data, licensing, security, savedObjects, dataViewEditor, unifiedSearch, embeddable, visualizations, controls, dashboard, savedObjectsTagging, eventAnnotation, dataViewFieldEditor, lens, triggersActionsUi, cases, observabilityShared, telemetry, advancedSettings, maps, exploratoryView, fleet, observability, banners, reporting, timelines, cloudSecurityPosture, runtimeFields, indexManagement, dashboardEnhanced, imageEmbeddable, graph, monitoring, securitySolution, synthetics, transform, uptime, cloudLinks, console, dataViewManagement, filesManagement, uiActions, visTypeVislib | - | +| | inspector, data, licensing, security, savedObjects, runtimeFields, indexManagement, dataViewEditor, unifiedSearch, embeddable, visualizations, controls, dashboard, savedObjectsTagging, dataViewFieldEditor, eventAnnotation, lens, triggersActionsUi, cases, observabilityShared, telemetry, advancedSettings, maps, exploratoryView, fleet, observability, banners, reporting, timelines, cloudSecurityPosture, dashboardEnhanced, imageEmbeddable, graph, monitoring, securitySolution, synthetics, uptime, cloudLinks, console, dataViewManagement, filesManagement, uiActions, visTypeVislib | - | | | observability, @kbn/securitysolution-data-table, securitySolution | - | | | @kbn/securitysolution-data-table, securitySolution | - | | | securitySolution | - | @@ -70,7 +70,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-api-server-internal | - | | | @kbn/core-saved-objects-api-server-internal | - | | | @kbn/core-saved-objects-api-server-internal, canvas, @kbn/core-saved-objects-browser-internal | - | -| | @kbn/core-saved-objects-server-internal, @kbn/core-plugins-server-internal, savedObjectsTagging, @kbn/core-saved-objects-server-mocks | - | | | @kbn/core, kibanaUtils, expressions, data, savedObjectsTaggingOss, embeddable, visualizations, controls, savedObjectsTagging, uiActionsEnhanced, lens, maps, canvas, dashboardEnhanced, globalSearchProviders, @kbn/core-saved-objects-api-browser, savedObjects, savedObjectsManagement, eventAnnotation, graph, dashboard | - | | | @kbn/core-saved-objects-browser, @kbn/core-saved-objects-browser-internal, @kbn/core, home, savedObjects, visualizations, lens, visTypeTimeseries, @kbn/core-saved-objects-browser-mocks | - | | | @kbn/core-saved-objects-browser-internal, savedObjects, @kbn/core-saved-objects-browser-mocks | - | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 5864b2813f5eb..b09904070bf9a 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -107,7 +107,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [plugin_context.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts#:~:text=legacy), [plugin_context.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts#:~:text=legacy) | - | | | [plugin.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin.ts#:~:text=AsyncPlugin), [plugin.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin.ts#:~:text=AsyncPlugin) | 8.8.0 | | | [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs), [plugin_manifest_parser.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/discovery/plugin_manifest_parser.ts#:~:text=extraPublicDirs) | - | -| | [plugin_context.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts#:~:text=getAllIndices), [plugin_context.ts](https://github.com/elastic/kibana/tree/main/packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts#:~:text=getAllIndices) | - | @@ -266,15 +265,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [import_dashboards.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts#:~:text=migrationVersion) | - | | | [import_dashboards.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts#:~:text=migrationVersion), [import_dashboards.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts#:~:text=migrationVersion), [import_dashboards.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts#:~:text=migrationVersion), [import_dashboards.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/import_dashboards.ts#:~:text=migrationVersion) | - | | | [collect_references_deep.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/collect_references_deep.test.ts#:~:text=SavedObjectAttributes), [collect_references_deep.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/collect_references_deep.test.ts#:~:text=SavedObjectAttributes), [collect_references_deep.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/collect_references_deep.test.ts#:~:text=SavedObjectAttributes), [collect_references_deep.test.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/legacy_import_export/lib/collect_references_deep.test.ts#:~:text=SavedObjectAttributes) | - | -| | [saved_objects_service.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts#:~:text=getAllIndices) | - | - - - -## @kbn/core-saved-objects-server-mocks - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [saved_objects_service.mock.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts#:~:text=getAllIndices), [saved_objects_service.mock.ts](https://github.com/elastic/kibana/tree/main/packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts#:~:text=getAllIndices) | - | @@ -1398,7 +1388,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [request_handler_context.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/server/request_handler_context.ts#:~:text=authz) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/types.ts#:~:text=SavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/types.ts#:~:text=SavedObject), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.ts#:~:text=SavedObject), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.ts#:~:text=SavedObject), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.test.ts#:~:text=SavedObject), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.test.ts#:~:text=SavedObject), [utils.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.test.ts#:~:text=SavedObject), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/test_utils/index.ts#:~:text=SavedObject), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/test_utils/index.ts#:~:text=SavedObject), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/test_utils/index.ts#:~:text=SavedObject)+ 3 more | - | | | [references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/references.ts#:~:text=SavedObjectReference), [references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/references.ts#:~:text=SavedObjectReference), [references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/references.ts#:~:text=SavedObjectReference), [references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/references.ts#:~:text=SavedObjectReference), [references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/references.ts#:~:text=SavedObjectReference), [references.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/common/references.ts#:~:text=SavedObjectReference), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.ts#:~:text=SavedObjectReference), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.ts#:~:text=SavedObjectReference), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.ts#:~:text=SavedObjectReference), [utils.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/public/utils.ts#:~:text=SavedObjectReference)+ 11 more | - | -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/server/plugin.ts#:~:text=getAllIndices) | - | | | [tag.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/saved_objects_tagging/server/saved_objects/tag.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | @@ -1615,10 +1604,9 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [register_transform_health_rule_type.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts#:~:text=alertFactory) | - | -| | [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [es_index_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/services/es_index_service.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [es_index_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/services/es_index_service.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title) | - | -| | [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [es_index_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/services/es_index_service.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [es_index_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/services/es_index_service.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title) | - | -| | [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [es_index_service.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/services/es_index_service.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title) | - | -| | [toast_notification_text.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx#:~:text=toMountPoint), [toast_notification_text.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx#:~:text=toMountPoint), [step_create_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx#:~:text=toMountPoint), [step_create_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx#:~:text=toMountPoint), [step_create_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx#:~:text=toMountPoint), [step_create_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx#:~:text=toMountPoint), [step_create_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx#:~:text=toMountPoint), [step_details_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx#:~:text=toMountPoint), [step_details_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx#:~:text=toMountPoint), [step_details_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx#:~:text=toMountPoint)+ 19 more | - | +| | [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [use_data_view_exists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [use_data_view_exists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title) | - | +| | [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [use_data_view_exists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [use_data_view_exists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title) | - | +| | [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_search_items/common.ts#:~:text=title), [filter_term_form.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx#:~:text=title), [use_data_view_exists.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts#:~:text=title), [transforms.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/routes/api/transforms.ts#:~:text=title), [common.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/common.test.ts#:~:text=title) | - | | | [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/app.tsx#:~:text=KibanaThemeProvider), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/app.tsx#:~:text=KibanaThemeProvider), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/app.tsx#:~:text=KibanaThemeProvider) | - | | | [license.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/server/services/license.ts#:~:text=license%24) | 8.8.0 | | | [mount_management_section.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/transform/public/app/mount_management_section.ts#:~:text=savedObjects) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index af65fb19f5342..bbdf4234fb74b 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 5169da2cde4e7..6b0064c8f0858 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 65c3fb0bef8a3..13f444604cc4f 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -991,24 +991,6 @@ "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "discover", - "id": "def-public.DiscoverSetup.docViews", - "type": "Object", - "tags": [], - "label": "docViews", - "description": [], - "signature": [ - "{ addDocView(docViewRaw: ", - "DocViewInput", - " | ", - "DocViewInputFn", - "): void; }" - ], - "path": "src/plugins/discover/public/plugin.tsx", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "discover", "id": "def-public.DiscoverSetup.locator", diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index ad7a18b2ba759..a63ae77760646 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 99 | 0 | 72 | 17 | +| 98 | 0 | 71 | 15 | ## Client diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 5b0c6edf5ed30..675890ffa1ac8 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index e51c759a4260f..90e742bda6198 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 34334fb846e41..ace6dbb2a4c7d 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: 2023-08-31 +date: 2023-09-05 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 fec72fb9822ca..be41e8d5bc699 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: 2023-08-31 +date: 2023-09-05 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 cbde77f143f8c..8fd457f066ffe 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: 2023-08-31 +date: 2023-09-05 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 4f01a1f739e50..cf6cd38a5251c 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: 2023-08-31 +date: 2023-09-05 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 18f78e4eded19..07418305cdc71 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index a74883318db9e..f5aaa1ac5bd5c 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 6143c89b29960..d72d41002cf5d 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 9bf96154dbd29..edabbf7f2b416 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: 2023-08-31 +date: 2023-09-05 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 ad2a0e0bd2dbb..d977e9d3c6444 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: 2023-08-31 +date: 2023-09-05 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 d302c947899f2..cf353aeb1663c 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: 2023-08-31 +date: 2023-09-05 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 6bae86336271a..4dc1d165e75fb 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: 2023-08-31 +date: 2023-09-05 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 2b275e3dcee13..bd676f00bd162 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: 2023-08-31 +date: 2023-09-05 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 24bd3420a2358..e07f5ea5cd63f 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: 2023-08-31 +date: 2023-09-05 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 c6219a34b0b6f..38013982ab985 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: 2023-08-31 +date: 2023-09-05 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 847c71aad5042..0e8902fbf0a0f 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: 2023-08-31 +date: 2023-09-05 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 bab457b980673..fcae81f5883cf 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: 2023-08-31 +date: 2023-09-05 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 56b8d2021ef89..039b050b32bc6 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: 2023-08-31 +date: 2023-09-05 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 3e9f12147ab59..9f2f3434acb56 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: 2023-08-31 +date: 2023-09-05 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 4ef83001528c2..8f9d323b53023 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: 2023-08-31 +date: 2023-09-05 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 1c4898d10e35f..f3e7d5eeaee3c 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: 2023-08-31 +date: 2023-09-05 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 d7ef8aae7da96..214d3d21153e2 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: 2023-08-31 +date: 2023-09-05 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 784b377013cc5..7f245d3889e1f 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index bb622685ac10c..8bd5ba8e59463 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -6975,6 +6975,20 @@ "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "expressions", + "id": "def-public.Datatable.warning", + "type": "string", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -18368,6 +18382,20 @@ "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "expressions", + "id": "def-server.Datatable.warning", + "type": "string", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -30133,6 +30161,20 @@ "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "expressions", + "id": "def-common.Datatable.warning", + "type": "string", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -39366,7 +39408,7 @@ }, "[]; meta?: ", "DatatableMeta", - " | undefined; }" + " | undefined; warning?: string | undefined; }" ], "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", "deprecated": false, @@ -39424,7 +39466,7 @@ }, "[]; meta?: ", "DatatableMeta", - " | undefined; }" + " | undefined; warning?: string | undefined; }" ], "path": "src/plugins/expressions/common/expression_types/specs/datatable.ts", "deprecated": false, @@ -41815,7 +41857,7 @@ }, " | { [x: string]: any; })[]; type: \"datatable\"; meta?: ", "DatatableMeta", - " | undefined; }>" + " | undefined; warning?: string | undefined; }>" ], "path": "src/plugins/expressions/common/expression_functions/specs/map_column.ts", "deprecated": false, diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 64b7d3d883c47..ce5cf4cc0939f 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2205 | 17 | 1746 | 5 | +| 2208 | 17 | 1749 | 5 | ## Client diff --git a/api_docs/features.mdx b/api_docs/features.mdx index d433e0d7ce363..db13ee18b015e 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: 2023-08-31 +date: 2023-09-05 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 7b82e841bd51b..bc8dff8530b8e 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 8e634433e6dac..7cb2ca900ab10 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index 705919e015db5..54c4bb33663b7 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: 2023-08-31 +date: 2023-09-05 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 9974c3202afc6..fe86c6e0074a2 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index e23eadd716382..58bf0969ecb00 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: 2023-08-31 +date: 2023-09-05 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 bc9cbe06e3141..53425f7e23d24 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: 2023-08-31 +date: 2023-09-05 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 5a273a247dc82..a1230a39ce3f2 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: 2023-08-31 +date: 2023-09-05 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 2cc874f59ccb6..9915ed0e2802a 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: 2023-08-31 +date: 2023-09-05 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 73b1867ba3fc9..586539ca0d0aa 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: 2023-08-31 +date: 2023-09-05 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 eb6ca9dc97ce7..c394ca0f93615 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: 2023-08-31 +date: 2023-09-05 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 6b276602ed0c2..25a6849dd773c 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 3d00b256aada5..0cccce355c006 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index b91af00a7b1ba..5b47285b9edcd 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 9aec795382afe..c3c4259afdfb1 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 8fbc51a7b68c6..9d13f55b01c3d 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 105c0d2e386a3..6e51456817f54 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 18fa1ec5ce347..9bb30d89b5db3 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index b21f2bd757b77..c60de50828f02 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 8a0c83193084f..45459e55d57d2 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 0caf1d8eca132..64b3d4ae9600c 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 1b1fb2313ddde..0387bc14aa30c 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: 2023-08-31 +date: 2023-09-05 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 b8a41b63456ac..a2dfb1d49ac93 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index aa2a2fabaa159..c36b7b83b967c 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index a204b4f414b2e..053d4313a1174 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 8763ae8c69da2..5b8013b126b1a 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index b58602fd604ae..c2055ef8d02bc 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 613596463a6b9..df61103a09941 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 8887898a4263f..fb844e6b7c754 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 4f6e5089e8d6c..30c1a22a8ec4a 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: 2023-08-31 +date: 2023-09-05 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_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 74728db7e4de8..09007f8b0e82e 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 615bac13b1df8..a04a564cde49c 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 77f98b81aa9a5..ce523adf57985 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index e0961accc4a26..9f4d642a9f4ef 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 97c2a284e51dd..82da938a2e3b9 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 88f075ca55107..b14c9ededd480 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: 2023-08-31 +date: 2023-09-05 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 f4bdbd8388c08..e49db93b653a5 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: 2023-08-31 +date: 2023-09-05 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 22f93b5c9d991..6b8ed504dc92d 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: 2023-08-31 +date: 2023-09-05 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 e95d9d3ce05ea..a5c29e677ec23 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: 2023-08-31 +date: 2023-09-05 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 0aede1cb69fb5..50523b6543892 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: 2023-08-31 +date: 2023-09-05 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 6f74fac507084..30878509c9908 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: 2023-08-31 +date: 2023-09-05 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 b80687daef231..001c90e047fae 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: 2023-08-31 +date: 2023-09-05 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.devdocs.json b/api_docs/kbn_code_editor.devdocs.json index 97a003dc517d0..eea9517c0bb23 100644 --- a/api_docs/kbn_code_editor.devdocs.json +++ b/api_docs/kbn_code_editor.devdocs.json @@ -27,7 +27,7 @@ "label": "CodeEditor", "description": [], "signature": [ - "({ languageId, value, onChange, width, options, overrideEditorWillMount, editorDidMount, editorWillMount, useDarkTheme: useDarkThemeProp, transparentBackground, suggestionProvider, signatureProvider, hoverProvider, placeholder, languageConfiguration, \"aria-label\": ariaLabel, isCopyable, allowFullScreen, }: React.PropsWithChildren<", + "({ languageId, value, onChange, width, height, options, overrideEditorWillMount, editorDidMount, editorWillMount, useDarkTheme: useDarkThemeProp, transparentBackground, suggestionProvider, signatureProvider, hoverProvider, placeholder, languageConfiguration, \"aria-label\": ariaLabel, isCopyable, allowFullScreen, }: React.PropsWithChildren<", "Props", ">) => JSX.Element" ], @@ -40,7 +40,7 @@ "id": "def-common.CodeEditor.$1", "type": "CompoundType", "tags": [], - "label": "{\n languageId,\n value,\n onChange,\n width,\n options,\n overrideEditorWillMount,\n editorDidMount,\n editorWillMount,\n useDarkTheme: useDarkThemeProp,\n transparentBackground,\n suggestionProvider,\n signatureProvider,\n hoverProvider,\n placeholder,\n languageConfiguration,\n 'aria-label': ariaLabel = i18n.translate('sharedUXPackages.codeEditor.ariaLabel', {\n defaultMessage: 'Code Editor',\n }),\n isCopyable = false,\n allowFullScreen = false,\n}", + "label": "{\n languageId,\n value,\n onChange,\n width,\n height = '100px',\n options,\n overrideEditorWillMount,\n editorDidMount,\n editorWillMount,\n useDarkTheme: useDarkThemeProp,\n transparentBackground,\n suggestionProvider,\n signatureProvider,\n hoverProvider,\n placeholder,\n languageConfiguration,\n 'aria-label': ariaLabel = i18n.translate('sharedUXPackages.codeEditor.ariaLabel', {\n defaultMessage: 'Code Editor',\n }),\n isCopyable = false,\n allowFullScreen = false,\n}", "description": [], "signature": [ "React.PropsWithChildren<", diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index a5f2b8dfd5677..909659dcf4b32 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mocks.mdx b/api_docs/kbn_code_editor_mocks.mdx index e060e72cbadbe..4d1b33ff13923 100644 --- a/api_docs/kbn_code_editor_mocks.mdx +++ b/api_docs/kbn_code_editor_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mocks title: "@kbn/code-editor-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mocks plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mocks'] --- import kbnCodeEditorMocksObj from './kbn_code_editor_mocks.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index ac12509b720ef..2d3190c184aa0 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: 2023-08-31 +date: 2023-09-05 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 7c1aebb5abce3..a044b568a4c6d 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.devdocs.json b/api_docs/kbn_config_mocks.devdocs.json index df37ecf488422..29e17d6500043 100644 --- a/api_docs/kbn_config_mocks.devdocs.json +++ b/api_docs/kbn_config_mocks.devdocs.json @@ -344,7 +344,15 @@ "section": "def-common.ChangedDeprecatedPaths", "text": "ChangedDeprecatedPaths" }, - ">, [], unknown>; } & ", + ">, [], unknown>; addDynamicConfigPaths: jest.MockInstance; setDynamicConfigOverrides: jest.MockInstance], unknown>; } & ", "IConfigService" ], "path": "packages/kbn-config-mocks/src/config_service.mock.ts", diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index 032ae8e192c8b..7dff56ea557ef 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: 2023-08-31 +date: 2023-09-05 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 80559094e37c7..d98cbfcac9f03 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: 2023-08-31 +date: 2023-09-05 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 80646894e11be..571943ac43efc 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index e014004687bea..f840d96fb96a8 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: 2023-08-31 +date: 2023-09-05 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 6911bd6b6f547..80dc326e0b499 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: 2023-08-31 +date: 2023-09-05 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_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index dc335d5b2f612..59ee0aee26e27 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index b92cfb8c94f61..da3749b332c70 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: 2023-08-31 +date: 2023-09-05 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 5b5a59d7fe33f..abf01e9b87809 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: 2023-08-31 +date: 2023-09-05 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 03899ac72f8cd..eeafd6d571c92 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: 2023-08-31 +date: 2023-09-05 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 95b287d79854d..56a4f9835d002 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: 2023-08-31 +date: 2023-09-05 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 4de67f669be7b..d62cfc6e67a36 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: 2023-08-31 +date: 2023-09-05 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 432fa1859b2ed..c734b69e04e11 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: 2023-08-31 +date: 2023-09-05 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 314ad5565f41b..af02ffe0dc431 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: 2023-08-31 +date: 2023-09-05 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 863a037578cdb..0c91163570254 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: 2023-08-31 +date: 2023-09-05 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 326f2c569f43d..2b4ca8a154b87 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: 2023-08-31 +date: 2023-09-05 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 1e489202736d7..839b32626a245 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: 2023-08-31 +date: 2023-09-05 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 2c6795d65ccb0..498d5d98e4a90 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: 2023-08-31 +date: 2023-09-05 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 d29359cd4e1e7..53cde53b4ed52 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: 2023-08-31 +date: 2023-09-05 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 c1c891ba95967..211b46e09eabd 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: 2023-08-31 +date: 2023-09-05 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.devdocs.json b/api_docs/kbn_core_apps_server_internal.devdocs.json index 56bb924457859..db65fdba1b5be 100644 --- a/api_docs/kbn_core_apps_server_internal.devdocs.json +++ b/api_docs/kbn_core_apps_server_internal.devdocs.json @@ -159,7 +159,23 @@ ], "interfaces": [], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "@kbn/core-apps-server-internal", + "id": "def-common.CoreAppConfigType", + "type": "Type", + "tags": [], + "label": "CoreAppConfigType", + "description": [], + "signature": [ + "{ readonly allowDynamicConfigOverrides: boolean; }" + ], + "path": "packages/core/apps/core-apps-server-internal/src/core_app_config.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [] } } \ No newline at end of file diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index bf3f6967f2fae..14b282a273f22 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; @@ -21,10 +21,13 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 8 | 0 | 8 | 1 | +| 9 | 0 | 9 | 1 | ## Common ### Functions +### Consts, variables and types + + diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 0296a7724e765..315c7acf87a17 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: 2023-08-31 +date: 2023-09-05 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 33f58dd0c3db7..9b9547190aa86 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: 2023-08-31 +date: 2023-09-05 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 0afb136cb62c1..99e3e0ed02fa2 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: 2023-08-31 +date: 2023-09-05 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 1754969d7445a..4e1e2c7844df3 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: 2023-08-31 +date: 2023-09-05 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 48d6df951b008..647817f602e86 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: 2023-08-31 +date: 2023-09-05 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 cefeb629c97a6..5a469f8fb6cc0 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: 2023-08-31 +date: 2023-09-05 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 ba7860603a43e..fc98432fd11db 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: 2023-08-31 +date: 2023-09-05 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 0911b94ff466f..707a34374771c 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index fd514328834c6..ebfd9644f1ffa 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: 2023-08-31 +date: 2023-09-05 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 f09f0ac46fc25..86c1b2a59a51c 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: 2023-08-31 +date: 2023-09-05 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 16839802bab6b..941f7eeab85a6 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: 2023-08-31 +date: 2023-09-05 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 d636b64c37886..ec369f63898dd 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: 2023-08-31 +date: 2023-09-05 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 b7c0671187144..e392692c7a0ce 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: 2023-08-31 +date: 2023-09-05 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 b31918997f56f..8871af521c930 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: 2023-08-31 +date: 2023-09-05 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 cd27cf947158d..6b56be8c38b51 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: 2023-08-31 +date: 2023-09-05 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 ea4b52556d5cd..e667a125a4268 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: 2023-08-31 +date: 2023-09-05 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 d1f6d4884d42b..9127767aba5b2 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: 2023-08-31 +date: 2023-09-05 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 caf61d08c5363..8cf713c6da2f1 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: 2023-08-31 +date: 2023-09-05 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 c16097aaeb41b..f1ef685c162ad 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: 2023-08-31 +date: 2023-09-05 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 3075ffb3a73ba..324b3291c428b 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: 2023-08-31 +date: 2023-09-05 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 45340317183d8..bd3bb18d01281 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: 2023-08-31 +date: 2023-09-05 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 d47261b041362..f72e86ef83440 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: 2023-08-31 +date: 2023-09-05 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 cc64203043134..4d968a10b1371 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: 2023-08-31 +date: 2023-09-05 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 8b038d4ec8e98..aadb7ee12c9f5 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: 2023-08-31 +date: 2023-09-05 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 ecb3d8932a4c5..5891024b67a45 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: 2023-08-31 +date: 2023-09-05 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 d7f7cbe6ba47d..f5369679076f2 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: 2023-08-31 +date: 2023-09-05 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 a55d59f4f90d2..a4628267a3b23 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: 2023-08-31 +date: 2023-09-05 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 28f48c684b6e8..af7d968100a5a 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: 2023-08-31 +date: 2023-09-05 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 df8832912ed71..6dffcd5bf011d 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: 2023-08-31 +date: 2023-09-05 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 f0068604005e7..9f3b157a0e7ad 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index 56daa8bc04540..7196d5b59d0b4 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 0f12384bf42ab..dbc1eaec1fb49 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 98bacfc32ff4c..c353870e9bd1c 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: 2023-08-31 +date: 2023-09-05 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 262819d2c0b34..1a5426df061ed 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: 2023-08-31 +date: 2023-09-05 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 48503519ba04f..ea6fd0531228d 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: 2023-08-31 +date: 2023-09-05 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 10fb7bdc62488..bca77c3503b45 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: 2023-08-31 +date: 2023-09-05 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 60a1f0befb409..376f67dce7275 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: 2023-08-31 +date: 2023-09-05 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 b08d9b2f532a6..ea1da3f4749f4 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: 2023-08-31 +date: 2023-09-05 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 83c868bc58036..bf0e09898be90 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: 2023-08-31 +date: 2023-09-05 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 ebefef5e85ec6..5775b5d5f9b73 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: 2023-08-31 +date: 2023-09-05 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 bc56d11afbc7b..9a5c8dc842acb 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: 2023-08-31 +date: 2023-09-05 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 51ff78a19b774..24b454a40a72b 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: 2023-08-31 +date: 2023-09-05 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 99c8dd424f267..2323310976cdf 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: 2023-08-31 +date: 2023-09-05 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 29eb7e26c39c1..efa9880e343cd 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: 2023-08-31 +date: 2023-09-05 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 8a6ba161cbc87..688cb85dc67d1 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: 2023-08-31 +date: 2023-09-05 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 16cad5d8554c0..ed462f0b7103e 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: 2023-08-31 +date: 2023-09-05 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 860003d098949..9c9a2f63eab66 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: 2023-08-31 +date: 2023-09-05 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 2f2fc6f5434cd..f740c651d8dcf 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: 2023-08-31 +date: 2023-09-05 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 0e8b339d206b9..2307f7280d904 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: 2023-08-31 +date: 2023-09-05 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 d93fac3815646..897affe7c09b8 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: 2023-08-31 +date: 2023-09-05 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 b82dc4b068775..d4fdd95134136 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: 2023-08-31 +date: 2023-09-05 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 5ad567d58a5f1..87346e93af629 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: 2023-08-31 +date: 2023-09-05 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 e2865a641f48a..c8dcdc45a54a4 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: 2023-08-31 +date: 2023-09-05 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 8de5d103bde3f..ef1491370a696 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: 2023-08-31 +date: 2023-09-05 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 0d9d25553b9a7..f85ebe7a68529 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: 2023-08-31 +date: 2023-09-05 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 0476ea5bd8173..018b03c72899f 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: 2023-08-31 +date: 2023-09-05 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 8cb9f0a4277e8..646cf9fd1bb02 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -3623,62 +3623,6 @@ "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/routes/get_aad_fields_by_rule_type.ts" }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/find_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_index/find_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/read_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list/read_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/summary_exception_list_route.ts" - }, { "plugin": "savedObjectsTagging", "path": "x-pack/plugins/saved_objects_tagging/server/routes/tags/get_all_tags.ts" @@ -6469,62 +6413,6 @@ "plugin": "ruleRegistry", "path": "x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts" }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/create_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list/create_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/export_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/import_exceptions_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list/import_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts" - }, { "plugin": "savedObjectsTagging", "path": "x-pack/plugins/saved_objects_tagging/server/routes/tags/create_tag.ts" @@ -8543,26 +8431,6 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/update_rule.ts" }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/update_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list/update_list_route.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/security/fleet_router.ts" @@ -9285,14 +9153,6 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/bulk_disable_rules.ts" }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list/patch_list_route.ts" - }, { "plugin": "fleet", "path": "x-pack/plugins/fleet/server/services/security/fleet_router.ts" @@ -9663,30 +9523,6 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/maintenance_window/delete_maintenance_window.ts" }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/delete_exception_list_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts" - }, - { - "plugin": "lists", - "path": "x-pack/plugins/lists/server/routes/list/delete_list_route.ts" - }, { "plugin": "savedObjectsTagging", "path": "x-pack/plugins/saved_objects_tagging/server/routes/tags/delete_tag.ts" @@ -13745,6 +13581,62 @@ "plugin": "data", "path": "src/plugins/data/server/scripts/route.ts" }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/find_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_item/find_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_index/find_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/internal/find_lists_by_size_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/read_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_index/read_list_index_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_item/read_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list/read_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_privileges/read_list_privileges_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/summary_exception_list_route.ts" + }, { "plugin": "telemetry", "path": "src/plugins/telemetry/server/routes/telemetry_config.ts" @@ -14257,10 +14149,6 @@ "plugin": "sessionView", "path": "x-pack/plugins/session_view/server/routes/get_total_io_bytes_route.ts" }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/server/routes/api/privileges.ts" - }, { "plugin": "transform", "path": "x-pack/plugins/transform/server/routes/api/transforms_audit_messages.ts" @@ -14481,6 +14369,10 @@ "deprecated": false, "trackAdoption": true, "references": [ + { + "plugin": "@kbn/core-apps-server-internal", + "path": "packages/core/apps/core-apps-server-internal/src/core_app.ts" + }, { "plugin": "dataViews", "path": "src/plugins/data_views/server/rest_api_routes/public/runtime_fields/put_runtime_field.ts" @@ -14505,6 +14397,26 @@ "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/update_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_item/update_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list/update_list_route.ts" + }, { "plugin": "telemetry", "path": "src/plugins/telemetry/server/routes/telemetry_user_has_seen_notice.ts" @@ -14620,6 +14532,14 @@ { "plugin": "canvas", "path": "x-pack/plugins/canvas/server/routes/workpad/update.test.ts" + }, + { + "plugin": "@kbn/core-apps-server-internal", + "path": "packages/core/apps/core-apps-server-internal/src/core_app.test.ts" + }, + { + "plugin": "@kbn/core-apps-server-internal", + "path": "packages/core/apps/core-apps-server-internal/src/core_app.test.ts" } ], "returnComment": [], @@ -14773,6 +14693,62 @@ "plugin": "unifiedSearch", "path": "src/plugins/unified_search/server/autocomplete/value_suggestions_route.ts" }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/create_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_index/create_list_index_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_item/create_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list/create_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/duplicate_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/export_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_index/export_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/internal/create_exception_filter_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/import_exceptions_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list/import_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/internal/create_exceptions_list_route.ts" + }, { "plugin": "telemetry", "path": "src/plugins/telemetry/server/routes/telemetry_opt_in_stats.ts" @@ -15417,6 +15393,14 @@ "deprecated": false, "trackAdoption": true, "references": [ + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_item/patch_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list/patch_list_route.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts" @@ -15537,6 +15521,30 @@ "plugin": "data", "path": "src/plugins/data/server/query/routes.ts" }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/delete_exception_list_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_index/delete_list_index_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list_item/delete_list_item_route.ts" + }, + { + "plugin": "lists", + "path": "x-pack/plugins/lists/server/routes/list/delete_list_route.ts" + }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/annotations.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 1f93e3e31dae8..d75b9c88f0d8c 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: 2023-08-31 +date: 2023-09-05 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 a25b7c1a45c96..17ec295e2b28a 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: 2023-08-31 +date: 2023-09-05 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 16437f6ff7ab3..af7530ebe2780 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: 2023-08-31 +date: 2023-09-05 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 6d5adb43c3e95..8c8bf1891f9f1 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: 2023-08-31 +date: 2023-09-05 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 e551227387d36..b28afa660b41c 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: 2023-08-31 +date: 2023-09-05 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 c893a0fd60007..e26626cf1aa43 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: 2023-08-31 +date: 2023-09-05 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 ffc9151f43217..1dde8083861cc 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: 2023-08-31 +date: 2023-09-05 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 e60c05adfe04d..4c96d38b98734 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: 2023-08-31 +date: 2023-09-05 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 c3e0bf21e7c64..c95da94e81dd9 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: 2023-08-31 +date: 2023-09-05 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 3e9736316992d..313d1a1cbc7ce 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: 2023-08-31 +date: 2023-09-05 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 ee7dd5bdf90c8..b270138d4cde2 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: 2023-08-31 +date: 2023-09-05 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 62d335e01c3ad..bfad413d0dbae 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: 2023-08-31 +date: 2023-09-05 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 0518e9ee72ea5..a3d274221d1f7 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: 2023-08-31 +date: 2023-09-05 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 fdd8ff8fd822a..b96e16ddd9e4e 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: 2023-08-31 +date: 2023-09-05 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 935901a3e518a..4ea507f43b8d8 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: 2023-08-31 +date: 2023-09-05 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 a8840dd3613b3..e663c9a363275 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: 2023-08-31 +date: 2023-09-05 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 213cedd70d322..c1e5800d3fc35 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: 2023-08-31 +date: 2023-09-05 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 ab94b922fe184..377505265a597 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: 2023-08-31 +date: 2023-09-05 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 36f6e7afb4b59..08e6c40d3b799 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: 2023-08-31 +date: 2023-09-05 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 8fb6369169096..374fd7a4c3600 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: 2023-08-31 +date: 2023-09-05 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 a5eef520ee6ac..789f56c123186 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: 2023-08-31 +date: 2023-09-05 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 aa5c116bc2edc..9ce1103581bb2 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: 2023-08-31 +date: 2023-09-05 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 a3277ae7a65a6..f65dc13cd22a7 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: 2023-08-31 +date: 2023-09-05 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 6cee5807ef013..d9393f985758f 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: 2023-08-31 +date: 2023-09-05 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 a8ea1a47da543..2a7dcbd5d1af9 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: 2023-08-31 +date: 2023-09-05 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 bb4195a8fe37b..8701f13ca30dc 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: 2023-08-31 +date: 2023-09-05 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 88bae9bd3ea60..8d37a662156d1 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: 2023-08-31 +date: 2023-09-05 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 aadcf67bae283..4cc7d28317be7 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: 2023-08-31 +date: 2023-09-05 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 e0c4fda40518a..48905d30f9cfe 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: 2023-08-31 +date: 2023-09-05 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 1331d04ffc85c..afca185707beb 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: 2023-08-31 +date: 2023-09-05 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 63a4ae4dac5ef..f6a66c5963efc 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: 2023-08-31 +date: 2023-09-05 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 fff8c97f6e654..147187be6169d 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: 2023-08-31 +date: 2023-09-05 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 ca261ae0ea913..831b0fa16040c 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: 2023-08-31 +date: 2023-09-05 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 d636320c8f81c..13f3e351a4e1b 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: 2023-08-31 +date: 2023-09-05 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 9c07d5c90c07d..cee4243d41ec9 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: 2023-08-31 +date: 2023-09-05 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 5097c74135732..d0e79df85e348 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: 2023-08-31 +date: 2023-09-05 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 1ab1150ff7861..0efde46e225c8 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: 2023-08-31 +date: 2023-09-05 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_server.devdocs.json b/api_docs/kbn_core_plugins_server.devdocs.json index 98b1596549758..1d895c5714572 100644 --- a/api_docs/kbn_core_plugins_server.devdocs.json +++ b/api_docs/kbn_core_plugins_server.devdocs.json @@ -436,6 +436,29 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-common.PluginConfigDescriptor.dynamicConfig", + "type": "Object", + "tags": [], + "label": "dynamicConfig", + "description": [ + "\nList of configuration properties that can be dynamically changed via the PUT /_settings API." + ], + "signature": [ + { + "pluginId": "@kbn/core-plugins-server", + "scope": "common", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-common.DynamicConfigDescriptor", + "text": "DynamicConfigDescriptor" + }, + " | undefined" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-plugins-server", "id": "def-common.PluginConfigDescriptor.schema", @@ -1050,6 +1073,31 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/core-plugins-server", + "id": "def-common.DynamicConfigDescriptor", + "type": "Type", + "tags": [], + "label": "DynamicConfigDescriptor", + "description": [ + "\nType defining the list of configuration properties that can be dynamically updated\nObject properties can either be fully exposed or narrowed down to specific keys.\n" + ], + "signature": [ + "{ [Key in keyof T]?: (T[Key] extends Maybe ? boolean : T[Key] extends Maybe ? boolean | ", + { + "pluginId": "@kbn/core-plugins-server", + "scope": "common", + "docId": "kibKbnCorePluginsServerPluginApi", + "section": "def-common.DynamicConfigDescriptor", + "text": "DynamicConfigDescriptor" + }, + " : boolean) | undefined; }" + ], + "path": "packages/core/plugins/core-plugins-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-plugins-server", "id": "def-common.ExposedToBrowserDescriptor", @@ -1057,7 +1105,7 @@ "tags": [], "label": "ExposedToBrowserDescriptor", "description": [ - "\nType defining the list of configuration properties that will be exposed on the client-side\nObject properties can either be fully exposed\n" + "\nType defining the list of configuration properties that will be exposed on the client-side\nObject properties can either be fully exposed or narrowed down to specific keys.\n" ], "signature": [ "{ [Key in keyof T]?: (T[Key] extends Maybe ? boolean : T[Key] extends Maybe ? boolean | ", diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index ac0c38450ebcb..b9b84c8887fc5 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 58 | 0 | 26 | 0 | +| 60 | 0 | 26 | 0 | ## Common diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index bc5b5c82f43a1..7a04d07f67c12 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: 2023-08-31 +date: 2023-09-05 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 172452e6bc966..8b8849d1e1a78 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: 2023-08-31 +date: 2023-09-05 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 d808516ce314b..bde0ba3320d89 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: 2023-08-31 +date: 2023-09-05 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 f8eff817f64b9..c5f0137d455e2 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: 2023-08-31 +date: 2023-09-05 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 8bbe2bc8dfb49..b09d5759718c2 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: 2023-08-31 +date: 2023-09-05 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 53b3a6fc40e71..71ec48a5a4eb3 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: 2023-08-31 +date: 2023-09-05 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 85ebcb415549a..985a16b0261ea 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: 2023-08-31 +date: 2023-09-05 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 414f01e0491a0..c3e93e7242086 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: 2023-08-31 +date: 2023-09-05 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.devdocs.json b/api_docs/kbn_core_saved_objects_api_server.devdocs.json index e529c9e80e178..89f29c9e91e81 100644 --- a/api_docs/kbn_core_saved_objects_api_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_server.devdocs.json @@ -7942,7 +7942,7 @@ "tags": [], "label": "version", "description": [ - "\nAn opaque version number which changes on each successful write operation.\nCan be used for implementing optimistic concurrency control." + "\nAn opaque version number which changes on each successful write operation.\nCan be used for implementing optimistic concurrency control.\nUnused for multi-namespace objects" ], "signature": [ "string | undefined" @@ -8028,6 +8028,22 @@ "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/update.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-api-server", + "id": "def-common.SavedObjectsUpdateOptions.migrationVersionCompatibility", + "type": "CompoundType", + "tags": [], + "label": "migrationVersionCompatibility", + "description": [ + "{@link SavedObjectsRawDocParseOptions.migrationVersionCompatibility}" + ], + "signature": [ + "\"raw\" | \"compatible\" | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/update.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 8a62fdb8fbc93..5389c790c3889 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 351 | 1 | 5 | 1 | +| 352 | 1 | 5 | 1 | ## Common 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 1d7e23551fac5..24d6094fecad2 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: 2023-08-31 +date: 2023-09-05 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 56c7cc8f46ee4..3348a66f9503c 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: 2023-08-31 +date: 2023-09-05 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 62f4f84327978..00ec9085ed5b0 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: 2023-08-31 +date: 2023-09-05 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 4d11b87d5750b..46cca04b8c670 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: 2023-08-31 +date: 2023-09-05 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 b280e87a2762a..15a10088397da 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: 2023-08-31 +date: 2023-09-05 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 095d809abc97b..f11d1ea3fd27b 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: 2023-08-31 +date: 2023-09-05 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 5691658f02493..b38bf406d436f 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: 2023-08-31 +date: 2023-09-05 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 25e6e89e0a395..dcc9f8b8c8e94 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: 2023-08-31 +date: 2023-09-05 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 67ca7bc41f1af..d87aa7fa00c18 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index c8425be055fba..0243585e35df1 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: 2023-08-31 +date: 2023-09-05 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 fc4b8aeb807ff..089cd4f11e138 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: 2023-08-31 +date: 2023-09-05 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 097e6c4edbe8c..1853a66e3f1b5 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -8647,7 +8647,9 @@ "type": "Interface", "tags": [], "label": "SavedObjectsRawDocSource", - "description": [], + "description": [ + "\nSaved object document as stored in `_source` of doc in ES index\nSimilar to SavedObjectDoc and excludes `version`, includes `references`, has `attributes` in [typeMapping]\n" + ], "path": "packages/core/saved-objects/core-saved-objects-server/src/serialization.ts", "deprecated": false, "trackAdoption": false, @@ -9619,52 +9621,6 @@ "trackAdoption": false, "children": [], "returnComment": [] - }, - { - "parentPluginId": "@kbn/core-saved-objects-server", - "id": "def-common.SavedObjectsServiceSetup.getAllIndices", - "type": "Function", - "tags": [ - "deprecated" - ], - "label": "getAllIndices", - "description": [ - "\nReturns all (aliases to) kibana system indices used for saved object storage.\n" - ], - "signature": [ - "() => string[]" - ], - "path": "packages/core/saved-objects/core-saved-objects-server/src/contracts.ts", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "@kbn/core-saved-objects-server-internal", - "path": "packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts" - }, - { - "plugin": "@kbn/core-plugins-server-internal", - "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" - }, - { - "plugin": "@kbn/core-plugins-server-internal", - "path": "packages/core/plugins/core-plugins-server-internal/src/plugin_context.ts" - }, - { - "plugin": "savedObjectsTagging", - "path": "x-pack/plugins/saved_objects_tagging/server/plugin.ts" - }, - { - "plugin": "@kbn/core-saved-objects-server-mocks", - "path": "packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts" - }, - { - "plugin": "@kbn/core-saved-objects-server-mocks", - "path": "packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts" - } - ], - "children": [], - "returnComment": [] } ], "initialIsOpen": false @@ -10225,7 +10181,7 @@ "tags": [], "label": "getAllIndices", "description": [ - "\nReturns all (aliases to) kibana system indices used for saved object storage." + "\nReturns all (aliases to) kibana system indices used for saved object storage.\n" ], "signature": [ "() => string[]" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 1f7ba67f59898..0d93a2c9924c8 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 548 | 1 | 122 | 4 | +| 547 | 1 | 121 | 4 | ## Common diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index 7c94b1cb500fd..038594c4e6f50 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: 2023-08-31 +date: 2023-09-05 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 e05f09dc2e643..8de8c4fc312c4 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: 2023-08-31 +date: 2023-09-05 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 c807548374956..14872988849f1 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: 2023-08-31 +date: 2023-09-05 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_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 3f321655d78ec..0707f752b2a6c 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: 2023-08-31 +date: 2023-09-05 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 85fb62b5d20bc..35c63747efecb 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: 2023-08-31 +date: 2023-09-05 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 d3f87243ac1e2..b13279c38b32f 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: 2023-08-31 +date: 2023-09-05 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 e6f162205f20b..5740bf4cbada0 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: 2023-08-31 +date: 2023-09-05 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 640536d4e1bdc..3126e14f0581c 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: 2023-08-31 +date: 2023-09-05 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 87375b22b27b1..d2910acd94f73 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: 2023-08-31 +date: 2023-09-05 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 f0c020fcef23e..caca10c2fd48f 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: 2023-08-31 +date: 2023-09-05 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 62838b929c0cf..96d43fb283968 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: 2023-08-31 +date: 2023-09-05 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_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 432fac261568c..52d1fb852d224 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: 2023-08-31 +date: 2023-09-05 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 44fb03be51546..e256f3ba6d69e 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: 2023-08-31 +date: 2023-09-05 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 e7296a9cfbdc0..c883b482a9c69 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: 2023-08-31 +date: 2023-09-05 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 0be7fa9f6b433..513db41d2f316 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: 2023-08-31 +date: 2023-09-05 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 63d91c0a9cefb..38cfbeb018997 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: 2023-08-31 +date: 2023-09-05 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 5e7a69d5b3157..cfe6994c0bbf7 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: 2023-08-31 +date: 2023-09-05 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 a82e7e55774bb..0bacde75c8ed3 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: 2023-08-31 +date: 2023-09-05 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 ae6d41edcb787..f1671013301da 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: 2023-08-31 +date: 2023-09-05 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 2bf42e5f20f34..3f0b161976b96 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: 2023-08-31 +date: 2023-09-05 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 f52ad36f695c3..696ae1d316070 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: 2023-08-31 +date: 2023-09-05 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 66d93cfe8bbac..6461a930f9926 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: 2023-08-31 +date: 2023-09-05 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 14314e238f71c..11e95f64326de 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: 2023-08-31 +date: 2023-09-05 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 c9d5341b8d164..2fff03abb2438 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: 2023-08-31 +date: 2023-09-05 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 cd78ab0cb7938..3d8450614de08 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: 2023-08-31 +date: 2023-09-05 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_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index 77eeffed9f266..8a4e30bc7f65e 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: 2023-08-31 +date: 2023-09-05 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_internal.mdx b/api_docs/kbn_core_user_settings_server_internal.mdx index 41dcf57269f9c..bbc16de105137 100644 --- a/api_docs/kbn_core_user_settings_server_internal.mdx +++ b/api_docs/kbn_core_user_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-internal title: "@kbn/core-user-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-internal plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-internal'] --- import kbnCoreUserSettingsServerInternalObj from './kbn_core_user_settings_server_internal.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 8d28e4363c3ac..f2235fdee4dee 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: 2023-08-31 +date: 2023-09-05 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 99e823bd22274..c14fe4df54dc4 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: 2023-08-31 +date: 2023-09-05 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 ce70608a81a63..cd44c94dbb706 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 05220f2cc867e..1244ed0c0da4c 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 6a68a438d2845..76ecfb8d270ca 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 78b0ec7217583..8a115eeed4cf6 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: 2023-08-31 +date: 2023-09-05 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 ec7e1cdc184d3..bda8d0b6b8ab1 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: 2023-08-31 +date: 2023-09-05 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 88d315d9dc031..023e5b73ca23d 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 1982a451203bf..247745c07f508 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: 2023-08-31 +date: 2023-09-05 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 9ce72754e73e3..bb3308665a207 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: 2023-08-31 +date: 2023-09-05 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 dbcbc0da8d191..8754a1ec6e042 100644 --- a/api_docs/kbn_deeplinks_observability.devdocs.json +++ b/api_docs/kbn_deeplinks_observability.devdocs.json @@ -30,7 +30,7 @@ "label": "AppId", "description": [], "signature": [ - "\"metrics\" | \"apm\" | \"logs\" | \"observability-overview\" | \"observabilityOnboarding\"" + "\"metrics\" | \"apm\" | \"logs\" | \"observability-overview\" | \"observabilityOnboarding\" | \"observability-log-explorer\"" ], "path": "packages/deeplinks/observability/deep_links.ts", "deprecated": false, @@ -52,7 +52,7 @@ "section": "def-common.AppId", "text": "AppId" }, - " | \"discover:log-explorer\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:rules\" | \"observability-overview:alerts\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"observability-overview:slos\" | \"metrics:settings\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:metrics-hosts\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:services\" | \"apm:service-groups-list\" | \"apm:storage-explorer\"" + " | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:rules\" | \"observability-overview:alerts\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"observability-overview:slos\" | \"metrics:settings\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:metrics-hosts\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:services\" | \"apm:service-groups-list\" | \"apm:storage-explorer\"" ], "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 1ddc62ebfbc15..315988ced942c 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: 2023-08-31 +date: 2023-09-05 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 3c8263637c076..8777eb2ca54ef 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 55350a41e1323..387d6797cd5a5 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: 2023-08-31 +date: 2023-09-05 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 bd59fed1ed260..efaffaf33ca7c 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: 2023-08-31 +date: 2023-09-05 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 6b869dd3da889..ef7beaef0f6a9 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: 2023-08-31 +date: 2023-09-05 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 28b48b2ad2ef5..763e602b18868 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: 2023-08-31 +date: 2023-09-05 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 f1853a8bdcf51..918307a7aea1f 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: 2023-08-31 +date: 2023-09-05 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 ae1a85ad39b38..8889c66a849e1 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: 2023-08-31 +date: 2023-09-05 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 02b226853401b..787be9b13f6ff 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: 2023-08-31 +date: 2023-09-05 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 fa9d670cd0529..d0134b6dd43c5 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.devdocs.json b/api_docs/kbn_discover_utils.devdocs.json index 6ae82d7acfccd..74196fab61cdd 100644 --- a/api_docs/kbn_discover_utils.devdocs.json +++ b/api_docs/kbn_discover_utils.devdocs.json @@ -587,6 +587,41 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.getFieldTypeName", + "type": "Function", + "tags": [], + "label": "getFieldTypeName", + "description": [ + "\nReturns a user-friendly name of a field type" + ], + "signature": [ + "(type: string | undefined) => string" + ], + "path": "packages/kbn-discover-utils/src/utils/get_field_type_name.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.getFieldTypeName.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-discover-utils/src/utils/get_field_type_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.getIgnoredReason", @@ -744,6 +779,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.isKnownFieldType", + "type": "Function", + "tags": [], + "label": "isKnownFieldType", + "description": [], + "signature": [ + "(type?: string | undefined) => type is string" + ], + "path": "packages/kbn-discover-utils/src/utils/field_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.isKnownFieldType.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-discover-utils/src/utils/field_types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.isNestedFieldParent", @@ -875,6 +943,20 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.KNOWN_FIELD_TYPES", + "type": "Enum", + "tags": [], + "label": "KNOWN_FIELD_TYPES", + "description": [ + "\nField types for which name and description are defined" + ], + "path": "packages/kbn-discover-utils/src/utils/field_types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "misc": [ @@ -970,13 +1052,13 @@ }, { "parentPluginId": "@kbn/discover-utils", - "id": "def-common.ENABLE_SQL", + "id": "def-common.ENABLE_ESQL", "type": "string", "tags": [], - "label": "ENABLE_SQL", + "label": "ENABLE_ESQL", "description": [], "signature": [ - "\"discover:enableSql\"" + "\"discover:enableESQL\"" ], "path": "packages/kbn-discover-utils/src/constants.ts", "deprecated": false, @@ -1013,6 +1095,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/discover-utils", + "id": "def-common.KNOWN_FIELD_TYPE_LIST", + "type": "Array", + "tags": [], + "label": "KNOWN_FIELD_TYPE_LIST", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-discover-utils/src/utils/field_types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/discover-utils", "id": "def-common.MAX_DOC_FIELDS_DISPLAYED", diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 79024d0ecffc2..1ee3655894d70 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 59 | 0 | 34 | 3 | +| 65 | 0 | 38 | 3 | ## Common diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index 5dd70d02389dd..724a581015e7e 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -644,7 +644,7 @@ "label": "apis", "description": [], "signature": [ - "{ readonly bulkIndexAlias: string; readonly byteSizeUnits: string; readonly createAutoFollowPattern: string; readonly createFollower: string; readonly createIndex: string; readonly createSnapshotLifecyclePolicy: string; readonly createRoleMapping: string; readonly createRoleMappingTemplates: string; readonly createRollupJobsRequest: string; readonly createApiKey: string; readonly createPipeline: string; readonly createTransformRequest: string; readonly cronExpressions: string; readonly executeWatchActionModes: string; readonly indexExists: string; readonly multiSearch: string; readonly openIndex: string; readonly putComponentTemplate: string; readonly painlessExecute: string; readonly painlessExecuteAPIContexts: string; readonly putComponentTemplateMetadata: string; readonly putSnapshotLifecyclePolicy: string; readonly putIndexTemplateV1: string; readonly putWatch: string; readonly restApis: string; readonly searchPreference: string; readonly securityApis: string; readonly simulatePipeline: string; readonly timeUnits: string; readonly unfreezeIndex: string; readonly updateTransform: string; }" + "{ readonly bulkIndexAlias: string; readonly indexStats: string; readonly byteSizeUnits: string; readonly createAutoFollowPattern: string; readonly createFollower: string; readonly createIndex: string; readonly createSnapshotLifecyclePolicy: string; readonly createRoleMapping: string; readonly createRoleMappingTemplates: string; readonly createRollupJobsRequest: string; readonly createApiKey: string; readonly createPipeline: string; readonly createTransformRequest: string; readonly cronExpressions: string; readonly executeWatchActionModes: string; readonly indexExists: string; readonly multiSearch: string; readonly openIndex: string; readonly putComponentTemplate: string; readonly painlessExecute: string; readonly painlessExecuteAPIContexts: string; readonly putComponentTemplateMetadata: string; readonly putSnapshotLifecyclePolicy: string; readonly putIndexTemplateV1: string; readonly putWatch: string; readonly restApis: string; readonly searchPreference: string; readonly securityApis: string; readonly simulatePipeline: string; readonly timeUnits: string; readonly unfreezeIndex: string; readonly updateTransform: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 007fdabcfd5fa..32a41d70a9325 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: 2023-08-31 +date: 2023-09-05 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 f5b27c737b5a5..a276ef5f584e8 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: 2023-08-31 +date: 2023-09-05 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 e36c2b0e45a3a..bd3a9ef6ceb82 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: 2023-08-31 +date: 2023-09-05 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 65397b4d289ca..ae8ce838528bd 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index 40103298d2de8..31679eb5a4ee6 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index 8b0178fe32bd9..6af12ec235d93 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: 2023-08-31 +date: 2023-09-05 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_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index ef07d0a947ef6..057d553c9c272 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 42ff9a3b20562..2626b9b5e3793 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.devdocs.json b/api_docs/kbn_es_archiver.devdocs.json index 65257a15f067a..61d819e2b15f9 100644 --- a/api_docs/kbn_es_archiver.devdocs.json +++ b/api_docs/kbn_es_archiver.devdocs.json @@ -439,7 +439,7 @@ "tags": [], "label": "emptyKibanaIndex", "description": [ - "\nDelete any Kibana indices, and initialize the Kibana index as Kibana would do\non startup." + "\nCleanup saved object indices, preserving the space:default saved object." ], "signature": [ "() => Promise never" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2592,7 +2592,7 @@ "text": "AggregateQuery" } ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -2683,6 +2683,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getIndexPatternFromESQLQuery", + "type": "Function", + "tags": [], + "label": "getIndexPatternFromESQLQuery", + "description": [], + "signature": [ + "(esql: string | undefined) => string" + ], + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getIndexPatternFromESQLQuery.$1", + "type": "string", + "tags": [], + "label": "esql", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.getIndexPatternFromSQLQuery", @@ -2693,7 +2726,7 @@ "signature": [ "(sqlQuery: string | undefined) => string" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -2707,7 +2740,7 @@ "signature": [ "string | undefined" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "isRequired": false @@ -2716,6 +2749,39 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getLanguageDisplayName", + "type": "Function", + "tags": [], + "label": "getLanguageDisplayName", + "description": [], + "signature": [ + "(language: string) => string" + ], + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.getLanguageDisplayName.$1", + "type": "string", + "tags": [], + "label": "language", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.isCombinedFilter", @@ -3152,7 +3218,7 @@ }, " | { [key: string]: any; }) => boolean" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -3181,7 +3247,7 @@ }, " | { [key: string]: any; }" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -3216,7 +3282,7 @@ }, " | undefined) => boolean" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -3245,7 +3311,7 @@ }, " | undefined" ], - "path": "packages/kbn-es-query/src/es_query/es_query_sql.ts", + "path": "packages/kbn-es-query/src/es_query/es_aggregate_query.ts", "deprecated": false, "trackAdoption": false, "isRequired": false diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 1f326e8a9da21..34abd1a51f0fd 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 255 | 1 | 195 | 15 | +| 259 | 1 | 199 | 15 | ## Common diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 85bea4b3bf4a9..ca7517756e605 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: 2023-08-31 +date: 2023-09-05 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 0e4f605a555fd..7899f9650cd30 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 36da66848d651..fdd6e0c7f3fc3 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: 2023-08-31 +date: 2023-09-05 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 ac5fecbc330f8..fc83a934bf7e1 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: 2023-08-31 +date: 2023-09-05 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 5925a7c86030f..0788687a910fe 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: 2023-08-31 +date: 2023-09-05 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 8715c09f3030d..8af6fb11bde12 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 77685c076a27c..c99be713b8d90 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: 2023-08-31 +date: 2023-09-05 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_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index c18507ab036e4..b911c6e1e1952 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: 2023-08-31 +date: 2023-09-05 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_generate.mdx b/api_docs/kbn_generate.mdx index dcb0610551cad..b5bda95c806cb 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: 2023-08-31 +date: 2023-09-05 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 6cab2a17b1eb7..e3d7321f12ea1 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: 2023-08-31 +date: 2023-09-05 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 a2ca8d6fea0ef..65b0ac1dd0ecd 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_generate_csv_types.mdx b/api_docs/kbn_generate_csv_types.mdx index 3c096a07c337d..a68e429f6013e 100644 --- a/api_docs/kbn_generate_csv_types.mdx +++ b/api_docs/kbn_generate_csv_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv-types title: "@kbn/generate-csv-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv-types plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv-types'] --- import kbnGenerateCsvTypesObj from './kbn_generate_csv_types.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index fe27879215b6e..df6dcbf68a99c 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: 2023-08-31 +date: 2023-09-05 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 6cfb08ebfb7d4..7fe9a26ba9dd7 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: 2023-08-31 +date: 2023-09-05 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 9b2c6d475600d..f64d1c6af5206 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: 2023-08-31 +date: 2023-09-05 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 8f7289bf003ff..8676c7107d4dd 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: 2023-08-31 +date: 2023-09-05 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 adb7115e75c4c..a0f2a90b37a14 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: 2023-08-31 +date: 2023-09-05 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 bde6ed48305c2..8024bad81452e 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: 2023-08-31 +date: 2023-09-05 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 530c0c4e3b47a..79f69a5cc71a0 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: 2023-08-31 +date: 2023-09-05 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 ec5bc472f9892..cc4337a22a137 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: 2023-08-31 +date: 2023-09-05 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 592304aabd880..81ae937e1aabc 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 2dc027e61305d..903ff74457bd2 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: 2023-08-31 +date: 2023-09-05 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 76fc39b19ce4c..2d1f2dd1b4f3e 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 354775f584bb9..d3f8fb3e152da 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 6cf49dafb657e..3b5fe7bcd0bb7 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: 2023-08-31 +date: 2023-09-05 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 389f0677f32c7..eea14a63ba6ba 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: 2023-08-31 +date: 2023-09-05 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 5545d13c4d266..5c11668ffa71e 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index fec54f8ec0558..f4b3cbee7bc65 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: 2023-08-31 +date: 2023-09-05 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 3272017185207..277d89eeb2666 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: 2023-08-31 +date: 2023-09-05 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 d8c72b3999eac..3121954ab3512 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 3e2db0a4fb049..6d1e806fffcf2 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: 2023-08-31 +date: 2023-09-05 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 14cd96df85166..ffb235143b227 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 70c9874174eef..6dac7d9151945 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: 2023-08-31 +date: 2023-09-05 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 2027a09d74372..c13b36d6a01b5 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: 2023-08-31 +date: 2023-09-05 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_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index 513f1eb0dfe90..0643d300555bb 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: 2023-08-31 +date: 2023-09-05 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_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 2fdbcde76e91d..8bcf6ef9da913 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: 2023-08-31 +date: 2023-09-05 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 77126dd798ccf..268c13ee40c21 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: 2023-08-31 +date: 2023-09-05 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 a60c1a10cbc50..cda3b46c2c802 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 94dd7e499a226..d4c39692829a9 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: 2023-08-31 +date: 2023-09-05 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 e018ab763ea4c..edb82b7d856a9 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: 2023-08-31 +date: 2023-09-05 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_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index 80228426e7c87..9ee3a48b1ed90 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: 2023-08-31 +date: 2023-09-05 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_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index adb8f5ac9f634..d4fcdeafed66b 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: 2023-08-31 +date: 2023-09-05 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 ada1ea99901d6..8e0369f66c66b 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 40bf1da8636a4..0a44b471adea8 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: 2023-08-31 +date: 2023-09-05 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 c69c9f5d1165a..1a8bff8e80c51 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: 2023-08-31 +date: 2023-09-05 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 dca38829d1f8a..f376e5de94cbd 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: 2023-08-31 +date: 2023-09-05 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 a0df930cf267e..5a614d4f7e906 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: 2023-08-31 +date: 2023-09-05 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 9f484184a1ee6..cc1cd6b7c29c3 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: 2023-08-31 +date: 2023-09-05 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 b0878df182bb8..88af0e128fe6d 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: 2023-08-31 +date: 2023-09-05 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 7bca4caf14b01..5004023259bfa 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: 2023-08-31 +date: 2023-09-05 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 43ad3a96481c4..8ab31c0810681 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: 2023-08-31 +date: 2023-09-05 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 4ba43a3a50a33..de7246615f050 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: 2023-08-31 +date: 2023-09-05 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 47221104da4b7..300345dc19e9f 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: 2023-08-31 +date: 2023-09-05 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 b7479a7488984..65e39c56c54cf 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: 2023-08-31 +date: 2023-09-05 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 550fda3a86c3e..5989125209f3c 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: 2023-08-31 +date: 2023-09-05 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 59a9fd5e0be72..8c2fe6d0f842b 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: 2023-08-31 +date: 2023-09-05 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 22275a6390f02..b87966a18bcc8 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: 2023-08-31 +date: 2023-09-05 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 61d20853caa8b..54cb3c3ed4458 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: 2023-08-31 +date: 2023-09-05 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_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 0b2874d805878..032e218c58780 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: 2023-08-31 +date: 2023-09-05 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_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index dbbfa6b0fab39..7aed7a647acd3 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_monaco.devdocs.json b/api_docs/kbn_monaco.devdocs.json index 364fa6046fc99..a02324fc33509 100644 --- a/api_docs/kbn_monaco.devdocs.json +++ b/api_docs/kbn_monaco.devdocs.json @@ -373,7 +373,7 @@ "label": "getSourceIdentifiers", "description": [], "signature": [ - "CallbackFn | undefined" + "CallbackFn | undefined" ], "path": "packages/kbn-monaco/src/esql/lib/autocomplete/types.ts", "deprecated": false, @@ -387,7 +387,49 @@ "label": "getFieldsIdentifiers", "description": [], "signature": [ - "CallbackFn | undefined" + "CallbackFn | undefined" + ], + "path": "packages/kbn-monaco/src/esql/lib/autocomplete/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.ESQLCustomAutocompleteCallbacks.getPoliciesIdentifiers", + "type": "Function", + "tags": [], + "label": "getPoliciesIdentifiers", + "description": [], + "signature": [ + "CallbackFn<{ name: string; indices: string[]; }> | undefined" + ], + "path": "packages/kbn-monaco/src/esql/lib/autocomplete/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.ESQLCustomAutocompleteCallbacks.getPolicyFieldsIdentifiers", + "type": "Function", + "tags": [], + "label": "getPolicyFieldsIdentifiers", + "description": [], + "signature": [ + "CallbackFn | undefined" + ], + "path": "packages/kbn-monaco/src/esql/lib/autocomplete/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/monaco", + "id": "def-common.ESQLCustomAutocompleteCallbacks.getPolicyMatchingFieldIdentifiers", + "type": "Function", + "tags": [], + "label": "getPolicyMatchingFieldIdentifiers", + "description": [], + "signature": [ + "CallbackFn | undefined" ], "path": "packages/kbn-monaco/src/esql/lib/autocomplete/types.ts", "deprecated": false, diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index c23d7b80c4e0a..e1d4a47d80bc5 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 71 | 0 | 69 | 3 | +| 74 | 0 | 72 | 3 | ## Common diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index bda7ee374437f..7e85861952f55 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: 2023-08-31 +date: 2023-09-05 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 aef43868ae482..3fb6a56259ba7 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 5da9555bbfcae..ab04f163b40df 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: 2023-08-31 +date: 2023-09-05 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 6e06115ceebe4..b3d04d8b790ae 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: 2023-08-31 +date: 2023-09-05 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 1fa274bc6daa0..5680da729406a 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: 2023-08-31 +date: 2023-09-05 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_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 9041966720191..6e12225151607 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: 2023-08-31 +date: 2023-09-05 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_generator.mdx b/api_docs/kbn_plugin_generator.mdx index bda21ef6f5423..0c622fb705406 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: 2023-08-31 +date: 2023-09-05 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 44413e84c712c..149efa170d300 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 634f2b2aab539..70d41bb5964de 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: 2023-08-31 +date: 2023-09-05 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 d552adba2ac5c..037d30c889f87 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 89e0b6f0caa65..58fbeeee2d187 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: 2023-08-31 +date: 2023-09-05 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 7e323d2cd4cd5..959e2a057f24c 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: 2023-08-31 +date: 2023-09-05 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 dacc15f4d5b10..7613d4be794d4 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: 2023-08-31 +date: 2023-09-05 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 baa6ce77ac522..0323e7ebc62b4 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: 2023-08-31 +date: 2023-09-05 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 6d28c1ee43eb1..cf70a70947460 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: 2023-08-31 +date: 2023-09-05 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 539bf7cc83c85..d04209a9f3568 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 383bdc0e2d5ec..c2e009a4b77fb 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: 2023-08-31 +date: 2023-09-05 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 c13ce02fa0421..31eb94cd3909e 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: 2023-08-31 +date: 2023-09-05 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 a6728dbd76035..0ea939bbde996 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: 2023-08-31 +date: 2023-09-05 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 6a0df88f9db3c..bd5a2b4bf7477 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: 2023-08-31 +date: 2023-09-05 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 4ce4e32d33757..ece34b24df02d 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index 2414241553b57..dcec40e3a89da 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index 366ed43c51a25..ef9900034a6d5 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: 2023-08-31 +date: 2023-09-05 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 8d5de8947312f..0393965e2ebb2 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: 2023-08-31 +date: 2023-09-05 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 6eb32ab8e700d..3605f1aba2368 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index f791b92030167..23d87424f2b07 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: 2023-08-31 +date: 2023-09-05 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_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 531afa21b44de..a7f3a7c301a2f 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.devdocs.json b/api_docs/kbn_security_solution_features.devdocs.json new file mode 100644 index 0000000000000..efeb01d3237a1 --- /dev/null +++ b/api_docs/kbn_security_solution_features.devdocs.json @@ -0,0 +1,487 @@ +{ + "id": "@kbn/security-solution-features", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureParams", + "type": "Interface", + "tags": [], + "label": "AppFeatureParams", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureParams", + "text": "AppFeatureParams" + }, + "" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureParams.baseKibanaFeature", + "type": "Object", + "tags": [], + "label": "baseKibanaFeature", + "description": [], + "signature": [ + "{ id: string; order?: number | undefined; name: string; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; description?: string | undefined; category: ", + { + "pluginId": "@kbn/core-application-common", + "scope": "common", + "docId": "kibKbnCoreApplicationCommonPluginApi", + "section": "def-common.AppCategory", + "text": "AppCategory" + }, + "; management?: { [sectionId: string]: readonly string[]; } | undefined; privileges: { all: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.FeatureKibanaPrivileges", + "text": "FeatureKibanaPrivileges" + }, + "; read: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.FeatureKibanaPrivileges", + "text": "FeatureKibanaPrivileges" + }, + "; } | null; catalogue?: readonly string[] | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; privilegesTooltip?: string | undefined; reserved?: { description: string; privileges: readonly ", + "ReservedKibanaPrivilege", + "[]; } | undefined; }" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureParams.baseKibanaSubFeatureIds", + "type": "Array", + "tags": [], + "label": "baseKibanaSubFeatureIds", + "description": [], + "signature": [ + "T[]" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureParams.subFeaturesMap", + "type": "Object", + "tags": [], + "label": "subFeaturesMap", + "description": [], + "signature": [ + "Map" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureKeys", + "type": "Type", + "tags": [], + "label": "AppFeatureKeys", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureKeyType", + "text": "AppFeatureKeyType" + }, + "[]" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureKeyType", + "type": "Type", + "tags": [], + "label": "AppFeatureKeyType", + "description": [], + "signature": [ + "AppFeatureSecurityKey", + " | ", + "AppFeatureCasesKey", + " | ", + "AppFeatureAssistantKey" + ], + "path": "x-pack/packages/security-solution/features/src/app_features_keys.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeatureKibanaConfig", + "type": "Type", + "tags": [], + "label": "AppFeatureKibanaConfig", + "description": [], + "signature": [ + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<", + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.BaseKibanaFeatureConfig", + "text": "BaseKibanaFeatureConfig" + }, + "> & { subFeatureIds?: T[] | undefined; subFeaturesPrivileges?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.SubFeaturePrivilegeConfig", + "text": "SubFeaturePrivilegeConfig" + }, + ">[] | undefined; }" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeaturesAssistantConfig", + "type": "Type", + "tags": [], + "label": "AppFeaturesAssistantConfig", + "description": [], + "signature": [ + "Map<", + "AppFeatureAssistantKey", + ", ", + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureKibanaConfig", + "text": "AppFeatureKibanaConfig" + }, + "<", + "AssistantSubFeatureId", + ">>" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeaturesCasesConfig", + "type": "Type", + "tags": [], + "label": "AppFeaturesCasesConfig", + "description": [], + "signature": [ + "Map<", + "AppFeatureCasesKey", + ", ", + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureKibanaConfig", + "text": "AppFeatureKibanaConfig" + }, + "<", + "CasesSubFeatureId", + ">>" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeaturesConfig", + "type": "Type", + "tags": [], + "label": "AppFeaturesConfig", + "description": [], + "signature": [ + "Map<", + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureKeyType", + "text": "AppFeatureKeyType" + }, + ", ", + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureKibanaConfig", + "text": "AppFeatureKibanaConfig" + }, + ">" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppFeaturesSecurityConfig", + "type": "Type", + "tags": [], + "label": "AppFeaturesSecurityConfig", + "description": [], + "signature": [ + "Map<", + "AppFeatureSecurityKey", + ", ", + { + "pluginId": "@kbn/security-solution-features", + "scope": "common", + "docId": "kibKbnSecuritySolutionFeaturesPluginApi", + "section": "def-common.AppFeatureKibanaConfig", + "text": "AppFeatureKibanaConfig" + }, + "<", + "SecuritySubFeatureId", + ">>" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.AppSubFeaturesMap", + "type": "Type", + "tags": [], + "label": "AppSubFeaturesMap", + "description": [], + "signature": [ + "Map" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.BaseKibanaFeatureConfig", + "type": "Type", + "tags": [], + "label": "BaseKibanaFeatureConfig", + "description": [], + "signature": [ + "{ id: string; order?: number | undefined; name: string; alerting?: readonly string[] | undefined; cases?: readonly string[] | undefined; description?: string | undefined; category: ", + { + "pluginId": "@kbn/core-application-common", + "scope": "common", + "docId": "kibKbnCoreApplicationCommonPluginApi", + "section": "def-common.AppCategory", + "text": "AppCategory" + }, + "; management?: { [sectionId: string]: readonly string[]; } | undefined; privileges: { all: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.FeatureKibanaPrivileges", + "text": "FeatureKibanaPrivileges" + }, + "; read: ", + { + "pluginId": "features", + "scope": "common", + "docId": "kibFeaturesPluginApi", + "section": "def-common.FeatureKibanaPrivileges", + "text": "FeatureKibanaPrivileges" + }, + "; } | null; catalogue?: readonly string[] | undefined; excludeFromBasePrivileges?: boolean | undefined; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; app: readonly string[]; privilegesTooltip?: string | undefined; reserved?: { description: string; privileges: readonly ", + "ReservedKibanaPrivilege", + "[]; } | undefined; }" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/security-solution-features", + "id": "def-common.SubFeaturesPrivileges", + "type": "Type", + "tags": [], + "label": "SubFeaturesPrivileges", + "description": [], + "signature": [ + "{ id?: string | undefined; name?: string | undefined; includeIn?: \"none\" | \"read\" | \"all\" | undefined; minimumLicense?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<\"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined>; alerting?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<{ rule?: { all?: readonly string[] | undefined; read?: readonly string[] | undefined; } | undefined; alert?: { all?: readonly string[] | undefined; read?: readonly string[] | undefined; } | undefined; } | undefined>; cases?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<{ all?: readonly string[] | undefined; push?: readonly string[] | undefined; create?: readonly string[] | undefined; read?: readonly string[] | undefined; update?: readonly string[] | undefined; delete?: readonly string[] | undefined; } | undefined>; disabled?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "; management?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<{ [sectionId: string]: readonly string[]; } | undefined>; ui?: readonly string[] | undefined; catalogue?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "; app?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "; requireAllSpaces?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "; api?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "; savedObject?: ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "<{ all: readonly string[]; read: readonly string[]; }> | undefined; }" + ], + "path": "x-pack/packages/security-solution/features/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx new file mode 100644 index 0000000000000..feff9a8532c37 --- /dev/null +++ b/api_docs/kbn_security_solution_features.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: kibKbnSecuritySolutionFeaturesPluginApi +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: 2023-09-05 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] +--- +import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; + + + +Contact [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 14 | 0 | 14 | 6 | + +## Common + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 7ba0bfa26420b..43b8698ec5add 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: 2023-08-31 +date: 2023-09-05 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 83879ef322a10..0edc300b7fbb8 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: 2023-08-31 +date: 2023-09-05 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 068006b37a637..303b370aed662 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: 2023-08-31 +date: 2023-09-05 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 dffbe8973049b..0e8e3606673c7 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: 2023-08-31 +date: 2023-09-05 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 7bc25bbefdd9a..39fd4b1f96d01 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: 2023-08-31 +date: 2023-09-05 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 574af8bded64c..e1881be0c8187 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 2c2e112945173..1c4796084d273 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: 2023-08-31 +date: 2023-09-05 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 99c81007fab71..057fd8ddd0154 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index 4ce23e47fba8f..bcab35e3734e8 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index ae9a0a7e9b537..6188b4f538622 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: 2023-08-31 +date: 2023-09-05 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 1cf8eca2166d8..ee9589bd9fdab 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: 2023-08-31 +date: 2023-09-05 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 464c6e10d8866..55ab104bac818 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: 2023-08-31 +date: 2023-09-05 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 07e8aa5b5556c..16df8b1d3143c 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: 2023-08-31 +date: 2023-09-05 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 974020ce0ade0..9d02dbe8bf408 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: 2023-08-31 +date: 2023-09-05 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 260431910b459..47fd8f9a4d494 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: 2023-08-31 +date: 2023-09-05 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 fb8c299509112..5c0ca05384879 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: 2023-08-31 +date: 2023-09-05 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 056b62569ad6b..806945c74d6ef 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: 2023-08-31 +date: 2023-09-05 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 43c0751f6bdfc..67c024298e1af 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: 2023-08-31 +date: 2023-09-05 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 b6abee2a70f3a..ae9982c0af157 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: 2023-08-31 +date: 2023-09-05 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 ab93744b3e11f..f9802c7fe0576 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: 2023-08-31 +date: 2023-09-05 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 6a865e0ae4142..6dc1d8f5b2b13 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: 2023-08-31 +date: 2023-09-05 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 31d4820763432..1b4eefb68fc5f 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: 2023-08-31 +date: 2023-09-05 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 ec9839bb4db68..e106cb033c5c2 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index c40cef6f7927c..f9ad4f267548f 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: 2023-08-31 +date: 2023-09-05 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_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index e1084b2209f5d..8f8629d869e68 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: 2023-08-31 +date: 2023-09-05 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 e829ca52fb8f6..82f04c8c1f8f3 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: 2023-08-31 +date: 2023-09-05 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 5db48e2f132a6..e4ec0a2a0470d 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: 2023-08-31 +date: 2023-09-05 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_avatar_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index 937164ab6caed..332ee7b559786 100644 --- a/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx +++ b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-user-profile-components title: "@kbn/shared-ux-avatar-user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-user-profile-components plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-user-profile-components'] --- import kbnSharedUxAvatarUserProfileComponentsObj from './kbn_shared_ux_avatar_user_profile_components.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 170a79043d17d..b342b28412dd3 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: 2023-08-31 +date: 2023-09-05 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_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 28c333bf658f1..ea0dee0f20096 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 6efe1857d2738..bed943cf01244 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: 2023-08-31 +date: 2023-09-05 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 c467c44c5bf9f..298b26586d47f 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: 2023-08-31 +date: 2023-09-05 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 a037514c01402..f8e4d0340abe9 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index da0742e78a0c4..a9cfd49bd9006 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: 2023-08-31 +date: 2023-09-05 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_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index cda0e6cc766a9..571aa579476e0 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: 2023-08-31 +date: 2023-09-05 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 503b49e6a26a2..d320a6fe79159 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: 2023-08-31 +date: 2023-09-05 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 647be5d88ced7..7a01e2db59806 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: 2023-08-31 +date: 2023-09-05 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 14e968508ea23..05b8167d72a32 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: 2023-08-31 +date: 2023-09-05 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 9c6d7a66453a9..7fe50b1e6efa5 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: 2023-08-31 +date: 2023-09-05 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 45b1713daaee5..341baae0eddc6 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: 2023-08-31 +date: 2023-09-05 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 4d7167c79a271..b5bdafbe3406e 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: 2023-08-31 +date: 2023-09-05 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 fadd69b743bf2..bd9f0e5e054b5 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: 2023-08-31 +date: 2023-09-05 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 5f5003dce8576..bdb21965fe310 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: 2023-08-31 +date: 2023-09-05 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 c736017970b4d..f8166ef3df380 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: 2023-08-31 +date: 2023-09-05 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 2da9f06ac47fb..034c8d773754d 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: 2023-08-31 +date: 2023-09-05 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 e008dbcaac161..47ecb7343d741 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: 2023-08-31 +date: 2023-09-05 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 de564080f6682..c5369259e7b4d 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: 2023-08-31 +date: 2023-09-05 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 4fd42bb48e46b..b9d0e9b498902 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: 2023-08-31 +date: 2023-09-05 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 c54b630b535a3..2bd6c3050ac8f 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: 2023-08-31 +date: 2023-09-05 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 2acd11544fc63..35e91bb002744 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: 2023-08-31 +date: 2023-09-05 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 7ca17c09b82a6..c1cf40e7bc764 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: 2023-08-31 +date: 2023-09-05 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 5f30612551e76..86fa9e7c1891f 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: 2023-08-31 +date: 2023-09-05 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 b9592179ecc9b..3c8e084113bee 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: 2023-08-31 +date: 2023-09-05 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 f6dde6c99f1e0..28f32b9dc5257 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: 2023-08-31 +date: 2023-09-05 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 573d72fbd8caa..997a796e86d22 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: 2023-08-31 +date: 2023-09-05 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 bed39fe2108b1..f470445bd947b 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: 2023-08-31 +date: 2023-09-05 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 e63bb6bca3c2e..33873f09e4810 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: 2023-08-31 +date: 2023-09-05 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 bbfdab153d988..274db8e8bfa85 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: 2023-08-31 +date: 2023-09-05 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 c383c36cad2e0..9a775023878d6 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: 2023-08-31 +date: 2023-09-05 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 adb787dc89fe5..aed9adc9f36ba 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: 2023-08-31 +date: 2023-09-05 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 35acb7814d426..07c8ac15e2ccb 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: 2023-08-31 +date: 2023-09-05 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 575dec52b2730..129749e6731df 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: 2023-08-31 +date: 2023-09-05 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 d206006f296c6..d36240ef6c53e 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: 2023-08-31 +date: 2023-09-05 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 6d9e3e4477ffe..cf78e32a622ed 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: 2023-08-31 +date: 2023-09-05 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_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index ae276d53a3cda..d3a1875b6ce61 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: 2023-08-31 +date: 2023-09-05 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 a2ce1f57cb673..0839df57edc00 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: 2023-08-31 +date: 2023-09-05 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 ea565b6ba58b6..407b4ab1645d0 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index f34f0d248cb0f..8a7b3d8d10eba 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: 2023-08-31 +date: 2023-09-05 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 e7ab1af01cb48..8af618fd3428f 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: 2023-08-31 +date: 2023-09-05 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 309966fc0a9db..dbffcc85a47b8 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index 4312a7942360c..6b1ecb4fc1a93 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: 2023-08-31 +date: 2023-09-05 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 93b224851b4cf..f25b8eca3b096 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index da0ee7250ea6c..5077de40d935f 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: 2023-08-31 +date: 2023-09-05 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 984266764db13..43372f3125e20 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: 2023-08-31 +date: 2023-09-05 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.devdocs.json b/api_docs/kbn_text_based_editor.devdocs.json index 1eb1abc6f8275..e0ba49c3e1b0e 100644 --- a/api_docs/kbn_text_based_editor.devdocs.json +++ b/api_docs/kbn_text_based_editor.devdocs.json @@ -203,6 +203,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/text-based-editor", + "id": "def-public.TextBasedLanguagesEditorProps.warning", + "type": "string", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/text-based-editor", "id": "def-public.TextBasedLanguagesEditorProps.isDisabled", @@ -244,6 +258,20 @@ "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/text-based-editor", + "id": "def-public.TextBasedLanguagesEditorProps.hideMinimizeButton", + "type": "CompoundType", + "tags": [], + "label": "hideMinimizeButton", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index 3b5916bc801f9..9e04bda94e0e3 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 15 | 0 | 14 | 0 | +| 17 | 0 | 16 | 0 | ## Client diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index 1e09e6abda1dd..871c6c2b8e718 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 7693bbfa5144d..be3c8e29d5516 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: 2023-08-31 +date: 2023-09-05 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 399abae571184..46f8c19cf89ec 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: 2023-08-31 +date: 2023-09-05 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 ad123dd8f536c..d8b53fc2d669f 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: 2023-08-31 +date: 2023-09-05 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 81bb9ce483ff1..a08cefa0974a5 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: 2023-08-31 +date: 2023-09-05 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 6ace28c7d04f4..68e956c6a9fd7 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.devdocs.json b/api_docs/kbn_unified_data_table.devdocs.json new file mode 100644 index 0000000000000..ae7cb737b9638 --- /dev/null +++ b/api_docs/kbn_unified_data_table.devdocs.json @@ -0,0 +1,1584 @@ +{ + "id": "@kbn/unified-data-table", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.getDisplayedColumns", + "type": "Function", + "tags": [], + "label": "getDisplayedColumns", + "description": [ + "\nFunction to provide fallback when\n1) no columns are given\n2) Just one column is given, which is the configured timefields" + ], + "signature": [ + "(stateColumns: string[], dataView: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ") => string[]" + ], + "path": "packages/kbn-unified-data-table/src/utils/columns.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.getDisplayedColumns.$1", + "type": "Array", + "tags": [], + "label": "stateColumns", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-unified-data-table/src/utils/columns.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.getDisplayedColumns.$2", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "packages/kbn-unified-data-table/src/utils/columns.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.getRowsPerPageOptions", + "type": "Function", + "tags": [], + "label": "getRowsPerPageOptions", + "description": [], + "signature": [ + "(currentRowsPerPage?: number | undefined) => number[]" + ], + "path": "packages/kbn-unified-data-table/src/utils/rows_per_page.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.getRowsPerPageOptions.$1", + "type": "number", + "tags": [], + "label": "currentRowsPerPage", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/utils/rows_per_page.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.JSONCodeEditorCommonMemoized", + "type": "Function", + "tags": [], + "label": "JSONCodeEditorCommonMemoized", + "description": [], + "signature": [ + "React.NamedExoticComponent & { readonly type: (props: JsonCodeEditorCommonProps) => JSX.Element; }" + ], + "path": "packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor_common.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.JSONCodeEditorCommonMemoized.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.popularizeField", + "type": "Function", + "tags": [], + "label": "popularizeField", + "description": [], + "signature": [ + "(dataView: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", fieldName: string, DataViewsService: ", + { + "pluginId": "dataViews", + "scope": "public", + "docId": "kibDataViewsPluginApi", + "section": "def-public.DataViewsServicePublic", + "text": "DataViewsServicePublic" + }, + ", capabilities: ", + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + }, + ") => Promise" + ], + "path": "packages/kbn-unified-data-table/src/utils/popularize_field.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.popularizeField.$1", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "packages/kbn-unified-data-table/src/utils/popularize_field.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.popularizeField.$2", + "type": "string", + "tags": [], + "label": "fieldName", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-unified-data-table/src/utils/popularize_field.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.popularizeField.$3", + "type": "Object", + "tags": [], + "label": "DataViewsService", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "public", + "docId": "kibDataViewsPluginApi", + "section": "def-public.DataViewsServicePublic", + "text": "DataViewsServicePublic" + } + ], + "path": "packages/kbn-unified-data-table/src/utils/popularize_field.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.popularizeField.$4", + "type": "Object", + "tags": [], + "label": "capabilities", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + } + ], + "path": "packages/kbn-unified-data-table/src/utils/popularize_field.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTable", + "type": "Function", + "tags": [], + "label": "UnifiedDataTable", + "description": [], + "signature": [ + "({ ariaLabelledBy, columns, controlColumnIds, dataView, loadingState, onFilter, onResize, onSetColumns, onSort, rows, sampleSize, searchDescription, searchTitle, settings, showTimeCol, showFullScreenButton, sort, useNewFieldsApi, isSortEnabled, isPaginationEnabled, cellActionsTriggerId, className, rowHeightState, onUpdateRowHeight, isPlainRecord, rowsPerPageState, onUpdateRowsPerPage, onFieldEdited, services, renderCustomGridBody, trailingControlColumns, totalHits, onFetchMoreRecords, renderDocumentView, setExpandedDoc, expandedDoc, configRowHeight, showMultiFields, maxDocFieldsDisplayed, externalControlColumns, externalAdditionalControls, rowsPerPageOptions, visibleCellActions, externalCustomRenderers, consumer, componentsTourSteps, }: ", + { + "pluginId": "@kbn/unified-data-table", + "scope": "common", + "docId": "kibKbnUnifiedDataTablePluginApi", + "section": "def-common.UnifiedDataTableProps", + "text": "UnifiedDataTableProps" + }, + ") => JSX.Element" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTable.$1", + "type": "Object", + "tags": [], + "label": "{\n ariaLabelledBy,\n columns,\n controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT,\n dataView,\n loadingState,\n onFilter,\n onResize,\n onSetColumns,\n onSort,\n rows,\n sampleSize,\n searchDescription,\n searchTitle,\n settings,\n showTimeCol,\n showFullScreenButton = true,\n sort,\n useNewFieldsApi,\n isSortEnabled = true,\n isPaginationEnabled = true,\n cellActionsTriggerId,\n className,\n rowHeightState,\n onUpdateRowHeight,\n isPlainRecord = false,\n rowsPerPageState,\n onUpdateRowsPerPage,\n onFieldEdited,\n services,\n renderCustomGridBody,\n trailingControlColumns,\n totalHits,\n onFetchMoreRecords,\n renderDocumentView,\n setExpandedDoc,\n expandedDoc,\n configRowHeight,\n showMultiFields = true,\n maxDocFieldsDisplayed = 50,\n externalControlColumns,\n externalAdditionalControls,\n rowsPerPageOptions,\n visibleCellActions,\n externalCustomRenderers,\n consumer = 'discover',\n componentsTourSteps,\n}", + "description": [], + "signature": [ + { + "pluginId": "@kbn/unified-data-table", + "scope": "common", + "docId": "kibKbnUnifiedDataTablePluginApi", + "section": "def-common.UnifiedDataTableProps", + "text": "UnifiedDataTableProps" + } + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.useColumns", + "type": "Function", + "tags": [], + "label": "useColumns", + "description": [], + "signature": [ + "({ capabilities, dataView, dataViews, setAppState, useNewFieldsApi, columns, sort, defaultOrder, }: UseColumnsProps) => { columns: string[]; onAddColumn: (columnName: string) => void; onRemoveColumn: (columnName: string) => void; onMoveColumn: (columnName: string, newIndex: number) => void; onSetColumns: (nextColumns: string[], hideTimeColumn: boolean) => void; }" + ], + "path": "packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.useColumns.$1", + "type": "Object", + "tags": [], + "label": "{\n capabilities,\n dataView,\n dataViews,\n setAppState,\n useNewFieldsApi,\n columns,\n sort,\n defaultOrder = 'desc',\n}", + "description": [], + "signature": [ + "UseColumnsProps" + ], + "path": "packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps", + "type": "Interface", + "tags": [], + "label": "UnifiedDataTableProps", + "description": [], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.ariaLabelledBy", + "type": "string", + "tags": [], + "label": "ariaLabelledBy", + "description": [ + "\nDetermines which element labels the grid for ARIA" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.className", + "type": "string", + "tags": [], + "label": "className", + "description": [ + "\nOptional class name to apply" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.columns", + "type": "Array", + "tags": [], + "label": "columns", + "description": [ + "\nDetermines ids of the columns which are displayed" + ], + "signature": [ + "string[]" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.expandedDoc", + "type": "Object", + "tags": [], + "label": "expandedDoc", + "description": [ + "\nIf set, the given document is displayed in a flyout" + ], + "signature": [ + "DataTableRecord", + " | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.dataView", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [ + "\nThe used data view" + ], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.loadingState", + "type": "Enum", + "tags": [], + "label": "loadingState", + "description": [ + "\nDetermines if data is currently loaded" + ], + "signature": [ + { + "pluginId": "@kbn/unified-data-table", + "scope": "common", + "docId": "kibKbnUnifiedDataTablePluginApi", + "section": "def-common.DataLoadingState", + "text": "DataLoadingState" + } + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onFilter", + "type": "Function", + "tags": [], + "label": "onFilter", + "description": [ + "\nFunction to add a filter in the grid cell or document flyout" + ], + "signature": [ + "(mapping: string | ", + "FieldMapping", + " | undefined, value: unknown, mode: \"+\" | \"-\") => void" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onFilter.$1", + "type": "CompoundType", + "tags": [], + "label": "mapping", + "description": [], + "signature": [ + "string | ", + "FieldMapping", + " | undefined" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onFilter.$2", + "type": "Unknown", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onFilter.$3", + "type": "CompoundType", + "tags": [], + "label": "mode", + "description": [], + "signature": [ + "\"+\" | \"-\"" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/types.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onResize", + "type": "Function", + "tags": [], + "label": "onResize", + "description": [ + "\nFunction triggered when a column is resized by the user" + ], + "signature": [ + "((colSettings: { columnId: string; width: number; }) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onResize.$1", + "type": "Object", + "tags": [], + "label": "colSettings", + "description": [], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onResize.$1.columnId", + "type": "string", + "tags": [], + "label": "columnId", + "description": [], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onResize.$1.width", + "type": "number", + "tags": [], + "label": "width", + "description": [], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onSetColumns", + "type": "Function", + "tags": [], + "label": "onSetColumns", + "description": [ + "\nFunction to set all columns" + ], + "signature": [ + "(columns: string[], hideTimeColumn: boolean) => void" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onSetColumns.$1", + "type": "Array", + "tags": [], + "label": "columns", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onSetColumns.$2", + "type": "boolean", + "tags": [], + "label": "hideTimeColumn", + "description": [], + "signature": [ + "boolean" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onSort", + "type": "Function", + "tags": [], + "label": "onSort", + "description": [ + "\nfunction to change sorting of the documents, skipped when isSortEnabled is set to false" + ], + "signature": [ + "((sort: string[][]) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onSort.$1", + "type": "Array", + "tags": [], + "label": "sort", + "description": [], + "signature": [ + "string[][]" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.rows", + "type": "Array", + "tags": [], + "label": "rows", + "description": [ + "\nArray of documents provided by Elasticsearch" + ], + "signature": [ + "DataTableRecord", + "[] | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.sampleSize", + "type": "number", + "tags": [], + "label": "sampleSize", + "description": [ + "\nThe max size of the documents returned by Elasticsearch" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.setExpandedDoc", + "type": "Function", + "tags": [], + "label": "setExpandedDoc", + "description": [ + "\nFunction to set the expanded document, which is displayed in a flyout" + ], + "signature": [ + "((doc?: ", + "DataTableRecord", + " | undefined) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.setExpandedDoc.$1", + "type": "Object", + "tags": [], + "label": "doc", + "description": [], + "signature": [ + "DataTableRecord", + " | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [ + "\nGrid display settings persisted in Elasticsearch (e.g. column width)" + ], + "signature": [ + { + "pluginId": "@kbn/unified-data-table", + "scope": "common", + "docId": "kibKbnUnifiedDataTablePluginApi", + "section": "def-common.UnifiedDataTableSettings", + "text": "UnifiedDataTableSettings" + }, + " | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.searchDescription", + "type": "string", + "tags": [], + "label": "searchDescription", + "description": [ + "\nSearch description" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.searchTitle", + "type": "string", + "tags": [], + "label": "searchTitle", + "description": [ + "\nSearch title" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.showTimeCol", + "type": "boolean", + "tags": [], + "label": "showTimeCol", + "description": [ + "\nDetermines whether the time columns should be displayed (legacy settings)" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.showFullScreenButton", + "type": "CompoundType", + "tags": [], + "label": "showFullScreenButton", + "description": [ + "\nDetermines whether the full screen button should be displayed" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.isSortEnabled", + "type": "CompoundType", + "tags": [], + "label": "isSortEnabled", + "description": [ + "\nManage user sorting control" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.sort", + "type": "Array", + "tags": [], + "label": "sort", + "description": [ + "\nCurrent sort setting" + ], + "signature": [ + "SortOrder", + "[]" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.useNewFieldsApi", + "type": "boolean", + "tags": [], + "label": "useNewFieldsApi", + "description": [ + "\nHow the data is fetched" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.isPaginationEnabled", + "type": "CompoundType", + "tags": [], + "label": "isPaginationEnabled", + "description": [ + "\nManage pagination control" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.controlColumnIds", + "type": "Array", + "tags": [], + "label": "controlColumnIds", + "description": [ + "\nList of used control columns (available: 'openDetails', 'select')" + ], + "signature": [ + "string[] | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.rowHeightState", + "type": "number", + "tags": [], + "label": "rowHeightState", + "description": [ + "\nRow height from state" + ], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onUpdateRowHeight", + "type": "Function", + "tags": [], + "label": "onUpdateRowHeight", + "description": [ + "\nUpdate row height state" + ], + "signature": [ + "((rowHeight: number) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onUpdateRowHeight.$1", + "type": "number", + "tags": [], + "label": "rowHeight", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.isPlainRecord", + "type": "CompoundType", + "tags": [], + "label": "isPlainRecord", + "description": [ + "\nIs text base lang mode enabled" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.rowsPerPageState", + "type": "number", + "tags": [], + "label": "rowsPerPageState", + "description": [ + "\nCurrent state value for rowsPerPage" + ], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onUpdateRowsPerPage", + "type": "Function", + "tags": [], + "label": "onUpdateRowsPerPage", + "description": [ + "\nUpdate rows per page state" + ], + "signature": [ + "((rowsPerPage: number) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onUpdateRowsPerPage.$1", + "type": "number", + "tags": [], + "label": "rowsPerPage", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onFieldEdited", + "type": "Function", + "tags": [], + "label": "onFieldEdited", + "description": [ + "\nCallback to execute on edit runtime field" + ], + "signature": [ + "(() => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.cellActionsTriggerId", + "type": "string", + "tags": [], + "label": "cellActionsTriggerId", + "description": [ + "\nOptional triggerId to retrieve the column cell actions that will override the default ones" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.services", + "type": "Object", + "tags": [], + "label": "services", + "description": [ + "\nService dependencies" + ], + "signature": [ + "{ theme: ", + { + "pluginId": "@kbn/react-kibana-context-common", + "scope": "common", + "docId": "kibKbnReactKibanaContextCommonPluginApi", + "section": "def-common.ThemeServiceStart", + "text": "ThemeServiceStart" + }, + "; fieldFormats: ", + { + "pluginId": "fieldFormats", + "scope": "public", + "docId": "kibFieldFormatsPluginApi", + "section": "def-public.FieldFormatsStart", + "text": "FieldFormatsStart" + }, + "; uiSettings: ", + { + "pluginId": "@kbn/core-ui-settings-browser", + "scope": "common", + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-common.IUiSettingsClient", + "text": "IUiSettingsClient" + }, + "; dataViewFieldEditor: ", + { + "pluginId": "dataViewFieldEditor", + "scope": "public", + "docId": "kibDataViewFieldEditorPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + }, + "; toastNotifications: ", + { + "pluginId": "@kbn/core-notifications-browser", + "scope": "common", + "docId": "kibKbnCoreNotificationsBrowserPluginApi", + "section": "def-common.IToasts", + "text": "IToasts" + }, + "; storage: ", + { + "pluginId": "kibanaUtils", + "scope": "public", + "docId": "kibKibanaUtilsPluginApi", + "section": "def-public.Storage", + "text": "Storage" + }, + "; data: ", + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataPluginApi", + "section": "def-public.DataPublicPluginStart", + "text": "DataPublicPluginStart" + }, + "; }" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.renderDocumentView", + "type": "Function", + "tags": [], + "label": "renderDocumentView", + "description": [ + "\nCallback to render DocumentView when the document is expanded" + ], + "signature": [ + "((hit: ", + "DataTableRecord", + ", displayedRows: ", + "DataTableRecord", + "[], displayedColumns: string[]) => JSX.Element | undefined) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.renderDocumentView.$1", + "type": "Object", + "tags": [], + "label": "hit", + "description": [], + "signature": [ + "DataTableRecord" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.renderDocumentView.$2", + "type": "Array", + "tags": [], + "label": "displayedRows", + "description": [], + "signature": [ + "DataTableRecord", + "[]" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.renderDocumentView.$3", + "type": "Array", + "tags": [], + "label": "displayedColumns", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.configRowHeight", + "type": "number", + "tags": [], + "label": "configRowHeight", + "description": [ + "\nOptional value for providing configuration setting for UnifiedDataTable rows height" + ], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.showMultiFields", + "type": "CompoundType", + "tags": [], + "label": "showMultiFields", + "description": [ + "\nOptional value for providing configuration setting for enabling to display the complex fields in the table. Default is true." + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.maxDocFieldsDisplayed", + "type": "number", + "tags": [], + "label": "maxDocFieldsDisplayed", + "description": [ + "\nOptional value for providing configuration setting for maximum number of document fields to display in the table. Default is 50." + ], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.externalControlColumns", + "type": "Array", + "tags": [], + "label": "externalControlColumns", + "description": [ + "\nOptional value for providing EuiDataGridControlColumn list of the additional leading control columns. UnifiedDataTable includes two control columns: Open Details and Select." + ], + "signature": [ + "EuiDataGridControlColumn", + "[] | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.totalHits", + "type": "number", + "tags": [], + "label": "totalHits", + "description": [ + "\nNumber total hits from ES" + ], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.onFetchMoreRecords", + "type": "Function", + "tags": [], + "label": "onFetchMoreRecords", + "description": [ + "\nTo fetch more" + ], + "signature": [ + "(() => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.externalAdditionalControls", + "type": "CompoundType", + "tags": [], + "label": "externalAdditionalControls", + "description": [ + "\nOptional value for providing the additional controls available in the UnifiedDataTable toolbar to manage it's records or state. UnifiedDataTable includes Columns, Sorting and Bulk Actions." + ], + "signature": [ + "boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.rowsPerPageOptions", + "type": "Array", + "tags": [], + "label": "rowsPerPageOptions", + "description": [ + "\nOptional list of number type values to set custom UnifiedDataTable paging options to display the records per page." + ], + "signature": [ + "number[] | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.renderCustomGridBody", + "type": "Function", + "tags": [], + "label": "renderCustomGridBody", + "description": [ + "\nAn optional function called to completely customize and control the rendering of\nEuiDataGrid's body and cell placement. This can be used to, e.g. remove EuiDataGrid's\nvirtualization library, or roll your own.\n\nThis component is **only** meant as an escape hatch for extremely custom use cases.\n\nBehind the scenes, this function is treated as a React component,\nallowing hooks, context, and other React concepts to be used.\nIt receives #EuiDataGridCustomBodyProps as its only argument." + ], + "signature": [ + "((args: ", + "EuiDataGridCustomBodyProps", + ") => React.ReactNode) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.renderCustomGridBody.$1", + "type": "Object", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "EuiDataGridCustomBodyProps" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.trailingControlColumns", + "type": "Array", + "tags": [], + "label": "trailingControlColumns", + "description": [ + "\nAn optional list of the EuiDataGridControlColumn type for setting trailing control columns standard for EuiDataGrid." + ], + "signature": [ + "EuiDataGridControlColumn", + "[] | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.visibleCellActions", + "type": "number", + "tags": [], + "label": "visibleCellActions", + "description": [ + "\nAn optional value for a custom number of the visible cell actions in the table. By default is up to 3." + ], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.externalCustomRenderers", + "type": "Object", + "tags": [], + "label": "externalCustomRenderers", + "description": [ + "\nAn optional settings for a specified fields rendering like links. Applied only for the listed fields rendering." + ], + "signature": [ + "Record React.ReactNode> | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.consumer", + "type": "string", + "tags": [], + "label": "consumer", + "description": [ + "\nName of the UnifiedDataTable consumer component or application" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableProps.componentsTourSteps", + "type": "Object", + "tags": [], + "label": "componentsTourSteps", + "description": [ + "\nOptional key/value pairs to set guided onboarding steps ids for a data table components included to guided tour." + ], + "signature": [ + "Record | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableSettings", + "type": "Interface", + "tags": [], + "label": "UnifiedDataTableSettings", + "description": [ + "\nUser configurable state of data grid, persisted in saved search" + ], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableSettings.columns", + "type": "Object", + "tags": [], + "label": "columns", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableSettingsColumn", + "type": "Interface", + "tags": [], + "label": "UnifiedDataTableSettingsColumn", + "description": [], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.UnifiedDataTableSettingsColumn.width", + "type": "number", + "tags": [], + "label": "width", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.DataLoadingState", + "type": "Enum", + "tags": [], + "label": "DataLoadingState", + "description": [], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "misc": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.ValueToStringConverter", + "type": "Type", + "tags": [], + "label": "ValueToStringConverter", + "description": [], + "signature": [ + "(rowIndex: number, columnId: string, options?: { compatibleWithCSV?: boolean | undefined; } | undefined) => { formattedString: string; withFormula: boolean; }" + ], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.ValueToStringConverter.$1", + "type": "number", + "tags": [], + "label": "rowIndex", + "description": [], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.ValueToStringConverter.$2", + "type": "string", + "tags": [], + "label": "columnId", + "description": [], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-common.ValueToStringConverter.$3", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "{ compatibleWithCSV?: boolean | undefined; } | undefined" + ], + "path": "packages/kbn-unified-data-table/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx new file mode 100644 index 0000000000000..91091dbb7a330 --- /dev/null +++ b/api_docs/kbn_unified_data_table.mdx @@ -0,0 +1,39 @@ +--- +#### +#### 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: kibKbnUnifiedDataTablePluginApi +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: 2023-09-05 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] +--- +import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; + +Contains functionality for the unified data table which can be integrated into apps + +Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 88 | 0 | 39 | 1 | + +## Common + +### Functions + + +### Interfaces + + +### Enums + + +### Consts, variables and types + + diff --git a/api_docs/kbn_unified_doc_viewer.devdocs.json b/api_docs/kbn_unified_doc_viewer.devdocs.json new file mode 100644 index 0000000000000..da1c2b438bd70 --- /dev/null +++ b/api_docs/kbn_unified_doc_viewer.devdocs.json @@ -0,0 +1,204 @@ +{ + "id": "@kbn/unified-doc-viewer", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewsRegistry", + "type": "Class", + "tags": [], + "label": "DocViewsRegistry", + "description": [], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewsRegistry.addDocView", + "type": "Function", + "tags": [], + "label": "addDocView", + "description": [ + "\nExtends and adds the given doc view to the registry array" + ], + "signature": [ + "(docViewRaw: ", + "DocViewInput", + " | ", + "DocViewInputFn", + ") => void" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewsRegistry.addDocView.$1", + "type": "CompoundType", + "tags": [], + "label": "docViewRaw", + "description": [], + "signature": [ + "DocViewInput", + " | ", + "DocViewInputFn" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewsRegistry.getDocViewsSorted", + "type": "Function", + "tags": [], + "label": "getDocViewsSorted", + "description": [ + "\nReturns a sorted array of doc_views for rendering tabs" + ], + "signature": [ + "(hit: ", + "DataTableRecord", + ") => ", + "DocView", + "[]" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewsRegistry.getDocViewsSorted.$1", + "type": "Object", + "tags": [], + "label": "hit", + "description": [], + "signature": [ + "DataTableRecord" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewer", + "type": "Function", + "tags": [], + "label": "DocViewer", + "description": [ + "\nRendering tabs with different views of 1 Elasticsearch hit in Discover.\nThe tabs are provided by the `docs_views` registry.\nA view can contain a React `component`, or any JS framework by using\na `render` function." + ], + "signature": [ + "({ docViews, ...renderProps }: ", + "DocViewerProps", + ") => JSX.Element | null" + ], + "path": "packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.DocViewer.$1", + "type": "Object", + "tags": [], + "label": "{ docViews, ...renderProps }", + "description": [], + "signature": [ + "DocViewerProps" + ], + "path": "packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.FieldName", + "type": "Function", + "tags": [], + "label": "FieldName", + "description": [], + "signature": [ + "({\n fieldName,\n fieldMapping,\n fieldType,\n fieldIconProps,\n scripted = false,\n highlight = '',\n}: Props) => JSX.Element" + ], + "path": "packages/kbn-unified-doc-viewer/src/components/field_name/field_name.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.FieldName.$1", + "type": "Object", + "tags": [], + "label": "{\n fieldName,\n fieldMapping,\n fieldType,\n fieldIconProps,\n scripted = false,\n highlight = '',\n}", + "description": [], + "signature": [ + "Props" + ], + "path": "packages/kbn-unified-doc-viewer/src/components/field_name/field_name.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [ + { + "parentPluginId": "@kbn/unified-doc-viewer", + "id": "def-common.ElasticRequestState", + "type": "Enum", + "tags": [], + "label": "ElasticRequestState", + "description": [], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx new file mode 100644 index 0000000000000..40c628ad3325c --- /dev/null +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -0,0 +1,36 @@ +--- +#### +#### 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: kibKbnUnifiedDocViewerPluginApi +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: 2023-09-05 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] +--- +import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; + + + +Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 10 | 0 | 7 | 6 | + +## Common + +### Functions + + +### Classes + + +### Enums + + diff --git a/api_docs/kbn_unified_field_list.devdocs.json b/api_docs/kbn_unified_field_list.devdocs.json index 88f3b347e3f0b..dddaeb04aa725 100644 --- a/api_docs/kbn_unified_field_list.devdocs.json +++ b/api_docs/kbn_unified_field_list.devdocs.json @@ -796,41 +796,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/unified-field-list", - "id": "def-common.getFieldTypeName", - "type": "Function", - "tags": [], - "label": "getFieldTypeName", - "description": [ - "\nReturns a user-friendly name of a field type" - ], - "signature": [ - "(type: string | undefined) => string" - ], - "path": "packages/kbn-unified-field-list/src/utils/field_types/get_field_type_name.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/unified-field-list", - "id": "def-common.getFieldTypeName.$1", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "packages/kbn-unified-field-list/src/utils/field_types/get_field_type_name.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/unified-field-list", "id": "def-common.getSearchMode", @@ -5518,20 +5483,6 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/unified-field-list", - "id": "def-common.KNOWN_FIELD_TYPES", - "type": "Enum", - "tags": [], - "label": "KNOWN_FIELD_TYPES", - "description": [ - "\nField types for which name and description are defined" - ], - "path": "packages/kbn-unified-field-list/src/utils/field_types/field_types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false } ], "misc": [ @@ -5691,21 +5642,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "@kbn/unified-field-list", - "id": "def-common.FieldTypeKnown", - "type": "Type", - "tags": [], - "label": "FieldTypeKnown", - "description": [], - "signature": [ - "string" - ], - "path": "packages/kbn-unified-field-list/src/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "@kbn/unified-field-list", "id": "def-common.GetCustomFieldType", diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 967ffdd332e73..f22127f77ae44 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 306 | 0 | 277 | 9 | +| 302 | 0 | 275 | 9 | ## Common diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index 20289bb13bc82..1e294e99efaba 100644 --- a/api_docs/kbn_url_state.mdx +++ b/api_docs/kbn_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-url-state title: "@kbn/url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/url-state plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 8d7ec6eac980f..b8c701132cb88 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: 2023-08-31 +date: 2023-09-05 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 522ad78bd0435..ed3eb341e30b8 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: 2023-08-31 +date: 2023-09-05 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.devdocs.json b/api_docs/kbn_utility_types.devdocs.json index 821e2d7a40523..6d177a2aa2cf2 100644 --- a/api_docs/kbn_utility_types.devdocs.json +++ b/api_docs/kbn_utility_types.devdocs.json @@ -627,6 +627,61 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/utility-types", + "id": "def-common.RecursivePartial", + "type": "Type", + "tags": [], + "label": "RecursivePartial", + "description": [], + "signature": [ + "{ [P in keyof T]?: (T[P] extends NonAny[] ? T[P] : T[P] extends readonly NonAny[] ? T[P] : T[P] extends (infer U)[] ? ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "[] : T[P] extends readonly (infer U)[] ? readonly ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "[] : T[P] extends Set ? Set<", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + "> : T[P] extends Map ? Map> : T[P] extends NonAny ? T[P] : ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.RecursivePartial", + "text": "RecursivePartial" + }, + ") | undefined; }" + ], + "path": "packages/kbn-utility-types/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/utility-types", "id": "def-common.RecursiveReadonly", diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index a81392db521d3..fabeb02cc299a 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 36 | 0 | 15 | 1 | +| 37 | 0 | 16 | 1 | ## Common diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index f64e21c7473c3..9e9cb5759dee2 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: 2023-08-31 +date: 2023-09-05 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 144543ea37762..7b5a3ae2edbf2 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: 2023-08-31 +date: 2023-09-05 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 bd0c650311ba9..0dc5954a37433 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 99d72a7aa596d..aa2fb5154468f 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index e7ae39a2ce8f4..9fa0c25531795 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.devdocs.json b/api_docs/kibana_react.devdocs.json index 04518800ede3e..3133e29cbacf4 100644 --- a/api_docs/kibana_react.devdocs.json +++ b/api_docs/kibana_react.devdocs.json @@ -908,6 +908,22 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/save_modal/show_saved_object_save_modal.tsx" }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/public/shared_imports.ts" + }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/public/application/index.tsx" + }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/public/application/index.tsx" + }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/public/application/index.tsx" + }, { "plugin": "serverless", "path": "x-pack/plugins/serverless/public/plugin.tsx" @@ -1576,22 +1592,6 @@ "plugin": "expressionShape", "path": "src/plugins/expression_shape/public/expression_renderers/progress_renderer.tsx" }, - { - "plugin": "indexManagement", - "path": "x-pack/plugins/index_management/public/shared_imports.ts" - }, - { - "plugin": "indexManagement", - "path": "x-pack/plugins/index_management/public/application/index.tsx" - }, - { - "plugin": "indexManagement", - "path": "x-pack/plugins/index_management/public/application/index.tsx" - }, - { - "plugin": "indexManagement", - "path": "x-pack/plugins/index_management/public/application/index.tsx" - }, { "plugin": "crossClusterReplication", "path": "x-pack/plugins/cross_cluster_replication/public/shared_imports.ts" @@ -3166,6 +3166,26 @@ "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/helpers/confirm_modal_promise.tsx" }, + { + "plugin": "runtimeFields", + "path": "x-pack/plugins/runtime_fields/public/shared_imports.ts" + }, + { + "plugin": "runtimeFields", + "path": "x-pack/plugins/runtime_fields/public/load_editor.tsx" + }, + { + "plugin": "runtimeFields", + "path": "x-pack/plugins/runtime_fields/public/load_editor.tsx" + }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx" + }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx" + }, { "plugin": "dataViewEditor", "path": "src/plugins/data_view_editor/public/shared_imports.ts" @@ -3326,14 +3346,6 @@ "plugin": "savedObjectsTagging", "path": "x-pack/plugins/saved_objects_tagging/public/components/assign_flyout/open_assign_flyout.tsx" }, - { - "plugin": "eventAnnotation", - "path": "src/plugins/event_annotation/public/get_table_list.tsx" - }, - { - "plugin": "eventAnnotation", - "path": "src/plugins/event_annotation/public/get_table_list.tsx" - }, { "plugin": "dataViewFieldEditor", "path": "src/plugins/data_view_field_editor/public/shared_imports.ts" @@ -3346,6 +3358,14 @@ "plugin": "dataViewFieldEditor", "path": "src/plugins/data_view_field_editor/public/open_delete_modal.tsx" }, + { + "plugin": "eventAnnotation", + "path": "src/plugins/event_annotation/public/get_table_list.tsx" + }, + { + "plugin": "eventAnnotation", + "path": "src/plugins/event_annotation/public/get_table_list.tsx" + }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/persistence/saved_objects_utils/confirm_modal_promise.tsx" @@ -3674,26 +3694,6 @@ "plugin": "cloudSecurityPosture", "path": "x-pack/plugins/cloud_security_posture/public/components/take_action.tsx" }, - { - "plugin": "runtimeFields", - "path": "x-pack/plugins/runtime_fields/public/shared_imports.ts" - }, - { - "plugin": "runtimeFields", - "path": "x-pack/plugins/runtime_fields/public/load_editor.tsx" - }, - { - "plugin": "runtimeFields", - "path": "x-pack/plugins/runtime_fields/public/load_editor.tsx" - }, - { - "plugin": "indexManagement", - "path": "x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx" - }, - { - "plugin": "indexManagement", - "path": "x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_edit/component_template_edit.tsx" - }, { "plugin": "dashboardEnhanced", "path": "x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/flyout_create_drilldown.tsx" @@ -3906,122 +3906,6 @@ "plugin": "synthetics", "path": "x-pack/plugins/synthetics/public/apps/synthetics/components/test_now_mode/manual_test_run_mode/simple_test_results.tsx" }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/components/toast_notification_text.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/components/toast_notification_text.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx" - }, - { - "plugin": "transform", - "path": "x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx" - }, { "plugin": "uptime", "path": "x-pack/plugins/uptime/public/legacy_uptime/lib/alert_types/alert_messages.tsx" diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index c2899bab77685..72e61b9db565c 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: 2023-08-31 +date: 2023-09-05 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 c7043efea0322..91d17d9fcde72 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: 2023-08-31 +date: 2023-09-05 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 71bacaad6ebca..eeb74883b2962 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: 2023-08-31 +date: 2023-09-05 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 ff23c940b0bc8..7640d66033c05 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: 2023-08-31 +date: 2023-09-05 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 86f910ca4901e..51aee902356a6 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: 2023-08-31 +date: 2023-09-05 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 9a5858fcaee14..6d5783871cdc4 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: 2023-08-31 +date: 2023-09-05 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 bfa40e142ca1f..8514ee21fcd37 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 78a4d8f31609d..7d88a913416d4 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/log_explorer.devdocs.json b/api_docs/log_explorer.devdocs.json new file mode 100644 index 0000000000000..742f9c0f72bfa --- /dev/null +++ b/api_docs/log_explorer.devdocs.json @@ -0,0 +1,76 @@ +{ + "id": "logExplorer", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "logExplorer", + "id": "def-public.LogExplorerPluginSetup", + "type": "Type", + "tags": [], + "label": "LogExplorerPluginSetup", + "description": [], + "signature": [ + "void" + ], + "path": "x-pack/plugins/log_explorer/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "logExplorer", + "id": "def-public.LogExplorerPluginStart", + "type": "Interface", + "tags": [], + "label": "LogExplorerPluginStart", + "description": [], + "path": "x-pack/plugins/log_explorer/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "logExplorer", + "id": "def-public.LogExplorerPluginStart.LogExplorer", + "type": "CompoundType", + "tags": [], + "label": "LogExplorer", + "description": [], + "signature": [ + "React.ComponentClass<", + "LogExplorerProps", + ", any> | React.FunctionComponent<", + "LogExplorerProps", + ">" + ], + "path": "x-pack/plugins/log_explorer/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/log_explorer.mdx b/api_docs/log_explorer.mdx new file mode 100644 index 0000000000000..88da234919d93 --- /dev/null +++ b/api_docs/log_explorer.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: kibLogExplorerPluginApi +slug: /kibana-dev-docs/api/logExplorer +title: "logExplorer" +image: https://source.unsplash.com/400x175/?github +description: API docs for the logExplorer plugin +date: 2023-09-05 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logExplorer'] +--- +import logExplorerObj from './log_explorer.devdocs.json'; + +This plugin provides a LogExplorer component using the Discover customization framework, offering several affordances specifically designed for log consumption. + +Contact [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 3 | 0 | 3 | 1 | + +## Client + +### Setup + + +### Start + + diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index d21c8678bdbd7..6a569ad488335 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: 2023-08-31 +date: 2023-09-05 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 62bf42794f51e..506e3bdaa1684 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: 2023-08-31 +date: 2023-09-05 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 753e36934248f..415d96478e799 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: 2023-08-31 +date: 2023-09-05 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 f2ee21c0654f0..a76d920efbd05 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 6104d0c90ee7e..87679e97ee10f 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 3bd402b689bde..2f9c10a8d601f 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: 2023-08-31 +date: 2023-09-05 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 2cd8a2e6ec393..1f3f4c9e84b3c 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: 2023-08-31 +date: 2023-09-05 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 349c843836456..58358d769e1c8 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: 2023-08-31 +date: 2023-09-05 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 04e067a9fa249..5c0fda7795ffc 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: 2023-08-31 +date: 2023-09-05 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 753457d10e5c3..4b84d2688576b 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: 2023-08-31 +date: 2023-09-05 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 da5e1a83739fe..844c63784a8e7 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: 2023-08-31 +date: 2023-09-05 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 e910e74323d61..24d66a3f94a94 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -2652,6 +2652,26 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "observability", + "id": "def-public.ObservabilityPublicPluginsStart.contentManagement", + "type": "Object", + "tags": [], + "label": "contentManagement", + "description": [], + "signature": [ + { + "pluginId": "contentManagement", + "scope": "public", + "docId": "kibContentManagementPluginApi", + "section": "def-public.ContentManagementPublicStart", + "text": "ContentManagementPublicStart" + } + ], + "path": "x-pack/plugins/observability/public/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "observability", "id": "def-public.ObservabilityPublicPluginsStart.data", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 57b36d34aa168..4f5365797c3b2 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/actionable-observability](https://github.com/orgs/elastic/team | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 541 | 2 | 532 | 16 | +| 542 | 2 | 533 | 16 | ## Client diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index 59f2dcee727e4..73a81e8571d20 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -399,7 +399,7 @@ "ObservabilityAIAssistantRouteHandlerResources", ") => Promise<{}>; } & ", "ObservabilityAIAssistantRouteCreateOptions", - "; \"POST /internal/observability_ai_assistant/functions/summarise\": { endpoint: \"POST /internal/observability_ai_assistant/functions/summarise\"; params?: ", + "; \"POST /internal/observability_ai_assistant/functions/summarize\": { endpoint: \"POST /internal/observability_ai_assistant/functions/summarize\"; params?: ", "TypeC", "<{ body: ", "TypeC", @@ -764,7 +764,7 @@ "ObservabilityAIAssistantRouteHandlerResources", ") => Promise<{}>; } & ", "ObservabilityAIAssistantRouteCreateOptions", - "; \"POST /internal/observability_ai_assistant/functions/summarise\": { endpoint: \"POST /internal/observability_ai_assistant/functions/summarise\"; params?: ", + "; \"POST /internal/observability_ai_assistant/functions/summarize\": { endpoint: \"POST /internal/observability_ai_assistant/functions/summarize\"; params?: ", "TypeC", "<{ body: ", "TypeC", @@ -1105,7 +1105,7 @@ "label": "ObservabilityAIAssistantAPIEndpoint", "description": [], "signature": [ - "\"POST /internal/observability_ai_assistant/chat\" | \"GET /internal/observability_ai_assistant/conversation/{conversationId}\" | \"POST /internal/observability_ai_assistant/conversations\" | \"POST /internal/observability_ai_assistant/conversation\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}/auto_title\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}/title\" | \"DELETE /internal/observability_ai_assistant/conversation/{conversationId}\" | \"GET /internal/observability_ai_assistant/connectors\" | \"POST /internal/observability_ai_assistant/functions/elasticsearch\" | \"POST /internal/observability_ai_assistant/functions/recall\" | \"POST /internal/observability_ai_assistant/functions/summarise\" | \"POST /internal/observability_ai_assistant/functions/setup_kb\" | \"GET /internal/observability_ai_assistant/functions/kb_status\" | \"POST /internal/observability_ai_assistant/functions/alerts\"" + "\"POST /internal/observability_ai_assistant/chat\" | \"GET /internal/observability_ai_assistant/conversation/{conversationId}\" | \"POST /internal/observability_ai_assistant/conversations\" | \"POST /internal/observability_ai_assistant/conversation\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}/auto_title\" | \"PUT /internal/observability_ai_assistant/conversation/{conversationId}/title\" | \"DELETE /internal/observability_ai_assistant/conversation/{conversationId}\" | \"GET /internal/observability_ai_assistant/connectors\" | \"POST /internal/observability_ai_assistant/functions/elasticsearch\" | \"POST /internal/observability_ai_assistant/functions/recall\" | \"POST /internal/observability_ai_assistant/functions/summarize\" | \"POST /internal/observability_ai_assistant/functions/setup_kb\" | \"GET /internal/observability_ai_assistant/functions/kb_status\" | \"POST /internal/observability_ai_assistant/functions/alerts\"" ], "path": "x-pack/plugins/observability_ai_assistant/public/api/index.ts", "deprecated": false, @@ -1235,7 +1235,7 @@ "ObservabilityAIAssistantRouteHandlerResources", ") => Promise<{}>; } & ", "ObservabilityAIAssistantRouteCreateOptions", - "; \"POST /internal/observability_ai_assistant/functions/summarise\": { endpoint: \"POST /internal/observability_ai_assistant/functions/summarise\"; params?: ", + "; \"POST /internal/observability_ai_assistant/functions/summarize\": { endpoint: \"POST /internal/observability_ai_assistant/functions/summarize\"; params?: ", "TypeC", "<{ body: ", "TypeC", diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index 8df493b8cd5e0..31e4264930aee 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 3d19856c2518b..939e6d954a9b7 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: 2023-08-31 +date: 2023-09-05 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 8851407016745..040d247a44432 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: 2023-08-31 +date: 2023-09-05 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 02bb0e4cd8143..b9a92bd0e15a9 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index f1e64b69f8a00..8c9256f9f511c 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: 2023-08-31 +date: 2023-09-05 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 | |--------------|----------|------------------------| -| 668 | 558 | 39 | +| 674 | 564 | 39 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 72348 | 226 | 61798 | 1499 | +| 72503 | 223 | 61894 | 1513 | ## Plugin Directory @@ -37,7 +37,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 91 | 1 | 75 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 94 | 0 | 75 | 27 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 104 | 0 | 84 | 27 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 268 | 2 | 253 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 72 | 0 | 16 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 3 | 0 | 2 | 0 | @@ -57,16 +57,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 268 | 0 | 249 | 1 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 101 | 0 | 98 | 9 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3310 | 33 | 2583 | 26 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3311 | 33 | 2584 | 26 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 16 | 0 | 7 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Reusable data view field editor across Kibana | 72 | 0 | 33 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data view management app | 2 | 0 | 2 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 1034 | 0 | 254 | 2 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 31 | 3 | 25 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 12 | 0 | 10 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 99 | 0 | 72 | 17 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 98 | 0 | 71 | 15 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | -| discoverLogExplorer | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin exposes and registers Logs+ features. | 0 | 0 | 0 | 0 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Server APIs for the Elastic AI Assistant | 4 | 0 | 2 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 542 | 1 | 442 | 7 | @@ -90,7 +89,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds 'shape' function and renderer to expressions | 148 | 0 | 146 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression Tagcloud plugin adds a `tagcloud` renderer and function to the expression plugin. The renderer will display the `Wordcloud` chart. | 6 | 0 | 6 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Expression XY plugin adds a `xy` renderer and function to the expression plugin. The renderer will display the `xy` chart. | 175 | 0 | 165 | 13 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2205 | 17 | 1746 | 5 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Adds expression runtime to Kibana | 2208 | 17 | 1749 | 5 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 235 | 0 | 99 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Index pattern fields and ambiguous values formatters | 292 | 5 | 253 | 3 | | | [@elastic/kibana-gis](https://github.com/orgs/elastic/teams/kibana-gis) | The file upload plugin contains components and services for uploading a file, analyzing its data, and then importing the data into an Elasticsearch index. Supported file types include CSV, TSV, newline-delimited JSON and GeoJSON. | 62 | 0 | 62 | 2 | @@ -123,6 +122,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 117 | 0 | 42 | 10 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 224 | 0 | 96 | 51 | +| | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin provides a LogExplorer component using the Discover customization framework, offering several affordances specifically designed for log consumption. | 3 | 0 | 3 | 1 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | Exposes the shared components and APIs to access and visualize logs. | 269 | 10 | 256 | 27 | | logstash | [@elastic/logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 47 | 0 | 47 | 7 | @@ -135,14 +135,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 541 | 2 | 532 | 16 | +| | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 542 | 2 | 533 | 16 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 42 | 0 | 39 | 7 | +| observabilityLogExplorer | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | This plugin exposes and registers observability log consumption features. | 0 | 0 | 0 | 0 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 14 | 0 | 14 | 0 | | | [@elastic/observability-ui](https://github.com/orgs/elastic/teams/observability-ui) | - | 277 | 1 | 276 | 11 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 24 | 0 | 24 | 7 | | painlessLab | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 218 | 2 | 164 | 11 | -| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 19 | 1 | 19 | 3 | +| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 17 | 1 | 17 | 3 | +| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 3 | 0 | 3 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 42 | 0 | 22 | 5 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 21 | 0 | 21 | 0 | @@ -158,7 +160,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-reporting-services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 27 | 0 | 8 | 5 | | searchprofiler | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 270 | 0 | 87 | 3 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 177 | 3 | 111 | 34 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 172 | 0 | 106 | 32 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | ESS customizations for Security Solution. | 6 | 0 | 6 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Serverless customizations for security. | 6 | 0 | 6 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | The core Serverless plugin, providing APIs to Serverless Project plugins. | 17 | 0 | 16 | 0 | @@ -176,7 +178,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 31 | 0 | 26 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 0 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 17 | 0 | 17 | 0 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 19 | 0 | 19 | 0 | | | [@elastic/protections-experience](https://github.com/orgs/elastic/teams/protections-experience) | Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats | 30 | 0 | 14 | 5 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 257 | 1 | 213 | 22 | | | [@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 | @@ -184,6 +186,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 573 | 1 | 547 | 51 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 145 | 0 | 103 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 206 | 0 | 140 | 9 | +| | [@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). | 13 | 0 | 10 | 3 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 53 | 0 | 23 | 2 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 148 | 2 | 110 | 22 | | upgradeAssistant | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 0 | 0 | 0 | 0 | @@ -262,7 +265,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 8 | 0 | 1 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 20 | 0 | 19 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2 | 0 | 2 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 8 | 0 | 8 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 13 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 2 | @@ -356,7 +359,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 15 | 0 | 11 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 58 | 0 | 26 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 60 | 0 | 26 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 5 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 5 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 6 | 0 | @@ -365,7 +368,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 25 | 1 | 24 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 111 | 1 | 0 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 351 | 1 | 5 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 352 | 1 | 5 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 0 | 11 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 89 | 0 | 61 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | @@ -377,7 +380,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 125 | 0 | 91 | 46 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 12 | 0 | 12 | 0 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 548 | 1 | 122 | 4 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 547 | 1 | 121 | 4 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 69 | 0 | 69 | 4 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 14 | 0 | 14 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 0 | 6 | 0 | @@ -425,7 +428,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 101 | 0 | 85 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 15 | 0 | 9 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 29 | 2 | 25 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 59 | 0 | 34 | 3 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 65 | 0 | 38 | 3 | | | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 73 | 0 | 73 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 39 | 0 | 26 | 5 | @@ -436,7 +439,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 8 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 27 | 0 | 14 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 3 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 255 | 1 | 195 | 15 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 259 | 1 | 199 | 15 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 12 | 0 | 12 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 39 | 0 | 39 | 0 | @@ -497,7 +500,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 1 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 8 | 0 | 8 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 31 | 1 | 24 | 1 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 71 | 0 | 69 | 3 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 74 | 0 | 72 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 1 | 50 | 0 | | | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 13 | 0 | 13 | 3 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 45 | 0 | 45 | 10 | @@ -525,6 +528,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 65 | 0 | 65 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 16 | 0 | 8 | 0 | +| | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 14 | 0 | 14 | 6 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 50 | 0 | 47 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 29 | 0 | 23 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 2 | 0 | 0 | 0 | @@ -599,18 +603,20 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 289 | 4 | 242 | 12 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 137 | 5 | 105 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 15 | 0 | 14 | 0 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 17 | 0 | 16 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 72 | 0 | 55 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 39 | 0 | 25 | 1 | | | [@elastic/apm-ui](https://github.com/orgs/elastic/teams/apm-ui) | - | 86 | 0 | 86 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 49 | 0 | 35 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 47 | 0 | 38 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 7 | 0 | 6 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 306 | 0 | 277 | 9 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 88 | 0 | 39 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 10 | 0 | 7 | 6 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 302 | 0 | 275 | 9 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 4 | 0 | 0 | 0 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 3 | 0 | 2 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 80 | 0 | 21 | 2 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 0 | 15 | 1 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 16 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 24 | 0 | 14 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 155 | 0 | 151 | 3 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 9f470e31cc507..17307c56df40b 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.devdocs.json b/api_docs/profiling.devdocs.json index c6b864a1e228a..1b57fc843050b 100644 --- a/api_docs/profiling.devdocs.json +++ b/api_docs/profiling.devdocs.json @@ -185,39 +185,6 @@ "common": { "classes": [], "functions": [ - { - "parentPluginId": "profiling", - "id": "def-common.fromMapToRecord", - "type": "Function", - "tags": [], - "label": "fromMapToRecord", - "description": [], - "signature": [ - "(m: Map) => Record" - ], - "path": "x-pack/plugins/profiling/common/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "profiling", - "id": "def-common.fromMapToRecord.$1", - "type": "Object", - "tags": [], - "label": "m", - "description": [], - "signature": [ - "Map" - ], - "path": "x-pack/plugins/profiling/common/index.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "profiling", "id": "def-common.getRoutePaths", diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 5509809657a0d..c733c69c88c29 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 19 | 1 | 19 | 3 | +| 17 | 1 | 17 | 3 | ## Client diff --git a/api_docs/profiling_data_access.devdocs.json b/api_docs/profiling_data_access.devdocs.json new file mode 100644 index 0000000000000..3528e7e26c101 --- /dev/null +++ b/api_docs/profiling_data_access.devdocs.json @@ -0,0 +1,76 @@ +{ + "id": "profilingDataAccess", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "profilingDataAccess", + "id": "def-server.ProfilingConfig", + "type": "Type", + "tags": [], + "label": "ProfilingConfig", + "description": [], + "signature": [ + "{ readonly elasticsearch?: Readonly<{} & { username: string; hosts: string; password: string; }> | undefined; }" + ], + "path": "x-pack/plugins/profiling_data_access/server/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "profilingDataAccess", + "id": "def-server.ProfilingDataAccessPluginStart", + "type": "Type", + "tags": [], + "label": "ProfilingDataAccessPluginStart", + "description": [], + "signature": [ + "{ services: { fetchFlamechartData: ({ esClient, rangeFrom, rangeTo, kuery }: FetchFlamechartParams) => Promise<", + "BaseFlameGraph", + ">; }; }" + ], + "path": "x-pack/plugins/profiling_data_access/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [], + "start": { + "parentPluginId": "profilingDataAccess", + "id": "def-server.ProfilingDataAccessPluginSetup", + "type": "Type", + "tags": [], + "label": "ProfilingDataAccessPluginSetup", + "description": [], + "signature": [ + "void" + ], + "path": "x-pack/plugins/profiling_data_access/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "lifecycle": "start", + "initialIsOpen": true + } + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx new file mode 100644 index 0000000000000..7dfef9cbc7f5d --- /dev/null +++ b/api_docs/profiling_data_access.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: kibProfilingDataAccessPluginApi +slug: /kibana-dev-docs/api/profilingDataAccess +title: "profilingDataAccess" +image: https://source.unsplash.com/400x175/?github +description: API docs for the profilingDataAccess plugin +date: 2023-09-05 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] +--- +import profilingDataAccessObj from './profiling_data_access.devdocs.json'; + + + +Contact [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 3 | 0 | 3 | 1 | + +## Server + +### Start + + +### Consts, variables and types + + diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 0395c6760bf09..46f7029e4c437 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: 2023-08-31 +date: 2023-09-05 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 c0edc8e9b160a..652db20d467be 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: 2023-08-31 +date: 2023-09-05 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 8fa7b2ae18a68..f05dfff64c6eb 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: 2023-08-31 +date: 2023-09-05 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 551f9ac0dac59..04ca4e478bd01 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: 2023-08-31 +date: 2023-09-05 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 ca886020268e1..deb21fb5af459 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: 2023-08-31 +date: 2023-09-05 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 71b50534dd919..a389e8c341df1 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: 2023-08-31 +date: 2023-09-05 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 8e041a0cdeb19..51f2eac47f7ee 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: 2023-08-31 +date: 2023-09-05 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 38309fcc1bc66..cc16ca5a190d2 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: 2023-08-31 +date: 2023-09-05 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 32575de4b4341..6e99575f34bea 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: 2023-08-31 +date: 2023-09-05 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 502f257494087..32fbb58ee3493 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: 2023-08-31 +date: 2023-09-05 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 4f1e99857d87a..f606643f4009d 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: 2023-08-31 +date: 2023-09-05 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 3fd7bf4ac83d4..fffd6ea49de6f 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: 2023-08-31 +date: 2023-09-05 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 ef15fa1453062..ffd1930565da5 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index cc599286f3517..3950548c880fb 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: 2023-08-31 +date: 2023-09-05 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 5ebed17999232..45c4a2685ac7c 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -1941,6 +1941,38 @@ ], "returnComment": [] }, + { + "parentPluginId": "securitySolution", + "id": "def-public.PluginStart.setDashboardsLandingCallout", + "type": "Function", + "tags": [], + "label": "setDashboardsLandingCallout", + "description": [], + "signature": [ + "(dashboardsLandingCallout: React.ComponentType<{}>) => void" + ], + "path": "x-pack/plugins/security_solution/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-public.PluginStart.setDashboardsLandingCallout.$1", + "type": "CompoundType", + "tags": [], + "label": "dashboardsLandingCallout", + "description": [], + "signature": [ + "React.ComponentType<{}>" + ], + "path": "x-pack/plugins/security_solution/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "securitySolution", "id": "def-public.PluginStart.getBreadcrumbsNav$", @@ -2792,22 +2824,16 @@ "children": [ { "parentPluginId": "securitySolution", - "id": "def-server.SecuritySolutionPluginSetup.setAppFeatures", + "id": "def-server.SecuritySolutionPluginSetup.setAppFeaturesConfigurator", "type": "Function", "tags": [], - "label": "setAppFeatures", + "label": "setAppFeaturesConfigurator", "description": [ - "\nSets the app features that are available to the Security Solution" + "\nSets the configurations for app features that are available to the Security Solution" ], "signature": [ - "(appFeatureKeys: ", - { - "pluginId": "securitySolution", - "scope": "common", - "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.AppFeatureKeys", - "text": "AppFeatureKeys" - }, + "(configurator: ", + "AppFeaturesConfigurator", ") => void" ], "path": "x-pack/plugins/security_solution/server/plugin_contract.ts", @@ -2817,22 +2843,15 @@ "children": [ { "parentPluginId": "securitySolution", - "id": "def-server.SecuritySolutionPluginSetup.setAppFeatures.$1", - "type": "Array", + "id": "def-server.SecuritySolutionPluginSetup.setAppFeaturesConfigurator.$1", + "type": "Object", "tags": [], - "label": "appFeatureKeys", + "label": "configurator", "description": [], "signature": [ - { - "pluginId": "securitySolution", - "scope": "common", - "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.AppFeatureKey", - "text": "AppFeatureKey" - }, - "[]" + "AppFeaturesConfigurator" ], - "path": "x-pack/plugins/security_solution/server/lib/app_features/app_features.ts", + "path": "x-pack/plugins/security_solution/server/lib/app_features_service/app_features_service.ts", "deprecated": false, "trackAdoption": false } @@ -2938,47 +2957,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "securitySolution", - "id": "def-common.AppFeatureKey", - "type": "Type", - "tags": [], - "label": "AppFeatureKey", - "description": [], - "signature": [ - "AppFeatureSecurityKey", - " | ", - "AppFeatureCasesKey", - " | ", - "AppFeatureAssistantKey" - ], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "securitySolution", - "id": "def-common.AppFeatureKeys", - "type": "Type", - "tags": [], - "label": "AppFeatureKeys", - "description": [], - "signature": [ - { - "pluginId": "securitySolution", - "scope": "common", - "docId": "kibSecuritySolutionPluginApi", - "section": "def-common.AppFeatureKey", - "text": "AppFeatureKey" - }, - "[]" - ], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "securitySolution", "id": "def-common.CASES_FEATURE_ID", @@ -3058,27 +3036,6 @@ } ], "objects": [ - { - "parentPluginId": "securitySolution", - "id": "def-common.ALL_APP_FEATURE_KEYS", - "type": "Object", - "tags": [], - "label": "ALL_APP_FEATURE_KEYS", - "description": [], - "signature": [ - "readonly (", - "AppFeatureSecurityKey", - " | ", - "AppFeatureCasesKey", - ".casesConnectors | ", - "AppFeatureAssistantKey", - ".assistant)[]" - ], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "securitySolution", "id": "def-common.allowedExperimentalValues", @@ -3095,62 +3052,6 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false - }, - { - "parentPluginId": "securitySolution", - "id": "def-common.AppFeatureKey", - "type": "Object", - "tags": [], - "label": "AppFeatureKey", - "description": [], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "securitySolution", - "id": "def-common.AppFeatureKey.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "securitySolution", - "id": "def-common.AppFeatureKey.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "securitySolution", - "id": "def-common.AppFeatureKey.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/security_solution/common/types/app_features.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false } ] } diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 818d3d6a75049..56c700c517970 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 177 | 3 | 111 | 34 | +| 172 | 0 | 106 | 32 | ## Client diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index a30f8948a2ffd..98f2cb7869788 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: 2023-08-31 +date: 2023-09-05 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 9cccef4b5e0f2..fe15bc4706c25 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: 2023-08-31 +date: 2023-09-05 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 7b539f150faca..0528a3c42d91c 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: 2023-08-31 +date: 2023-09-05 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 f32c5b04369ec..ca487148446ab 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: 2023-08-31 +date: 2023-09-05 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 ca81e10f02ea6..2382a958e93a4 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: 2023-08-31 +date: 2023-09-05 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 8bef3e925ae36..0c2b0290e9db7 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: 2023-08-31 +date: 2023-09-05 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 b238a21bd576c..6385220853e90 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 2f13d3c89fe0d..7d25378cd6f0e 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: 2023-08-31 +date: 2023-09-05 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 a21942465ec24..54715a2f5bf55 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: 2023-08-31 +date: 2023-09-05 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 69ab8f64e9b9e..546ab4089308b 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: 2023-08-31 +date: 2023-09-05 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 ccc3cf1c467a9..cfe538fc4b18e 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index c71b61035fcf5..c110a53377d03 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: 2023-08-31 +date: 2023-09-05 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 9b7fa86c76505..7bfe57d68a2d1 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index c5ec4b1709fa2..40acb98da6933 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: 2023-08-31 +date: 2023-09-05 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 2ff77cf44e049..0df30daa7aa12 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: 2023-08-31 +date: 2023-09-05 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 1a21f3a4fe16a..7a11b41d310d4 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.devdocs.json b/api_docs/text_based_languages.devdocs.json index e5f1b90b12a78..85e21f93ca908 100644 --- a/api_docs/text_based_languages.devdocs.json +++ b/api_docs/text_based_languages.devdocs.json @@ -210,6 +210,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "textBasedLanguages", + "id": "def-public.TextBasedLanguagesEditorProps.warning", + "type": "string", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "textBasedLanguages", "id": "def-public.TextBasedLanguagesEditorProps.isDisabled", @@ -251,6 +265,20 @@ "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "textBasedLanguages", + "id": "def-public.TextBasedLanguagesEditorProps.hideMinimizeButton", + "type": "CompoundType", + "tags": [], + "label": "hideMinimizeButton", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-text-based-editor/src/text_based_languages_editor.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 7dbf38fb09a3d..0742546f60027 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 17 | 0 | 17 | 0 | +| 19 | 0 | 19 | 0 | ## Client diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 813515dde9f41..c7145498c1a5c 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: 2023-08-31 +date: 2023-09-05 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 87e09f29e8900..bbc1eb06c8e39 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: 2023-08-31 +date: 2023-09-05 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 4e9d1032e3cf0..e5d3181a1d8d6 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 0912e894a9a00..51693988db001 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 842b9891be752..a60e9a0225c50 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: 2023-08-31 +date: 2023-09-05 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 8eb65f4aad6e7..8acfb4007dac3 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.devdocs.json b/api_docs/unified_doc_viewer.devdocs.json new file mode 100644 index 0000000000000..eb3609aa71e6d --- /dev/null +++ b/api_docs/unified_doc_viewer.devdocs.json @@ -0,0 +1,263 @@ +{ + "id": "unifiedDocViewer", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.JsonCodeEditor", + "type": "Function", + "tags": [], + "label": "JsonCodeEditor", + "description": [], + "signature": [ + "React.ForwardRefExoticComponent<", + "JsonCodeEditorProps", + " & React.RefAttributes<{}>>" + ], + "path": "src/plugins/unified_doc_viewer/public/index.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.JsonCodeEditor.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewer", + "type": "Function", + "tags": [], + "label": "UnifiedDocViewer", + "description": [], + "signature": [ + "React.ForwardRefExoticComponent<", + "DocViewRenderProps", + " & React.RefAttributes<{}>>" + ], + "path": "src/plugins/unified_doc_viewer/public/index.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewer.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.useEsDocSearch", + "type": "Function", + "tags": [], + "label": "useEsDocSearch", + "description": [ + "\nCustom react hook for querying a single doc in ElasticSearch" + ], + "signature": [ + "({\n id,\n index,\n dataView,\n requestSource,\n textBasedHits,\n}: ", + "EsDocSearchProps", + ") => [", + { + "pluginId": "@kbn/unified-doc-viewer", + "scope": "common", + "docId": "kibKbnUnifiedDocViewerPluginApi", + "section": "def-common.ElasticRequestState", + "text": "ElasticRequestState" + }, + ", ", + "DataTableRecord", + " | null, () => void]" + ], + "path": "src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.useEsDocSearch.$1", + "type": "Object", + "tags": [], + "label": "{\n id,\n index,\n dataView,\n requestSource,\n textBasedHits,\n}", + "description": [], + "signature": [ + "EsDocSearchProps" + ], + "path": "src/plugins/unified_doc_viewer/public/hooks/use_es_doc_search.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.useUnifiedDocViewerServices", + "type": "Function", + "tags": [], + "label": "useUnifiedDocViewerServices", + "description": [], + "signature": [ + "() => ", + "UnifiedDocViewerServices" + ], + "path": "src/plugins/unified_doc_viewer/public/hooks/use_doc_viewer_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewerSetup", + "type": "Interface", + "tags": [], + "label": "UnifiedDocViewerSetup", + "description": [], + "path": "src/plugins/unified_doc_viewer/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewerSetup.addDocView", + "type": "Function", + "tags": [], + "label": "addDocView", + "description": [], + "signature": [ + "(docViewRaw: ", + "DocViewInput", + " | ", + "DocViewInputFn", + ") => void" + ], + "path": "src/plugins/unified_doc_viewer/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewerSetup.addDocView.$1", + "type": "CompoundType", + "tags": [], + "label": "docViewRaw", + "description": [], + "signature": [ + "DocViewInput", + " | ", + "DocViewInputFn" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewerStart", + "type": "Interface", + "tags": [], + "label": "UnifiedDocViewerStart", + "description": [], + "path": "src/plugins/unified_doc_viewer/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewerStart.getDocViews", + "type": "Function", + "tags": [], + "label": "getDocViews", + "description": [], + "signature": [ + "(hit: ", + "DataTableRecord", + ") => ", + "DocView", + "[]" + ], + "path": "src/plugins/unified_doc_viewer/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "unifiedDocViewer", + "id": "def-public.UnifiedDocViewerStart.getDocViews.$1", + "type": "Object", + "tags": [], + "label": "hit", + "description": [], + "signature": [ + "DataTableRecord" + ], + "path": "packages/kbn-unified-doc-viewer/src/services/doc_views_registry.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx new file mode 100644 index 0000000000000..603f48d60f203 --- /dev/null +++ b/api_docs/unified_doc_viewer.mdx @@ -0,0 +1,36 @@ +--- +#### +#### 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: kibUnifiedDocViewerPluginApi +slug: /kibana-dev-docs/api/unifiedDocViewer +title: "unifiedDocViewer" +image: https://source.unsplash.com/400x175/?github +description: API docs for the unifiedDocViewer plugin +date: 2023-09-05 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] +--- +import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; + +This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). + +Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 13 | 0 | 10 | 3 | + +## Client + +### Setup + + +### Start + + +### Functions + + diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index e3d016be77067..7b1d9e1b20dad 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: 2023-08-31 +date: 2023-09-05 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 a9e828da07709..db79545b07381 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -701,7 +701,7 @@ "section": "def-public.DataViewPickerProps", "text": "DataViewPickerProps" }, - " | undefined; textBasedLanguageModeErrors?: Error[] | undefined; onTextBasedSavedAndExit?: (({ onSave }: ", + " | undefined; textBasedLanguageModeErrors?: Error[] | undefined; textBasedLanguageModeWarning?: string | undefined; onTextBasedSavedAndExit?: (({ onSave }: ", "OnSaveTextLanguageQueryProps", ") => void) | undefined; showSubmitButton?: boolean | undefined; submitButtonStyle?: \"full\" | \"auto\" | \"iconOnly\" | undefined; suggestionsSize?: ", "SuggestionsListSize", diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 4f7b41bf5d445..fd7beddabd867 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: 2023-08-31 +date: 2023-09-05 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 5bc459d37a6ec..a72a03bf4fac3 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: 2023-08-31 +date: 2023-09-05 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 b8f3bb8269554..62c01dfb2cc5f 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: 2023-08-31 +date: 2023-09-05 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 fafe162dcb3ef..11d978023890f 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index 09ba51bc1460c..960eb658ca681 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: 2023-08-31 +date: 2023-09-05 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 c411f945b55b7..15e9fd60eafed 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: 2023-08-31 +date: 2023-09-05 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 ef59d45846e50..59c3f306ced16 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: 2023-08-31 +date: 2023-09-05 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 b8a48e2212386..0010c70cfdbde 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: 2023-08-31 +date: 2023-09-05 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 dd26e237355b1..6173477d3c7a5 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: 2023-08-31 +date: 2023-09-05 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 361d2c8148583..fc76ac9c6fc64 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: 2023-08-31 +date: 2023-09-05 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 53e70f8e9260b..ce5bbdddd2e36 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: 2023-08-31 +date: 2023-09-05 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 b079a98811c17..c44173caff05c 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: 2023-08-31 +date: 2023-09-05 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 7bcb20b8cd8f4..d61f09f713d1b 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: 2023-08-31 +date: 2023-09-05 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 1fb6545a65053..bde589e42f805 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: 2023-08-31 +date: 2023-09-05 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 6db0c25e347eb..78696e8ff2b7d 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: 2023-08-31 +date: 2023-09-05 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 8cc91f2fd5a9f..a98046d0fe69a 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: 2023-08-31 +date: 2023-09-05 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 02291d78d807b..5b78f2be3fd99 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -2249,7 +2249,7 @@ "section": "def-common.DatatableRow", "text": "DatatableRow" }, - "[]; }" + "[]; warning?: string | undefined; }" ], "path": "src/plugins/visualizations/common/utils/prepare_log_table.ts", "deprecated": false, @@ -8133,7 +8133,7 @@ "section": "def-common.DatatableRow", "text": "DatatableRow" }, - "[]; }" + "[]; warning?: string | undefined; }" ], "path": "src/plugins/visualizations/common/utils/prepare_log_table.ts", "deprecated": false, diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 6456967cfc8c7..bc11233812a61 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: 2023-08-31 +date: 2023-09-05 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/catalog-info.yaml b/catalog-info.yaml index e2e4402873718..00637fb1a039b 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -151,11 +151,12 @@ spec: build_pull_request_forks: false build_tags: true # https://regex101.com/r/tY52jo/1 - filter_condition: 'build.tag =~ "/^deploy@\d+\$/"' + filter_condition: 'build.tag =~ /^deploy@\d+$/' filter_enabled: true - trigger_mode: none teams: kibana-operations: access_level: MANAGE_BUILD_AND_READ + kibana-tech-leads: + access_level: MANAGE_BUILD_AND_READ everyone: access_level: READ_ONLY diff --git a/config/serverless.yml b/config/serverless.yml index 31f51eeb59ee5..1349f71d019e6 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -119,6 +119,11 @@ xpack.alerting.rules.run.ruleTypeOverrides: xpack.alerting.rules.minimumScheduleInterval.enforce: true xpack.actions.run.maxAttempts: 10 +# Disables ESQL in advanced settings (hides it from the UI) +uiSettings: + overrides: + discover:enableESQL: false + # Task Manager xpack.task_manager.allow_reading_invalid_state: false diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 898597eabce5d..f3e74bb49ab0d 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -10,6 +10,8 @@ Review important information about the {kib} 8.x releases. + +* <> * <> * <> * <> @@ -46,6 +48,40 @@ Review important information about the {kib} 8.x releases. * <> -- +[[release-notes-8.9.2]] +== {kib} 8.9.2 + +Review the following information about the {kib} 8.9.2 release. + +[float] +[[enhancement-v8.9.2]] +=== Enhancements + +Fleet:: +* Adds the configuration setting `xpack.fleet.packageVerification.gpgKeyPath` as an environment variable in the {kib} container ({kibana-pull}163783[#163783]). + +[float] +[[fixes-v8.9.2]] +=== Bug Fixes + +Dashboard:: +* Fixes missing state on short URLs could be lost on an alias match redirect ({kibana-pull}163658[#163658]). +* Fixes 'Download CSV' returning no data when panel has custom time range outside the time range of the global time picker ({kibana-pull}163887[#163887]). +* Fixes **Dashboard** getting stuck at loading in {kib} when Controls is used and mapping changed from integer to keyword ({kibana-pull}163529[#163529]). +Elastic Security:: +For the Elastic Security 8.9.2 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_]. +Lens & Visualizations:: +* Allow removing temporary data view from event annotation group in *Lens* ({kibana-pull}163976[#163976]). +Machine Learning:: +* Anomaly detection wizard: ensure custom URLs test functionality works as expected ({kibana-pull}165055[#165055]). +* Fixes anomaly detection module manifest queries for {kib} sample data sets, so cold and frozen tiers are not queried ({kibana-pull}164332[#164332]). +Management:: +* Transforms: Fixes privileges check ({kibana-pull}163687[#163687]). +Operations:: +* Fixes an issue where {kib} did not start on CentOS/RHEL 7 ({kibana-pull}165151[#165151]). +Reporting:: +* Allow custom roles to use image reporting in **Dashboard** ({kibana-pull}163873[#163873]). + [[release-notes-8.9.1]] == {kib} 8.9.1 diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc index 9058b29f0cb8a..fb672b2884af2 100644 --- a/docs/apm/api.asciidoc +++ b/docs/apm/api.asciidoc @@ -11,7 +11,6 @@ Some APM app features are provided via a REST API: * <> * <> * <> -* <> * <> [float] @@ -716,219 +715,6 @@ curl -X DELETE "http://localhost:5601/api/apm/sourcemaps/apm:foo-1.0.0-644fd5a9" ******************************************************* //// -[role="xpack"] -[[android-sourcemap-api]] -=== Android source map API - -IMPORTANT: This endpoint is only compatible with the -{apm-guide-ref}/index.html[APM integration for Elastic Agent]. - -An Android source map (generated using Android's https://developer.android.com/build/shrink-code[R8 tool]) -allows obfuscated app stacktraces to be mapped back to original source code -- -allowing you to maintain the size and security of minimized code, without losing the ability to debug your application. - -For best results, uploading source maps should become a part of your deployment procedure, -and not something you only do when you see unhelpful errors. -That’s because uploading source maps after errors happen won’t make old errors magically readable -- -errors must occur again for source mapping to occur. - -The following APIs are available: - -* <> -* <> -* <> - -[float] -[[use-android-sourcemap-api]] -==== How to use APM APIs - -.Expand for required headers, privileges, and usage details -[%collapsible%closed] -====== -include::api.asciidoc[tag=using-the-APIs] -====== - -//// -******************************************************* -//// - -[[android-sourcemap-post]] -==== Create or update an Android source map - -Create or update an Android source map for a specific app and version. - -[[android-sourcemap-post-privs]] -===== Privileges - -The user accessing this endpoint requires `All` Kibana privileges for the {beat_kib_app} feature. -For more information, see <>. - -[[android-sourcemap-post-req]] -===== Request - -`POST /api/apm/androidmaps` - -[role="child_attributes"] -[[android-sourcemap-post-req-body]] -===== Request body - -`service_name`:: -(required, string) The name of the Android app that the map should apply to. - -`service_version`:: -(required, string) The version of the Android app that the map should apply to. - -`map_file`:: -(required, string or file upload) The R8-generated map. - -[[android-sourcemap-post-example]] -===== Examples - -The following example uploads a source map for a app named `foo` and a service version of `1.0.0`: - -[source,curl] --------------------------------------------------- -curl -X POST "http://localhost:5601/api/apm/androidmaps" \ --H 'Content-Type: multipart/form-data' \ --H 'kbn-xsrf: true' \ --H 'Authorization: ApiKey ${YOUR_API_KEY}' \ --F 'service_name="foo"' \ --F 'service_version="1.0.0"' \ --F 'map_file=@"/Path/to/the/file/mapping.txt"' --------------------------------------------------- - -[[android-sourcemap-post-body]] -===== Response body - -[source,js] --------------------------------------------------- -{ - "type": "sourcemap", - "identifier": "foo-1.0.0-android", - "relative_url": "/api/fleet/artifacts/foo-1.0.0-android/644fd5a997d1ddd90ee131ba18e2b3d03931d89dd1fe4599143c0b3264b3e456", - "body": "eJyFkL1OwzAUhd/Fc+MbYMuCEBIbHRjKgBgc96R16tiWr1OQqr47NwqJxEK3q/PzWccXxchnZ7E1A1SjuhjVZtF2yOxiEPlO17oWox3D3uPFeSRTjmJQARfCPeiAgGx8NTKsYdAc1T3rwaSJGcds8Sp3c1HnhfywUZ3QhMTFFGepZxqMC9oex3CS9tpk1XyozgOlmoVKuJX1DqEQZ0su7PGtLU+V/3JPKc3cL7TJ2FNDRPov4bFta3MDM4f7W69lpJjLO9qdK8bzVPhcJz3HUCQ4LbO/p5hCSC4cZPByrp/wFqOklbpefwAhzpqI", - "created": "2021-07-09T20:47:44.812Z", - "id": "apm:foo-1.0.0-android-644fd5a997d1ddd90ee131ba18e2b3d03931d89dd1fe4599143c0b3264b3e456", - "compressionAlgorithm": "zlib", - "decodedSha256": "644fd5a997d1ddd90ee131ba18e2b3d03931d89dd1fe4599143c0b3264b3e456", - "decodedSize": 441, - "encodedSha256": "024c72749c3e3dd411b103f7040ae62633558608f480bce4b108cf5b2275bd24", - "encodedSize": 237, - "encryptionAlgorithm": "none", - "packageName": "apm" -} --------------------------------------------------- - -//// -******************************************************* -//// - -[[android-sourcemap-get]] -==== Get source maps - -Returns an array of Fleet artifacts, including source map uploads. - -[[android-sourcemap-get-privs]] -===== Privileges - -The user accessing this endpoint requires `Read` or `All` Kibana privileges for the {beat_kib_app} feature. -For more information, see <>. - -[[android-sourcemap-get-req]] -===== Request - -`GET /api/apm/sourcemaps` - -[[android-sourcemap-get-example]] -===== Example - -The following example requests all uploaded source maps: - -[source,curl] --------------------------------------------------- -curl -X GET "http://localhost:5601/api/apm/sourcemaps" \ --H 'Content-Type: application/json' \ --H 'kbn-xsrf: true' \ --H 'Authorization: ApiKey ${YOUR_API_KEY}' --------------------------------------------------- - -[[android-sourcemap-get-body]] -===== Response body - -[source,js] --------------------------------------------------- -{ - "artifacts": [ - { - "type": "sourcemap", - "identifier": "foo-1.0.0-android", - "relative_url": "/api/fleet/artifacts/foo-1.0.0-android/644fd5a997d1ddd90ee131ba18e2b3d03931d89dd1fe4599143c0b3264b3e456", - "body": { - "serviceName": "foo", - "serviceVersion": "1.0.0", - "bundleFilepath": "android", - "sourceMap": "# compiler: R8\n# compiler_version: 3.2.47\n# min_api: 26\n..." - }, - "created": "2021-07-09T20:47:44.812Z", - "id": "apm:foo-1.0.0-android-644fd5a997d1ddd90ee131ba18e2b3d03931d89dd1fe4599143c0b3264b3e456", - "compressionAlgorithm": "zlib", - "decodedSha256": "644fd5a997d1ddd90ee131ba18e2b3d03931d89dd1fe4599143c0b3264b3e456", - "decodedSize": 441, - "encodedSha256": "024c72749c3e3dd411b103f7040ae62633558608f480bce4b108cf5b2275bd24", - "encodedSize": 237, - "encryptionAlgorithm": "none", - "packageName": "apm" - } - ] -} --------------------------------------------------- - -//// -******************************************************* -//// - -[[android-sourcemap-delete]] -==== Delete source map - -Delete a previously uploaded source map. - -[[android-sourcemap-delete-privs]] -===== Privileges - -The user accessing this endpoint requires `All` Kibana privileges for the {beat_kib_app} feature. -For more information, see <>. - -[[android-sourcemap-delete-req]] -===== Request - -`DELETE /api/apm/sourcemaps/:id` - -[[android-sourcemap-delete-example]] -===== Example - -The following example deletes a source map with an id of `apm:foo-1.0.0-android-644fd5a9`: - -[source,curl] --------------------------------------------------- -curl -X DELETE "http://localhost:5601/api/apm/sourcemaps/apm:foo-1.0.0-android-644fd5a9" \ --H 'Content-Type: application/json' \ --H 'kbn-xsrf: true' \ --H 'Authorization: ApiKey ${YOUR_API_KEY}' --------------------------------------------------- - -[[android-sourcemap-delete-body]] -===== Response body - -[source,js] --------------------------------------------------- -{} --------------------------------------------------- - -//// -******************************************************* -******************************************************* -//// - [role="xpack"] [[agent-key-api]] === APM agent Key API diff --git a/docs/concepts/data-views.asciidoc b/docs/concepts/data-views.asciidoc index 79aec68151d9a..c72679734b725 100644 --- a/docs/concepts/data-views.asciidoc +++ b/docs/concepts/data-views.asciidoc @@ -153,6 +153,10 @@ To exclude a cluster with the name `cluster_one`: Once you configure a {data-source} to use the {ccs} syntax, all searches and aggregations using that {data-source} in {kib} take advantage of {ccs}. +For more information, refer to +{ref}/modules-cross-cluster-search.html#exclude-problematic-clusters[Excluding +clusters or indicies from cross-cluster search]. + [float] [[delete-data-view]] === Delete a {data-source} diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index c48c7c8d17b43..9321e7499f9b4 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -697,6 +697,10 @@ Elastic. |Universal Profiling provides fleet-wide, whole-system, continuous profiling with zero instrumentation. Get a comprehensive understanding of what lines of code are consuming compute resources throughout your entire fleet by visualizing your data in Kibana using the flamegraph, stacktraces, and top functions views. +|{kib-repo}blob/{branch}/x-pack/plugins/profiling_data_access[profilingDataAccess] +|WARNING: Missing README. + + |{kib-repo}blob/{branch}/x-pack/plugins/remote_clusters/README.md[remoteClusters] |This plugin helps users manage their remote clusters, which enable cross-cluster search and cross-cluster replication. diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 5873af1ef9cb1..e0ddf9bd3f334 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -288,8 +288,8 @@ in the current data view is used. The columns that appear by default on the *Discover* page. The default is `_source`. -[[discover:enableSql]]`discover:enableSql`:: -experimental[] Allows SQL queries for search. +[[discover:enableESQL]]`discover:enableESQL`:: +experimental[] Allows ES|QL queries for search. [[discover-max-doc-fields-displayed]]`discover:maxDocFieldsDisplayed`:: Specifies the maximum number of fields to show in the document column of the *Discover* table. diff --git a/fleet_packages.json b/fleet_packages.json index 5ad9b3cff5830..a206560d48d80 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -24,7 +24,7 @@ [ { "name": "apm", - "version": "8.11.0-preview-1693211748", + "version": "8.11.0-preview-1693558513", "forceAlignStackVersion": true, "allowSyncToPrerelease": true }, @@ -54,7 +54,7 @@ }, { "name": "synthetics", - "version": "1.0.4" + "version": "1.0.6" }, { "name": "security_detection_engine", diff --git a/package.json b/package.json index 233826aacce77..06e36a7baf297 100644 --- a/package.json +++ b/package.json @@ -556,6 +556,7 @@ "@kbn/portable-dashboards-example": "link:examples/portable_dashboards_example", "@kbn/preboot-example-plugin": "link:examples/preboot_example", "@kbn/presentation-util-plugin": "link:src/plugins/presentation_util", + "@kbn/profiling-data-access-plugin": "link:x-pack/plugins/profiling_data_access", "@kbn/profiling-plugin": "link:x-pack/plugins/profiling", "@kbn/random-sampling": "link:x-pack/packages/kbn-random-sampling", "@kbn/react-field": "link:packages/kbn-react-field", @@ -742,6 +743,7 @@ "@kbn/ui-shared-deps-npm": "link:packages/kbn-ui-shared-deps-npm", "@kbn/ui-shared-deps-src": "link:packages/kbn-ui-shared-deps-src", "@kbn/ui-theme": "link:packages/kbn-ui-theme", + "@kbn/unified-data-table": "link:packages/kbn-unified-data-table", "@kbn/unified-doc-viewer": "link:packages/kbn-unified-doc-viewer", "@kbn/unified-doc-viewer-examples": "link:examples/unified_doc_viewer", "@kbn/unified-doc-viewer-plugin": "link:src/plugins/unified_doc_viewer", @@ -1073,6 +1075,7 @@ "@elastic/synthetics": "^1.3.0", "@emotion/babel-preset-css-prop": "^11.11.0", "@emotion/jest": "^11.11.0", + "@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", diff --git a/packages/core/http/core-http-router-server-internal/src/router.ts b/packages/core/http/core-http-router-server-internal/src/router.ts index 617c810109138..c265a7590d958 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.ts @@ -199,26 +199,38 @@ export class Router( setSpacesExtension: deps.savedObjects.setSpacesExtension, registerType: deps.savedObjects.registerType, getDefaultIndex: deps.savedObjects.getDefaultIndex, - getAllIndices: deps.savedObjects.getAllIndices, }, status: { core$: deps.status.core$, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts index 9989b4264f28f..e7bd523c0e741 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/index.ts @@ -23,6 +23,10 @@ export { type IPreflightCheckHelper, type PreflightCheckNamespacesParams, type PreflightCheckNamespacesResult, + type PreflightDocParams, + type PreflightDocResult, + type PreflightNSParams, + type PreflightNSResult, } from './preflight_check'; export interface RepositoryHelpers { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/preflight_check.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/preflight_check.ts index 5cf2bfbf21d99..1e39761d99d6e 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/preflight_check.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/helpers/preflight_check.ts @@ -117,7 +117,6 @@ export class PreflightCheckHelper { if (!this.registry.isMultiNamespace(type)) { throw new Error(`Cannot make preflight get request for non-multi-namespace type '${type}'.`); } - const { body, statusCode, headers } = await this.client.get( { id: this.serializer.generateRawId(undefined, type, id), @@ -151,8 +150,83 @@ export class PreflightCheckHelper { }; } + /** + * Pre-flight check fetching the document regardless of its namespace type for update. + */ + public async preflightGetDocForUpdate({ + type, + id, + namespace, + }: PreflightDocParams): Promise { + const { statusCode, body, headers } = await this.client.get( + { + id: this.serializer.generateRawId(namespace, type, id), + index: this.getIndexForType(type), + }, + { ignore: [404], meta: true } + ); + + // checking if the 404 is from Elasticsearch + if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { + throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(type, id); + } + + const indexFound = statusCode !== 404; + if (indexFound && isFoundGetResponse(body)) { + return { + checkDocFound: 'found', + rawDocSource: body, + }; + } + + return { + checkDocFound: 'not_found', + }; + } + + /** + * Pre-flight check to ensure that a multi-namespace object exists in the current namespace for update API. + */ + public preflightCheckNamespacesForUpdate({ + type, + namespace, + initialNamespaces, + preflightDocResult, + }: PreflightNSParams): PreflightNSResult { + const { checkDocFound, rawDocSource } = preflightDocResult; + if (!this.registry.isMultiNamespace(type)) { + return { + checkSkipped: true, + }; + } + + const namespaces = initialNamespaces ?? [SavedObjectsUtils.namespaceIdToString(namespace)]; + + if (checkDocFound === 'found' && rawDocSource !== undefined) { + if (!rawDocExistsInNamespaces(this.registry, rawDocSource, namespaces)) { + return { checkResult: 'found_outside_namespace', checkSkipped: false }; + } + return { + checkResult: 'found_in_namespace', + savedObjectNamespaces: + initialNamespaces ?? getSavedObjectNamespaces(namespace, rawDocSource), + rawDocSource, + checkSkipped: false, + }; + } + + return { + checkResult: 'not_found', + savedObjectNamespaces: initialNamespaces ?? getSavedObjectNamespaces(namespace), + checkSkipped: false, + }; + } + /** * Pre-flight check to ensure that an upsert which would create a new object does not result in an alias conflict. + * + * If an upsert would result in the creation of a new object, we need to check for alias conflicts too. + * This takes an extra round trip to Elasticsearch, but this won't happen often. */ public async preflightCheckForUpsertAliasConflict( type: string, @@ -189,6 +263,39 @@ export interface PreflightCheckNamespacesParams { initialNamespaces?: string[]; } +/** + * @internal + */ +export interface PreflightNSParams { + /** The object type to fetch */ + type: string; + /** The object ID to fetch */ + id: string; + /** The current space */ + namespace: string | undefined; + /** Optional; for an object that is being created, this specifies the initial namespace(s) it will exist in (overriding the current space) */ + initialNamespaces?: string[]; + /** Optional; for a pre-fetched object */ + preflightDocResult: PreflightDocResult; +} + +/** + * @internal + */ +export interface PreflightNSResult { + /** If the object exists, and whether or not it exists in the current space */ + checkResult?: 'not_found' | 'found_in_namespace' | 'found_outside_namespace'; + /** + * What namespace(s) the object should exist in, if it needs to be created; practically speaking, this will never be undefined if + * checkResult == not_found or checkResult == found_in_namespace + */ + savedObjectNamespaces?: string[]; + /** The source of the raw document, if the object already exists */ + rawDocSource?: GetResponseFound; + /** Indicates if the namespaces check is called or not. Non-multinamespace types are not shareable */ + checkSkipped?: boolean; +} + /** * @internal */ @@ -203,3 +310,30 @@ export interface PreflightCheckNamespacesResult { /** The source of the raw document, if the object already exists */ rawDocSource?: GetResponseFound; } + +/** + * @internal + */ +export interface PreflightDocParams { + /** The object type to fetch */ + type: string; + /** The object ID to fetch */ + id: string; + /** The current space */ + namespace: string | undefined; + /** + * optional migration version compatibility. + * {@link SavedObjectsRawDocParseOptions.migrationVersionCompatibility} + */ + migrationVersionCompatibility?: 'compatible' | 'raw'; +} + +/** + * @internal + */ +export interface PreflightDocResult { + /** If the object exists, and whether or not it exists in the current space */ + checkDocFound: 'not_found' | 'found'; + /** The source of the raw document, if the object already exists in the server's version (unsafe to use) */ + rawDocSource?: GetResponseFound; +} diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.test.ts new file mode 100644 index 0000000000000..dd5c51c6b433d --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.test.ts @@ -0,0 +1,741 @@ +/* + * Copyright 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 @typescript-eslint/no-shadow */ + +import { mockGetCurrentTime, mockPreflightCheckForCreate } from '../repository.test.mock'; + +import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + type SavedObjectUnsanitizedDoc, + type SavedObjectReference, + SavedObjectsRawDocSource, + SavedObjectsErrorHelpers, +} from '@kbn/core-saved-objects-server'; +import { ALL_NAMESPACES_STRING } from '@kbn/core-saved-objects-utils-server'; +import { SavedObjectsRepository } from '../repository'; +import { loggerMock } from '@kbn/logging-mocks'; +import { + SavedObjectsSerializer, + encodeHitVersion, +} from '@kbn/core-saved-objects-base-server-internal'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { kibanaMigratorMock } from '../../mocks'; +import { + NAMESPACE_AGNOSTIC_TYPE, + MULTI_NAMESPACE_ISOLATED_TYPE, + HIDDEN_TYPE, + mockVersionProps, + mockTimestampFields, + mockTimestamp, + mappings, + mockVersion, + createRegistry, + createDocumentMigrator, + getMockGetResponse, + createSpySerializer, + createBadRequestErrorPayload, + createConflictErrorPayload, + createGenericNotFoundErrorPayload, + updateSuccess, +} from '../../test_helpers/repository.test.common'; + +describe('SavedObjectsRepository', () => { + let client: ReturnType; + let repository: SavedObjectsRepository; + let migrator: ReturnType; + let logger: ReturnType; + let serializer: jest.Mocked; + + const registry = createRegistry(); + const documentMigrator = createDocumentMigrator(registry); + + const expectMigrationArgs = (args: unknown, contains = true, n = 1) => { + const obj = contains ? expect.objectContaining(args) : expect.not.objectContaining(args); + expect(migrator.migrateDocument).toHaveBeenNthCalledWith( + n, + obj, + expect.objectContaining({ + allowDowngrade: expect.any(Boolean), + }) + ); + }; + + beforeEach(() => { + client = elasticsearchClientMock.createElasticsearchClient(); + migrator = kibanaMigratorMock.create(); + documentMigrator.prepareMigrations(); + migrator.migrateDocument = jest.fn().mockImplementation(documentMigrator.migrate); + migrator.runMigrations = jest.fn().mockResolvedValue([{ status: 'skipped' }]); + logger = loggerMock.create(); + + // create a mock serializer "shim" so we can track function calls, but use the real serializer's implementation + serializer = createSpySerializer(registry); + + const allTypes = registry.getAllTypes().map((type) => type.name); + const allowedTypes = [...new Set(allTypes.filter((type) => !registry.isHidden(type)))]; + + // @ts-expect-error must use the private constructor to use the mocked serializer + repository = new SavedObjectsRepository({ + index: '.kibana-test', + mappings, + client, + migrator, + typeRegistry: registry, + serializer, + allowedTypes, + logger, + }); + + mockGetCurrentTime.mockReturnValue(mockTimestamp); + }); + + describe('#update', () => { + const id = 'logstash-*'; + const type = 'index-pattern'; + const attributes = { title: 'Testing' }; + const namespace = 'foo-namespace'; + const references = [ + { + name: 'ref_0', + type: 'test', + id: '1', + }, + ]; + const originId = 'some-origin-id'; + const mockMigrationVersion = { foo: '2.3.4' }; + const mockMigrateDocumentForUpdate = (doc: SavedObjectUnsanitizedDoc) => { + const response = { + ...doc, + attributes: { + ...doc.attributes, + ...(doc.attributes?.title && { title: `${doc.attributes.title}!!` }), + }, + migrationVersion: mockMigrationVersion, + managed: doc.managed ?? false, + references: doc.references || [ + { + name: 'ref_0', + type: 'test', + id: '1', + }, + ], + }; + return response; + }; + + beforeEach(() => { + mockPreflightCheckForCreate.mockReset(); + mockPreflightCheckForCreate.mockImplementation(({ objects }) => { + return Promise.resolve(objects.map(({ type, id }) => ({ type, id }))); // respond with no errors by default + }); + client.create.mockResponseImplementation((params) => { + return { + body: { + _id: params.id, + ...mockVersionProps, + } as estypes.CreateResponse, + }; + }); + }); + + describe('client calls', () => { + it(`should use the ES get action then index action when type is not multi-namespace for existing objects`, async () => { + const type = 'index-pattern'; + const id = 'logstash-*'; + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, type, id, attributes, { namespace }); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.index).toHaveBeenCalledTimes(1); + }); + + it(`should use the ES get action then index action when type is multi-namespace for existing objects`, async () => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes + ); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.index).toHaveBeenCalledTimes(1); + }); + + it(`should use the ES get action then index action when type is namespace agnostic for existing objects`, async () => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, NAMESPACE_AGNOSTIC_TYPE, id, attributes); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.index).toHaveBeenCalledTimes(1); + }); + + it(`should check for alias conflicts if a new multi-namespace object before create action would be created then create action to create the object`, async () => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { upsert: true }, + { mockGetResponseAsNotFound: { found: false } as estypes.GetResponse } + ); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.create).toHaveBeenCalledTimes(1); + }); + + it(`defaults to empty array with no input references`, async () => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, type, id, attributes); + expect( + (client.index.mock.calls[0][0] as estypes.CreateRequest).body! + .references + ).toEqual([]); // we're indexing a full new doc, serializer adds default if not defined + }); + + it(`accepts custom references array 1`, async () => { + const test = async (references: SavedObjectReference[]) => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, type, id, attributes, { + references, + }); + expect( + (client.index.mock.calls[0][0] as estypes.CreateRequest).body! + .references + ).toEqual(references); + client.index.mockClear(); + }; + await test(references); + }); + it(`accepts custom references array 2`, async () => { + const test = async (references: SavedObjectReference[]) => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, type, id, attributes, { + references, + }); + expect( + (client.index.mock.calls[0][0] as estypes.CreateRequest).body! + .references + ).toEqual(references); + client.index.mockClear(); + }; + await test([{ type: 'foo', id: '42', name: 'some ref' }]); + }); + it(`accepts custom references array 3`, async () => { + const test = async (references: SavedObjectReference[]) => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, type, id, attributes, { + references, + }); + expect( + (client.index.mock.calls[0][0] as estypes.CreateRequest).body! + .references + ).toEqual(references); + client.index.mockClear(); + }; + await test([]); + }); + + it(`uses the 'upsertAttributes' option when specified for a single-namespace type that does not exist`, async () => { + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess( + client, + repository, + registry, + type, + id, + attributes, + { + upsert: { + title: 'foo', + description: 'bar', + }, + }, + { mockGetResponseAsNotFound: { found: false } as estypes.GetResponse } + ); + + const expected = { + 'index-pattern': { description: 'bar', title: 'foo' }, + type: 'index-pattern', + ...mockTimestampFields, + }; + expect( + (client.create.mock.calls[0][0] as estypes.CreateRequest).body! + ).toEqual(expected); + }); + + it(`uses the 'upsertAttributes' option when specified for a multi-namespace type that does not exist`, async () => { + const options = { upsert: { title: 'foo', description: 'bar' } }; + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { + upsert: { + title: 'foo', + description: 'bar', + }, + }, + { + mockGetResponseAsNotFound: { found: false } as estypes.GetResponse, + } + ); + await repository.update(MULTI_NAMESPACE_ISOLATED_TYPE, id, attributes, options); + expect(client.get).toHaveBeenCalledTimes(2); + const expectedType = { + multiNamespaceIsolatedType: { description: 'bar', title: 'foo' }, + namespaces: ['default'], + type: 'multiNamespaceIsolatedType', + ...mockTimestampFields, + }; + expect( + (client.create.mock.calls[0][0] as estypes.CreateRequest).body! + ).toEqual(expectedType); + }); + + it(`ignores the 'upsertAttributes' option when specified for a multi-namespace type that already exists`, async () => { + // attributes don't change + const options = { upsert: { title: 'foo', description: 'bar' } }; + migrator.migrateDocument.mockImplementation((doc) => ({ ...doc, migrated: true })); + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + options + ); + await repository.update(MULTI_NAMESPACE_ISOLATED_TYPE, id, attributes, options); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ + id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`, + index: '.kibana-test_8.0.0-testing', + refresh: 'wait_for', + require_alias: true, + body: expect.objectContaining({ + multiNamespaceIsolatedType: { title: 'Testing' }, + namespaces: ['default'], + references: [], + type: 'multiNamespaceIsolatedType', + ...mockTimestampFields, + }), + }), + expect.anything() + ); + }); + + it(`doesn't accept custom references if not an array`, async () => { + const test = async (references: unknown) => { + migrator.migrateDocument.mockImplementation(mockMigrateDocumentForUpdate); + await updateSuccess(client, repository, registry, type, id, attributes, { + // @ts-expect-error references is unknown + references, + }); + expect( + (client.index.mock.calls[0][0] as estypes.CreateRequest).body! + .references + ).toEqual([]); + client.index.mockClear(); + client.create.mockClear(); + }; + await test('string'); + await test(123); + await test(true); + await test(null); + }); + + it(`defaults to a refresh setting of wait_for`, async () => { + migrator.migrateDocument.mockImplementation(mockMigrateDocumentForUpdate); + await updateSuccess(client, repository, registry, type, id, { foo: 'bar' }); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ + refresh: 'wait_for', + }), + expect.anything() + ); + }); + + it(`defaults to the version of the existing document when type is multi-namespace`, async () => { + migrator.migrateDocument.mockImplementation(mockMigrateDocumentForUpdate); + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { references } + ); + const versionProperties = { + if_seq_no: mockVersionProps._seq_no, + if_primary_term: mockVersionProps._primary_term, + }; + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining(versionProperties), + expect.anything() + ); + }); + + it(`accepts version`, async () => { + migrator.migrateDocument.mockImplementation(mockMigrateDocumentForUpdate); + await updateSuccess(client, repository, registry, type, id, attributes, { + version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }), + }); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ if_seq_no: 100, if_primary_term: 200 }), + expect.anything() + ); + }); + + it('retries the operation in case of conflict error', async () => { + client.get.mockResponse(getMockGetResponse(registry, { type, id })); + + client.index + .mockImplementationOnce(() => { + throw SavedObjectsErrorHelpers.createConflictError(type, id, 'conflict'); + }) + .mockImplementationOnce(() => { + throw SavedObjectsErrorHelpers.createConflictError(type, id, 'conflict'); + }) + .mockResponseImplementation((params) => { + return { + body: { + _id: params.id, + _seq_no: 1, + _primary_term: 1, + }, + } as any; + }); + + await repository.update(type, id, attributes, { retryOnConflict: 3 }); + + expect(client.get).toHaveBeenCalledTimes(3); + expect(client.index).toHaveBeenCalledTimes(3); + }); + + it('retries the operation a maximum of `retryOnConflict` times', async () => { + client.get.mockResponse(getMockGetResponse(registry, { type, id })); + + client.index.mockImplementation(() => { + throw SavedObjectsErrorHelpers.createConflictError(type, id, 'conflict'); + }); + + await expect( + repository.update(type, id, attributes, { retryOnConflict: 3 }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Saved object [index-pattern/logstash-*] conflict"` + ); + + expect(client.get).toHaveBeenCalledTimes(4); + expect(client.index).toHaveBeenCalledTimes(4); + }); + + it('default to a `retry_on_conflict` setting of `0` when `version` is provided', async () => { + client.get.mockResponse(getMockGetResponse(registry, { type, id })); + + client.index.mockImplementation(() => { + throw SavedObjectsErrorHelpers.createConflictError(type, id, 'conflict'); + }); + + await expect( + repository.update(type, id, attributes, { + version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }), + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Saved object [index-pattern/logstash-*] conflict"` + ); + + expect(client.get).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); + }); + + it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { + await updateSuccess(client, repository, registry, type, id, attributes, { namespace }); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ id: expect.stringMatching(`${namespace}:${type}:${id}`) }), // namespace expected: globalType + expect.anything() + ); + }); + + it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => { + await updateSuccess(client, repository, registry, type, id, attributes, { references }); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ id: expect.stringMatching(`${type}:${id}`) }), + expect.anything() + ); + }); + + it(`normalizes options.namespace from 'default' to undefined`, async () => { + await updateSuccess(client, repository, registry, type, id, attributes, { + references, + namespace: 'default', + }); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ id: expect.stringMatching(`${type}:${id}`) }), + expect.anything() + ); + }); + + it(`doesn't prepend namespace to the id when using agnostic-namespace type`, async () => { + await updateSuccess(client, repository, registry, NAMESPACE_AGNOSTIC_TYPE, id, attributes, { + namespace, + }); + + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ + id: expect.stringMatching(`${NAMESPACE_AGNOSTIC_TYPE}:${id}`), + }), + expect.anything() + ); + }); + + it(`doesn't prepend namespace to the id when using multi-namespace type`, async () => { + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { namespace } + ); + expect(client.index).toHaveBeenCalledWith( + expect.objectContaining({ + id: expect.stringMatching(`${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`), + }), + expect.anything() + ); + }); + }); + + describe('errors', () => { + const expectNotFoundError = async (type: string, id: string) => { + await expect( + repository.update(type, id, {}, { migrationVersionCompatibility: 'raw' }) + ).rejects.toThrowError(createGenericNotFoundErrorPayload(type, id)); + }; + + it(`throws when options.namespace is '*'`, async () => { + await expect( + repository.update(type, id, attributes, { namespace: ALL_NAMESPACES_STRING }) + ).rejects.toThrowError(createBadRequestErrorPayload('"options.namespace" cannot be "*"')); + }); + + it(`throws when type is invalid`, async () => { + await expectNotFoundError('unknownType', id); + expect(client.index).not.toHaveBeenCalled(); + }); + + it(`throws when type is hidden`, async () => { + await expectNotFoundError(HIDDEN_TYPE, id); + expect(client.index).not.toHaveBeenCalled(); + }); + + it(`throws when id is empty`, async () => { + await expect(repository.update(type, '', attributes)).rejects.toThrowError( + createBadRequestErrorPayload('id cannot be empty') + ); + expect(client.index).not.toHaveBeenCalled(); + }); + + it(`throws when ES is unable to find the document during get`, async () => { + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + { found: false } as estypes.GetResponse, + undefined + ) + ); + await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id); + expect(client.get).toHaveBeenCalledTimes(1); + }); + + it(`throws when ES is unable to find the index during get`, async () => { + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({} as estypes.GetResponse, { + statusCode: 404, + }) + ); + await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id); + expect(client.get).toHaveBeenCalledTimes(1); + }); + + it(`throws when type is multi-namespace and the document exists, but not in this namespace`, async () => { + const response = getMockGetResponse( + registry, + { type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, + namespace + ); + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(response) + ); + await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id); + expect(client.get).toHaveBeenCalledTimes(1); + }); + + it(`throws when there is an alias conflict from preflightCheckForCreate`, async () => { + client.get.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + found: false, + } as estypes.GetResponse) + ); + mockPreflightCheckForCreate.mockResolvedValue([ + { type: 'type', id: 'id', error: { type: 'aliasConflict' } }, + ]); + await expect( + repository.update( + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + { attr: 'value' }, + { + upsert: { + upsertAttr: 'val', + attr: 'value', + }, + } + ) + ).rejects.toThrowError(createConflictErrorPayload(MULTI_NAMESPACE_ISOLATED_TYPE, id)); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.index).not.toHaveBeenCalled(); + }); + + it(`does not throw when there is a different error from preflightCheckForCreate`, async () => { + mockPreflightCheckForCreate.mockResolvedValue([ + { type: 'type', id: 'id', error: { type: 'conflict' } }, + ]); + await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes, + { upsert: true }, + { mockGetResponseAsNotFound: { found: false } as estypes.GetResponse } + ); + expect(client.get).toHaveBeenCalledTimes(1); + expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); + expect(client.create).toHaveBeenCalledTimes(1); + }); + + it(`does not throw when the document does not exist`, async () => { + expect(client.create).not.toHaveBeenCalled(); + await expectNotFoundError(type, id); + }); + }); + + describe('migration', () => { + it('migrates the fetched document from get', async () => { + const type = 'index-pattern'; + const id = 'logstash-*'; + migrator.migrateDocument.mockImplementationOnce((doc) => ({ ...doc, migrated: true })); + await updateSuccess(client, repository, registry, type, id, attributes); + expect(migrator.migrateDocument).toHaveBeenCalledTimes(2); + expectMigrationArgs({ + id, + type, + }); + }); + + it('migrates the input arguments when upsert is used', async () => { + const options = { + upsert: { + title: 'foo', + description: 'bar', + }, + }; + const internalOptions = { + mockGetResponseAsNotFound: { found: false } as estypes.GetResponse, + }; + await updateSuccess( + client, + repository, + registry, + type, + id, + attributes, + options, + internalOptions + ); + expect(migrator.migrateDocument).toHaveBeenCalledTimes(1); + expectMigrationArgs({ + id, + type, + }); + }); + }); + + describe('returns', () => { + it(`returns _seq_no and _primary_term encoded as version`, async () => { + const result = await updateSuccess(client, repository, registry, type, id, attributes, { + namespace, + references, + }); + expect(result).toEqual({ + id, + type, + ...mockTimestampFields, + version: mockVersion, + attributes, + references, + namespaces: [namespace], + }); + }); + + it(`includes namespaces if type is multi-namespace`, async () => { + const result = await updateSuccess( + client, + repository, + registry, + MULTI_NAMESPACE_ISOLATED_TYPE, + id, + attributes + ); + expect(result).toMatchObject({ + namespaces: expect.any(Array), + }); + }); + + it(`includes namespaces if type is not multi-namespace`, async () => { + const result = await updateSuccess(client, repository, registry, type, id, attributes); + expect(result).toMatchObject({ + namespaces: ['default'], + }); + }); + + it(`includes originId property if present in cluster call response`, async () => { + const result = await updateSuccess( + client, + repository, + registry, + type, + id, + attributes, + {}, + { originId } + ); + expect(result).toMatchObject({ originId }); + }); + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts index 27f3d45c642de..e119d6e6303db 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/update.ts @@ -10,19 +10,21 @@ import { SavedObjectsErrorHelpers, type SavedObject, type SavedObjectSanitizedDoc, - SavedObjectsRawDoc, - SavedObjectsRawDocSource, } from '@kbn/core-saved-objects-server'; import { SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server'; -import { encodeHitVersion } from '@kbn/core-saved-objects-base-server-internal'; import { + decodeRequestVersion, + encodeHitVersion, +} from '@kbn/core-saved-objects-base-server-internal'; +import type { SavedObjectsUpdateOptions, SavedObjectsUpdateResponse, } from '@kbn/core-saved-objects-api-server'; +import { isNotFoundFromUnsupportedServer } from '@kbn/core-elasticsearch-server-internal'; import { DEFAULT_REFRESH_SETTING, DEFAULT_RETRY_COUNT } from '../constants'; -import { getCurrentTime, getExpectedVersionProperties } from './utils'; -import { ApiExecutionContext } from './types'; -import { PreflightCheckNamespacesResult } from './helpers'; +import { isValidRequest } from '../utils'; +import { getCurrentTime, getSavedObjectFromSource, mergeForUpdate } from './utils'; +import type { ApiExecutionContext } from './types'; export interface PerformUpdateParams { type: string; @@ -32,84 +34,141 @@ export interface PerformUpdateParams { } export const performUpdate = async ( + updateParams: PerformUpdateParams, + apiContext: ApiExecutionContext +): Promise> => { + const { type, id, options } = updateParams; + const { allowedTypes, helpers } = apiContext; + const namespace = helpers.common.getCurrentNamespace(options.namespace); + + // check request is valid + const { validRequest, error } = isValidRequest({ allowedTypes, type, id }); + if (!validRequest && error) { + throw error; + } + + const maxAttempts = options.version ? 1 : 1 + DEFAULT_RETRY_COUNT; + + // handle retryOnConflict manually by reattempting the operation in case of conflict errors + let response: SavedObjectsUpdateResponse; + for (let currentAttempt = 1; currentAttempt <= maxAttempts; currentAttempt++) { + try { + response = await executeUpdate(updateParams, apiContext, { namespace }); + break; + } catch (e) { + if ( + SavedObjectsErrorHelpers.isConflictError(e) && + e.retryableConflict && + currentAttempt < maxAttempts + ) { + continue; + } + throw e; + } + } + + return response!; +}; + +export const executeUpdate = async ( { id, type, attributes, options }: PerformUpdateParams, - { - registry, - helpers, - allowedTypes, - client, - serializer, - migrator, - extensions = {}, - }: ApiExecutionContext + { registry, helpers, client, serializer, extensions = {}, logger }: ApiExecutionContext, + { namespace }: { namespace: string | undefined } ): Promise> => { const { common: commonHelper, encryption: encryptionHelper, preflight: preflightHelper, migration: migrationHelper, + validation: validationHelper, } = helpers; const { securityExtension } = extensions; - const namespace = commonHelper.getCurrentNamespace(options.namespace); - if (!allowedTypes.includes(type)) { - throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); - } - if (!id) { - throw SavedObjectsErrorHelpers.createBadRequestError('id cannot be empty'); // prevent potentially upserting a saved object with an empty ID - } - const { version, references, upsert, refresh = DEFAULT_REFRESH_SETTING, - retryOnConflict = version ? 0 : DEFAULT_RETRY_COUNT, + migrationVersionCompatibility, } = options; - let preflightResult: PreflightCheckNamespacesResult | undefined; - if (registry.isMultiNamespace(type)) { - preflightResult = await preflightHelper.preflightCheckNamespaces({ - type, - id, - namespace, - }); - } + // Preflight calls to get the doc and check namespaces for multinamespace types. + const preflightDocResult = await preflightHelper.preflightGetDocForUpdate({ + type, + id, + namespace, + }); - const existingNamespaces = preflightResult?.savedObjectNamespaces ?? []; + const preflightDocNSResult = preflightHelper.preflightCheckNamespacesForUpdate({ + type, + id, + namespace, + preflightDocResult, + }); + const existingNamespaces = preflightDocNSResult?.savedObjectNamespaces ?? []; const authorizationResult = await securityExtension?.authorizeUpdate({ namespace, object: { type, id, existingNamespaces }, }); - if ( - preflightResult?.checkResult === 'found_outside_namespace' || - (!upsert && preflightResult?.checkResult === 'not_found') - ) { + // validate if an update (directly update or create the object instead) can be done, based on if the doc exists or not + const docOutsideNamespace = preflightDocNSResult?.checkResult === 'found_outside_namespace'; + const docNotFound = + preflightDocNSResult?.checkResult === 'not_found' || + preflightDocResult.checkDocFound === 'not_found'; + + // doc not in namespace, or doc not found but we're not upserting => throw 404 + if (docOutsideNamespace || (docNotFound && !upsert)) { throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); } - if (upsert && preflightResult?.checkResult === 'not_found') { - // If an upsert would result in the creation of a new object, we need to check for alias conflicts too. - // This takes an extra round trip to Elasticsearch, but this won't happen often. - // TODO: improve performance by combining these into a single preflight check + + if (upsert && preflightDocNSResult?.checkResult === 'not_found') { + // we only need to check multi-namespace objects. Single and agnostic types do not have aliases. + // throws SavedObjectsErrorHelpers.createConflictError(type, id) if there is one await preflightHelper.preflightCheckForUpsertAliasConflict(type, id, namespace); } + + // migrate the existing doc to the current version + let migrated: SavedObject; + if (preflightDocResult.checkDocFound === 'found') { + const document = getSavedObjectFromSource( + registry, + type, + id, + preflightDocResult.rawDocSource!, + { migrationVersionCompatibility } + ); + try { + migrated = migrationHelper.migrateStorageDocument(document) as SavedObject; + } catch (migrateStorageDocError) { + throw SavedObjectsErrorHelpers.decorateGeneralError( + migrateStorageDocError, + 'Failed to migrate document to the latest version.' + ); + } + } + // END ALL PRE_CLIENT CALL CHECKS && MIGRATE EXISTING DOC; + const time = getCurrentTime(); + let updatedOrCreatedSavedObject: SavedObject; + // `upsert` option set and document was not found -> we need to perform an upsert operation + const shouldPerformUpsert = upsert && docNotFound; - let rawUpsert: SavedObjectsRawDoc | undefined; - // don't include upsert if the object already exists; ES doesn't allow upsert in combination with version properties - if (upsert && (!preflightResult || preflightResult.checkResult === 'not_found')) { - let savedObjectNamespace: string | undefined; - let savedObjectNamespaces: string[] | undefined; + let savedObjectNamespace: string | undefined; + let savedObjectNamespaces: string[] | undefined; - if (registry.isSingleNamespace(type) && namespace) { - savedObjectNamespace = namespace; - } else if (registry.isMultiNamespace(type)) { - savedObjectNamespaces = preflightResult!.savedObjectNamespaces; - } + if (namespace && registry.isSingleNamespace(type)) { + savedObjectNamespace = namespace; + } else if (registry.isMultiNamespace(type)) { + savedObjectNamespaces = preflightDocNSResult.savedObjectNamespaces; + } - const migrated = migrationHelper.migrateInputDocument({ + // UPSERT CASE START + if (shouldPerformUpsert) { + // ignore attributes if creating a new doc: only use the upsert attributes + // don't include upsert if the object already exists; ES doesn't allow upsert in combination with version properties + const migratedUpsert = migrationHelper.migrateInputDocument({ id, type, ...(savedObjectNamespace && { namespace: savedObjectNamespace }), @@ -118,31 +177,111 @@ export const performUpdate = async ( ...(await encryptionHelper.optionallyEncryptAttributes(type, id, namespace, upsert)), }, updated_at: time, + ...(Array.isArray(references) && { references }), + }) as SavedObjectSanitizedDoc; + validationHelper.validateObjectForCreate(type, migratedUpsert); + const rawUpsert = serializer.savedObjectToRaw(migratedUpsert); + + const createRequestParams = { + id: rawUpsert._id, + index: commonHelper.getIndexForType(type), + refresh, + body: rawUpsert._source, + ...(version ? decodeRequestVersion(version) : {}), + require_alias: true, + }; + + const { + body: createDocResponseBody, + statusCode, + headers, + } = await client.create(createRequestParams, { meta: true }).catch((err) => { + if (SavedObjectsErrorHelpers.isEsUnavailableError(err)) { + throw err; + } + if (SavedObjectsErrorHelpers.isNotFoundError(err)) { + // see "404s from missing index" above + throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); + } + if (SavedObjectsErrorHelpers.isConflictError(err)) { + // flag the error as being caused by an update conflict + err.retryableConflict = true; + } + throw err; }); - rawUpsert = serializer.savedObjectToRaw(migrated as SavedObjectSanitizedDoc); - } + if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { + throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(id, type); + } + // client.create doesn't return the index document. + // Use rawUpsert as the _source + const upsertedSavedObject = serializer.rawToSavedObject( + { + ...rawUpsert, + ...createDocResponseBody, + }, + { migrationVersionCompatibility } + ); + const { originId } = upsertedSavedObject ?? {}; + let namespaces: string[] = []; + if (!registry.isNamespaceAgnostic(type)) { + namespaces = upsertedSavedObject.namespaces ?? [ + SavedObjectsUtils.namespaceIdToString(upsertedSavedObject.namespace), + ]; + } - const doc = { - [type]: await encryptionHelper.optionallyEncryptAttributes(type, id, namespace, attributes), - updated_at: time, - ...(Array.isArray(references) && { references }), - }; + updatedOrCreatedSavedObject = { + id, + type, + updated_at: time, + version: encodeHitVersion(createDocResponseBody), + namespaces, + ...(originId && { originId }), + references, + attributes: upsert, // these ignore the attribute values provided in the main request body. + } as SavedObject; - const body = await client - .update({ - id: serializer.generateRawId(namespace, type, id), + // UPSERT CASE END + } else { + // UPDATE CASE START + // at this point, we already know 1. the document exists 2. we're not doing an upsert + // therefor we can safely process with the "standard" update sequence. + + const updatedAttributes = mergeForUpdate( + { ...migrated!.attributes }, + await encryptionHelper.optionallyEncryptAttributes(type, id, namespace, attributes) + ); + const migratedUpdatedSavedObjectDoc = migrationHelper.migrateInputDocument({ + ...migrated!, + id, + type, + // need to override the redacted NS values from the decrypted/migrated document + namespace: savedObjectNamespace, + namespaces: savedObjectNamespaces, + attributes: updatedAttributes, + updated_at: time, + ...(Array.isArray(references) && { references }), + }); + + const docToSend = serializer.savedObjectToRaw( + migratedUpdatedSavedObjectDoc as SavedObjectSanitizedDoc + ); + + // implement creating the call params + const indexRequestParams = { + id: docToSend._id, index: commonHelper.getIndexForType(type), - ...getExpectedVersionProperties(version), refresh, - retry_on_conflict: retryOnConflict, - body: { - doc, - ...(rawUpsert && { upsert: rawUpsert._source }), - }, - _source_includes: ['namespace', 'namespaces', 'originId'], + body: docToSend._source, + // using version from the source doc if not provided as option to avoid erasing changes in case of concurrent calls + ...decodeRequestVersion(version || migrated!.version), require_alias: true, - }) - .catch((err) => { + }; + + const { + body: indexDocResponseBody, + statusCode, + headers, + } = await client.index(indexRequestParams, { meta: true }).catch((err) => { if (SavedObjectsErrorHelpers.isEsUnavailableError(err)) { throw err; } @@ -150,31 +289,50 @@ export const performUpdate = async ( // see "404s from missing index" above throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id); } + if (SavedObjectsErrorHelpers.isConflictError(err)) { + // flag the error as being caused by an update conflict + err.retryableConflict = true; + } throw err; }); + // throw if we can't verify a 404 response is from Elasticsearch + if (isNotFoundFromUnsupportedServer({ statusCode, headers })) { + throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(id, type); + } + // client.index doesn't return the indexed document. + // Rather than making another round trip to elasticsearch to fetch the doc, we use the SO we sent + // rawToSavedObject adds references as [] if undefined + const updatedSavedObject = serializer.rawToSavedObject( + { + ...docToSend, + ...indexDocResponseBody, + }, + { migrationVersionCompatibility } + ); - const { originId } = body.get?._source ?? {}; - let namespaces: string[] = []; - if (!registry.isNamespaceAgnostic(type)) { - namespaces = body.get?._source.namespaces ?? [ - SavedObjectsUtils.namespaceIdToString(body.get?._source.namespace), - ]; - } + const { originId } = updatedSavedObject ?? {}; + let namespaces: string[] = []; + if (!registry.isNamespaceAgnostic(type)) { + namespaces = updatedSavedObject.namespaces ?? [ + SavedObjectsUtils.namespaceIdToString(updatedSavedObject.namespace), + ]; + } - const result = { - id, - type, - updated_at: time, - version: encodeHitVersion(body), - namespaces, - ...(originId && { originId }), - references, - attributes, - } as SavedObject; + updatedOrCreatedSavedObject = { + id, + type, + updated_at: time, + version: encodeHitVersion(indexDocResponseBody), + namespaces, + ...(originId && { originId }), + references, + attributes, + } as SavedObject; + } return encryptionHelper.optionallyDecryptAndRedactSingleResult( - result, + updatedOrCreatedSavedObject!, authorizationResult?.typeMap, - attributes + shouldPerformUpsert ? upsert : attributes ); }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/index.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/index.ts index f3562dffb1e86..575b29d47ca0f 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/index.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/index.ts @@ -23,3 +23,4 @@ export { type GetSavedObjectFromSourceOptions, } from './internal_utils'; export { type Left, type Either, type Right, isLeft, isRight, left, right } from './either'; +export { mergeForUpdate } from './merge_for_update'; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/merge_for_update.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/merge_for_update.test.ts new file mode 100644 index 0000000000000..7d859f374a5e2 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/merge_for_update.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { mergeForUpdate } from './merge_for_update'; + +describe('mergeForUpdate', () => { + it('merges top level properties', () => { + expect(mergeForUpdate({ foo: 'bar', hello: 'dolly' }, { baz: 42 })).toEqual({ + foo: 'bar', + hello: 'dolly', + baz: 42, + }); + }); + + it('overrides top level properties', () => { + expect(mergeForUpdate({ foo: 'bar', hello: 'dolly' }, { baz: 42, foo: '9000' })).toEqual({ + foo: '9000', + hello: 'dolly', + baz: 42, + }); + }); + + it('ignores undefined top level properties', () => { + expect(mergeForUpdate({ foo: 'bar', hello: 'dolly' }, { baz: 42, foo: undefined })).toEqual({ + foo: 'bar', + hello: 'dolly', + baz: 42, + }); + }); + + it('merges nested properties', () => { + expect( + mergeForUpdate({ nested: { foo: 'bar', hello: 'dolly' } }, { nested: { baz: 42 } }) + ).toEqual({ + nested: { + foo: 'bar', + hello: 'dolly', + baz: 42, + }, + }); + }); + + it('overrides nested properties', () => { + expect( + mergeForUpdate( + { nested: { foo: 'bar', hello: 'dolly' } }, + { nested: { baz: 42, foo: '9000' } } + ) + ).toEqual({ + nested: { + foo: '9000', + hello: 'dolly', + baz: 42, + }, + }); + }); + + it('ignores undefined nested properties', () => { + expect( + mergeForUpdate( + { nested: { foo: 'bar', hello: 'dolly' } }, + { nested: { baz: 42, foo: undefined } } + ) + ).toEqual({ + nested: { + foo: 'bar', + hello: 'dolly', + baz: 42, + }, + }); + }); + + it('functions with mixed levels of properties', () => { + expect( + mergeForUpdate( + { rootPropA: 'A', nested: { foo: 'bar', hello: 'dolly', deep: { deeper: 'we need' } } }, + { rootPropB: 'B', nested: { baz: 42, foo: '9000', deep: { deeper: 'we are' } } } + ) + ).toEqual({ + rootPropA: 'A', + rootPropB: 'B', + nested: { + foo: '9000', + hello: 'dolly', + baz: 42, + deep: { + deeper: 'we are', + }, + }, + }); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/merge_for_update.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/merge_for_update.ts new file mode 100644 index 0000000000000..a3ad081fa74d7 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/apis/utils/merge_for_update.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isPlainObject } from 'lodash'; +import { set } from '@kbn/safer-lodash-set'; + +export const mergeForUpdate = ( + targetAttributes: Record, + updatedAttributes: any +): Record => { + return recursiveMerge(targetAttributes, updatedAttributes, []); +}; + +const recursiveMerge = (target: Record, value: any, keys: string[] = []) => { + if (isPlainObject(value) && Object.keys(value).length > 0) { + for (const [subKey, subVal] of Object.entries(value)) { + recursiveMerge(target, subVal, [...keys, subKey]); + } + } else if (keys.length > 0 && value !== undefined) { + set(target, keys, value); + } + + return target; +}; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.encryption_extension.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.encryption_extension.test.ts index 9c2c70e27d121..ecaefe05d65e0 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.encryption_extension.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.encryption_extension.test.ts @@ -350,7 +350,7 @@ describe('SavedObjectsRepository Encryption Extension', () => { namespace, } ); - expect(client.update).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); expect(mockEncryptionExt.isEncryptableType).toHaveBeenCalledTimes(2); // (no upsert) optionallyEncryptAttributes, optionallyDecryptAndRedactSingleResult expect(mockEncryptionExt.isEncryptableType).toHaveBeenCalledWith(nonEncryptedSO.type); expect(mockEncryptionExt.encryptAttributes).not.toHaveBeenCalled(); @@ -382,7 +382,7 @@ describe('SavedObjectsRepository Encryption Extension', () => { references: encryptedSO.references, } ); - expect(client.update).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); expect(mockEncryptionExt.isEncryptableType).toHaveBeenCalledTimes(2); // (no upsert) optionallyEncryptAttributes, optionallyDecryptAndRedactSingleResult expect(mockEncryptionExt.isEncryptableType).toHaveBeenCalledWith(encryptedSO.type); expect(mockEncryptionExt.encryptAttributes).toHaveBeenCalledTimes(1); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.security_extension.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.security_extension.test.ts index 3e81c09d1df9f..30778ef7b5f92 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.security_extension.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.security_extension.test.ts @@ -235,7 +235,7 @@ describe('SavedObjectsRepository Security Extension', () => { }); expect(mockSecurityExt.authorizeUpdate).toHaveBeenCalledTimes(1); - expect(client.update).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); expect(result).toEqual( expect.objectContaining({ id, type, attributes, namespaces: [namespace] }) ); @@ -250,7 +250,7 @@ describe('SavedObjectsRepository Security Extension', () => { }); expect(mockSecurityExt.authorizeUpdate).toHaveBeenCalledTimes(1); - expect(client.update).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); expect(result).toEqual( expect.objectContaining({ id, type, attributes, namespaces: [namespace] }) ); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts index a000384ce5236..29983177adc99 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.spaces_extension.test.ts @@ -222,27 +222,26 @@ describe('SavedObjectsRepository Spaces Extension', () => { id, {}, { upsert: true }, - { mockGetResponseValue: { found: false } as estypes.GetResponse } + { mockGetResponseAsNotFound: { found: false } as estypes.GetResponse }, + [currentSpace.expectedNamespace ?? 'default'] ); expect(mockSpacesExt.getCurrentNamespace).toBeCalledTimes(1); expect(mockSpacesExt.getCurrentNamespace).toHaveBeenCalledWith(undefined); - expect(client.update).toHaveBeenCalledTimes(1); - expect(client.update).toHaveBeenCalledWith( + expect(client.create).toHaveBeenCalledTimes(1); + expect(client.create).toHaveBeenCalledWith( expect.objectContaining({ id: `${ currentSpace.expectedNamespace ? `${currentSpace.expectedNamespace}:` : '' }${type}:${id}`, - body: expect.objectContaining({ - upsert: expect.objectContaining( - currentSpace.expectedNamespace - ? { - namespace: currentSpace.expectedNamespace, - } - : {} - ), - }), + body: expect.objectContaining( + currentSpace.expectedNamespace + ? { + namespace: currentSpace.expectedNamespace, + } + : {} + ), }), - { maxRetries: 0 } + expect.any(Object) ); }); }); @@ -1078,7 +1077,8 @@ describe('SavedObjectsRepository Spaces Extension', () => { id, {}, { upsert: true }, - { mockGetResponseValue: { found: false } as estypes.GetResponse } + { mockGetResponseAsNotFound: { found: false } as estypes.GetResponse }, + [currentSpace] ); expect(mockSpacesExt.getCurrentNamespace).toBeCalledTimes(1); expect(mockSpacesExt.getCurrentNamespace).toHaveBeenCalledWith(undefined); @@ -1354,11 +1354,12 @@ describe('SavedObjectsRepository Spaces Extension', () => { { // no namespace provided references: encryptedSO.references, - } + }, + {} ); expect(mockSpacesExt.getCurrentNamespace).toBeCalledTimes(1); expect(mockSpacesExt.getCurrentNamespace).toHaveBeenCalledWith(undefined); - expect(client.update).toHaveBeenCalledTimes(1); + expect(client.index).toHaveBeenCalledTimes(1); expect(mockEncryptionExt.isEncryptableType).toHaveBeenCalledTimes(2); // (no upsert) optionallyEncryptAttributes, optionallyDecryptAndRedactSingleResult expect(mockEncryptionExt.isEncryptableType).toHaveBeenCalledWith(encryptedSO.type); expect(mockEncryptionExt.encryptAttributes).toHaveBeenCalledTimes(1); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts index ab41890d36368..fa1fda60d09fd 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.test.ts @@ -69,7 +69,6 @@ import { import { kibanaMigratorMock } from '../mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import * as esKuery from '@kbn/es-query'; -import { errors as EsErrors } from '@elastic/elasticsearch'; import { CUSTOM_INDEX_TYPE, @@ -94,8 +93,6 @@ import { getMockBulkCreateResponse, bulkGet, getMockBulkUpdateResponse, - updateSuccess, - mockUpdateResponse, expectErrorResult, expectErrorInvalidType, expectErrorNotFound, @@ -188,6 +185,7 @@ describe('SavedObjectsRepository', () => { mockGetSearchDsl.mockClear(); }); + // Setup migration mock for creating an object const mockMigrationVersion = { foo: '2.3.4' }; const mockMigrateDocument = (doc: SavedObjectUnsanitizedDoc) => ({ ...doc, @@ -4819,507 +4817,6 @@ describe('SavedObjectsRepository', () => { }); }); - describe('#update', () => { - const id = 'logstash-*'; - const type = 'index-pattern'; - const attributes = { title: 'Testing' }; - const namespace = 'foo-namespace'; - const references = [ - { - name: 'ref_0', - type: 'test', - id: '1', - }, - ]; - const originId = 'some-origin-id'; - - beforeEach(() => { - mockPreflightCheckForCreate.mockReset(); - mockPreflightCheckForCreate.mockImplementation(({ objects }) => { - return Promise.resolve(objects.map(({ type, id }) => ({ type, id }))); // respond with no errors by default - }); - }); - - describe('client calls', () => { - it(`should use the ES update action when type is not multi-namespace`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes); - expect(client.get).not.toHaveBeenCalled(); - expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); - expect(client.update).toHaveBeenCalledTimes(1); - }); - - it(`should use the ES get action then update action when type is multi-namespace`, async () => { - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes - ); - expect(client.get).toHaveBeenCalledTimes(1); - expect(mockPreflightCheckForCreate).not.toHaveBeenCalled(); - expect(client.update).toHaveBeenCalledTimes(1); - }); - - it(`should check for alias conflicts if a new multi-namespace object would be created`, async () => { - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes, - { upsert: true }, - { mockGetResponseValue: { found: false } as estypes.GetResponse } - ); - expect(client.get).toHaveBeenCalledTimes(1); - expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); - expect(client.update).toHaveBeenCalledTimes(1); - }); - - it(`defaults to no references array`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - body: { doc: expect.not.objectContaining({ references: expect.anything() }) }, - }), - expect.anything() - ); - }); - - it(`accepts custom references array`, async () => { - const test = async (references: SavedObjectReference[]) => { - await updateSuccess(client, repository, registry, type, id, attributes, { references }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - body: { doc: expect.objectContaining({ references }) }, - }), - expect.anything() - ); - client.update.mockClear(); - }; - await test(references); - await test([{ type: 'foo', id: '42', name: 'some ref' }]); - await test([]); - }); - - it(`uses the 'upsertAttributes' option when specified for a single-namespace type`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { - upsert: { - title: 'foo', - description: 'bar', - }, - }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - id: 'index-pattern:logstash-*', - body: expect.objectContaining({ - upsert: expect.objectContaining({ - type: 'index-pattern', - 'index-pattern': { - title: 'foo', - description: 'bar', - }, - }), - }), - }), - expect.anything() - ); - }); - - it(`uses the 'upsertAttributes' option when specified for a multi-namespace type that does not exist`, async () => { - const options = { upsert: { title: 'foo', description: 'bar' } }; - mockUpdateResponse(client, MULTI_NAMESPACE_ISOLATED_TYPE, id, options); - await repository.update(MULTI_NAMESPACE_ISOLATED_TYPE, id, attributes, options); - expect(client.get).toHaveBeenCalledTimes(1); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:logstash-*`, - body: expect.objectContaining({ - upsert: expect.objectContaining({ - type: MULTI_NAMESPACE_ISOLATED_TYPE, - [MULTI_NAMESPACE_ISOLATED_TYPE]: { - title: 'foo', - description: 'bar', - }, - }), - }), - }), - expect.anything() - ); - }); - - it(`ignores use the 'upsertAttributes' option when specified for a multi-namespace type that already exists`, async () => { - const options = { upsert: { title: 'foo', description: 'bar' } }; - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes, - options - ); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - id: `${MULTI_NAMESPACE_ISOLATED_TYPE}:logstash-*`, - body: expect.not.objectContaining({ - upsert: expect.anything(), - }), - }), - expect.anything() - ); - }); - - it(`doesn't accept custom references if not an array`, async () => { - const test = async (references: unknown) => { - // @ts-expect-error references is unknown - await updateSuccess(client, repository, registry, type, id, attributes, { references }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - body: { doc: expect.not.objectContaining({ references: expect.anything() }) }, - }), - expect.anything() - ); - client.update.mockClear(); - }; - await test('string'); - await test(123); - await test(true); - await test(null); - }); - - it(`defaults to a refresh setting of wait_for`, async () => { - await updateSuccess(client, repository, registry, type, id, { foo: 'bar' }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - refresh: 'wait_for', - }), - expect.anything() - ); - }); - - it(`does not default to the version of the existing document when type is multi-namespace`, async () => { - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes, - { references } - ); - const versionProperties = { - if_seq_no: mockVersionProps._seq_no, - if_primary_term: mockVersionProps._primary_term, - }; - expect(client.update).toHaveBeenCalledWith( - expect.not.objectContaining(versionProperties), - expect.anything() - ); - }); - - it(`accepts version`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { - version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }), - }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ if_seq_no: 100, if_primary_term: 200 }), - expect.anything() - ); - }); - - it('default to a `retry_on_conflict` setting of `3` when `version` is not provided', async () => { - await updateSuccess(client, repository, registry, type, id, attributes, {}); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ retry_on_conflict: 3 }), - expect.anything() - ); - }); - - it('default to a `retry_on_conflict` setting of `0` when `version` is provided', async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { - version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }), - }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ retry_on_conflict: 0, if_seq_no: 100, if_primary_term: 200 }), - expect.anything() - ); - }); - - it('accepts a `retryOnConflict` option', async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { - version: encodeHitVersion({ _seq_no: 100, _primary_term: 200 }), - retryOnConflict: 42, - }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ retry_on_conflict: 42, if_seq_no: 100, if_primary_term: 200 }), - expect.anything() - ); - }); - - it(`prepends namespace to the id when providing namespace for single-namespace type`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { namespace }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ id: expect.stringMatching(`${namespace}:${type}:${id}`) }), - expect.anything() - ); - }); - - it(`doesn't prepend namespace to the id when providing no namespace for single-namespace type`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { references }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ id: expect.stringMatching(`${type}:${id}`) }), - expect.anything() - ); - }); - - it(`normalizes options.namespace from 'default' to undefined`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes, { - references, - namespace: 'default', - }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ id: expect.stringMatching(`${type}:${id}`) }), - expect.anything() - ); - }); - - it(`doesn't prepend namespace to the id when not using single-namespace type`, async () => { - await updateSuccess(client, repository, registry, NAMESPACE_AGNOSTIC_TYPE, id, attributes, { - namespace, - }); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - id: expect.stringMatching(`${NAMESPACE_AGNOSTIC_TYPE}:${id}`), - }), - expect.anything() - ); - - client.update.mockClear(); - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes, - { namespace } - ); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ - id: expect.stringMatching(`${MULTI_NAMESPACE_ISOLATED_TYPE}:${id}`), - }), - expect.anything() - ); - }); - - it(`includes _source_includes when type is multi-namespace`, async () => { - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes - ); - expect(client.update).toHaveBeenCalledWith( - expect.objectContaining({ _source_includes: ['namespace', 'namespaces', 'originId'] }), - expect.anything() - ); - }); - - it(`includes _source_includes when type is not multi-namespace`, async () => { - await updateSuccess(client, repository, registry, type, id, attributes); - expect(client.update).toHaveBeenLastCalledWith( - expect.objectContaining({ - _source_includes: ['namespace', 'namespaces', 'originId'], - }), - expect.anything() - ); - }); - }); - - describe('errors', () => { - const expectNotFoundError = async (type: string, id: string) => { - await expect(repository.update(type, id, {})).rejects.toThrowError( - createGenericNotFoundErrorPayload(type, id) - ); - }; - - it(`throws when options.namespace is '*'`, async () => { - await expect( - repository.update(type, id, attributes, { namespace: ALL_NAMESPACES_STRING }) - ).rejects.toThrowError(createBadRequestErrorPayload('"options.namespace" cannot be "*"')); - }); - - it(`throws when type is invalid`, async () => { - await expectNotFoundError('unknownType', id); - expect(client.update).not.toHaveBeenCalled(); - }); - - it(`throws when type is hidden`, async () => { - await expectNotFoundError(HIDDEN_TYPE, id); - expect(client.update).not.toHaveBeenCalled(); - }); - - it(`throws when id is empty`, async () => { - await expect(repository.update(type, '', attributes)).rejects.toThrowError( - createBadRequestErrorPayload('id cannot be empty') - ); - expect(client.update).not.toHaveBeenCalled(); - }); - - it(`throws when ES is unable to find the document during get`, async () => { - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise( - { found: false } as estypes.GetResponse, - undefined - ) - ); - await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id); - expect(client.get).toHaveBeenCalledTimes(1); - }); - - it(`throws when ES is unable to find the index during get`, async () => { - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise({} as estypes.GetResponse, { - statusCode: 404, - }) - ); - await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id); - expect(client.get).toHaveBeenCalledTimes(1); - }); - - it(`throws when type is multi-namespace and the document exists, but not in this namespace`, async () => { - const response = getMockGetResponse( - registry, - { type: MULTI_NAMESPACE_ISOLATED_TYPE, id }, - namespace - ); - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise(response) - ); - await expectNotFoundError(MULTI_NAMESPACE_ISOLATED_TYPE, id); - expect(client.get).toHaveBeenCalledTimes(1); - }); - - it(`throws when there is an alias conflict from preflightCheckForCreate`, async () => { - client.get.mockResolvedValueOnce( - elasticsearchClientMock.createSuccessTransportRequestPromise({ - found: false, - } as estypes.GetResponse) - ); - mockPreflightCheckForCreate.mockResolvedValue([ - { type: 'type', id: 'id', error: { type: 'aliasConflict' } }, - ]); - await expect( - repository.update( - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - { attr: 'value' }, - { - upsert: { - upsertAttr: 'val', - attr: 'value', - }, - } - ) - ).rejects.toThrowError(createConflictErrorPayload(MULTI_NAMESPACE_ISOLATED_TYPE, id)); - expect(client.get).toHaveBeenCalledTimes(1); - expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); - expect(client.update).not.toHaveBeenCalled(); - }); - - it(`does not throw when there is a different error from preflightCheckForCreate`, async () => { - mockPreflightCheckForCreate.mockResolvedValue([ - { type: 'type', id: 'id', error: { type: 'conflict' } }, - ]); - await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes, - { upsert: true }, - { mockGetResponseValue: { found: false } as estypes.GetResponse } - ); - expect(client.get).toHaveBeenCalledTimes(1); - expect(mockPreflightCheckForCreate).toHaveBeenCalledTimes(1); - expect(client.update).toHaveBeenCalledTimes(1); - }); - - it(`throws when ES is unable to find the document during update`, async () => { - const notFoundError = new EsErrors.ResponseError( - elasticsearchClientMock.createApiResponse({ - statusCode: 404, - body: { error: { type: 'es_type', reason: 'es_reason' } }, - }) - ); - client.update.mockResolvedValueOnce( - elasticsearchClientMock.createErrorTransportRequestPromise(notFoundError) - ); - await expectNotFoundError(type, id); - expect(client.update).toHaveBeenCalledTimes(1); - }); - }); - - describe('returns', () => { - it(`returns _seq_no and _primary_term encoded as version`, async () => { - const result = await updateSuccess(client, repository, registry, type, id, attributes, { - namespace, - references, - }); - expect(result).toEqual({ - id, - type, - ...mockTimestampFields, - version: mockVersion, - attributes, - references, - namespaces: [namespace], - }); - }); - - it(`includes namespaces if type is multi-namespace`, async () => { - const result = await updateSuccess( - client, - repository, - registry, - MULTI_NAMESPACE_ISOLATED_TYPE, - id, - attributes - ); - expect(result).toMatchObject({ - namespaces: expect.any(Array), - }); - }); - - it(`includes namespaces if type is not multi-namespace`, async () => { - const result = await updateSuccess(client, repository, registry, type, id, attributes); - expect(result).toMatchObject({ - namespaces: ['default'], - }); - }); - - it(`includes originId property if present in cluster call response`, async () => { - const result = await updateSuccess( - client, - repository, - registry, - type, - id, - attributes, - {}, - { originId } - ); - expect(result).toMatchObject({ originId }); - }); - }); - }); - describe('#openPointInTimeForType', () => { const type = 'index-pattern'; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts index ba96c10da0090..861a2f847d97b 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/index.ts @@ -9,3 +9,4 @@ export { decorateEsError } from './decorate_es_error'; export { getRootFields, includedFields } from './included_fields'; export { createRepositoryHelpers } from './create_helpers'; +export { isValidRequest } from './update_utils'; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/update_utils.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/update_utils.ts new file mode 100644 index 0000000000000..c686cbb7ca68b --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/utils/update_utils.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 { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; + +export const isValidRequest = ({ + allowedTypes, + type, + id, +}: { + allowedTypes: string[]; + type: string; + id?: string; +}) => { + return !id + ? { + validRequest: false, + error: SavedObjectsErrorHelpers.createBadRequestError('id cannot be empty'), + } + : !allowedTypes.includes(type) + ? { + validRequest: false, + error: SavedObjectsErrorHelpers.createGenericNotFoundError(type, id), + } + : { + validRequest: true, + }; +}; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts index 69f0124f681e1..e50cc4d1036eb 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/mocks/api_helpers.mocks.ts @@ -92,6 +92,8 @@ const createPreflightCheckHelperMock = (): PreflightCheckHelperMock => { preflightCheckForBulkDelete: jest.fn(), preflightCheckNamespaces: jest.fn(), preflightCheckForUpsertAliasConflict: jest.fn(), + preflightGetDocForUpdate: jest.fn(), + preflightCheckNamespacesForUpdate: jest.fn(), }; return mock; diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts index 2cb4f32f441cb..29c00e9d41ac1 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/test_helpers/repository.test.common.ts @@ -103,7 +103,7 @@ export const expectErrorConflict = (obj: TypeIdTuple, overrides?: Record) => expectErrorResult(obj, createUnsupportedTypeErrorPayload(obj.type), overrides); -export const KIBANA_VERSION = '2.0.0'; +export const KIBANA_VERSION = '8.8.0'; export const ALLOWED_CONVERT_VERSION = '8.0.0'; export const CUSTOM_INDEX_TYPE = 'customIndex'; /** This type has namespaceType: 'agnostic'. */ @@ -439,7 +439,7 @@ export const getMockGetResponse = ( } const namespaceId = namespaces[0] === 'default' ? undefined : namespaces[0]; - return { + const result = { // NOTE: Elasticsearch returns more fields (_index, _type) but the SavedObjectsRepository method ignores these found: true, _id: `${registry.isSingleNamespace(type) && namespaceId ? `${namespaceId}:` : ''}${type}:${id}`, @@ -464,6 +464,7 @@ export const getMockGetResponse = ( ...mockTimestampFields, } as SavedObjectsRawDocSource, } as estypes.GetResponse; + return result; }; export const getMockMgetResponse = ( @@ -489,35 +490,6 @@ expect.extend({ }, }); -export const mockUpdateResponse = ( - client: ElasticsearchClientMock, - type: string, - id: string, - options?: SavedObjectsUpdateOptions, - namespaces?: string[], - originId?: string -) => { - client.update.mockResponseOnce( - { - _id: `${type}:${id}`, - ...mockVersionProps, - result: 'updated', - // don't need the rest of the source for test purposes, just the namespace and namespaces attributes - get: { - _source: { - namespaces: namespaces ?? [options?.namespace ?? 'default'], - namespace: options?.namespace, - - // If the existing saved object contains an originId attribute, the operation will return it in the result. - // The originId parameter is just used for test purposes to modify the mock cluster call response. - ...(!!originId && { originId }), - }, - }, - } as estypes.UpdateResponse, - { statusCode: 200 } - ); -}; - export const updateSuccess = async >( client: ElasticsearchClientMock, repository: SavedObjectsRepository, @@ -528,20 +500,40 @@ export const updateSuccess = async >( options?: SavedObjectsUpdateOptions, internalOptions: { originId?: string; - mockGetResponseValue?: estypes.GetResponse; + mockGetResponseAsNotFound?: estypes.GetResponse; } = {}, objNamespaces?: string[] ) => { - const { mockGetResponseValue, originId } = internalOptions; - if (registry.isMultiNamespace(type)) { - const mockGetResponse = - mockGetResponseValue ?? - getMockGetResponse(registry, { type, id }, objNamespaces ?? options?.namespace); - client.get.mockResponseOnce(mockGetResponse, { statusCode: 200 }); + const { mockGetResponseAsNotFound, originId } = internalOptions; + const mockGetResponse = + mockGetResponseAsNotFound ?? + getMockGetResponse(registry, { type, id, originId }, objNamespaces ?? options?.namespace); + client.get.mockResponseOnce(mockGetResponse, { statusCode: 200 }); + if (!mockGetResponseAsNotFound) { + // index doc from existing doc + client.index.mockResponseImplementation((params) => { + return { + body: { + _id: params.id, + ...mockVersionProps, + } as estypes.CreateResponse, + }; + }); + } + if (mockGetResponseAsNotFound) { + // upsert case: create the doc. (be careful here, we're also sending mockGetResponseValue as { found: false }) + client.create.mockResponseImplementation((params) => { + return { + body: { + _id: params.id, + ...mockVersionProps, + } as estypes.CreateResponse, + }; + }); } - mockUpdateResponse(client, type, id, options, objNamespaces, originId); + const result = await repository.update(type, id, attributes, options); - expect(client.get).toHaveBeenCalledTimes(registry.isMultiNamespace(type) ? 1 : 0); + expect(client.get).toHaveBeenCalled(); // not asserting on the number of calls here, we end up testing the test mocks and not the actual implementation return result; }; diff --git a/packages/core/saved-objects/core-saved-objects-api-server/src/apis/update.ts b/packages/core/saved-objects/core-saved-objects-api-server/src/apis/update.ts index 66f7103102b6e..e830b32601c5b 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server/src/apis/update.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server/src/apis/update.ts @@ -18,6 +18,7 @@ export interface SavedObjectsUpdateOptions extends SavedOb /** * An opaque version number which changes on each successful write operation. * Can be used for implementing optimistic concurrency control. + * Unused for multi-namespace objects */ version?: string; /** {@inheritdoc SavedObjectReference} */ @@ -31,6 +32,8 @@ export interface SavedObjectsUpdateOptions extends SavedOb * Defaults to `0` when `version` is provided, `3` otherwise. */ retryOnConflict?: number; + /** {@link SavedObjectsRawDocParseOptions.migrationVersionCompatibility} */ + migrationVersionCompatibility?: 'compatible' | 'raw'; } /** diff --git a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts index 96eded287975c..cb3036fa9d668 100644 --- a/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts +++ b/packages/core/saved-objects/core-saved-objects-base-server-internal/src/serialization/serializer.ts @@ -116,7 +116,7 @@ export class SavedObjectsSerializer implements ISavedObjectsSerializer { ...(includeNamespaces && { namespaces }), ...(originId && { originId }), attributes: _source[type], - references: references || [], + references: references || [], // adds references default ...(managed != null ? { managed } : {}), ...(migrationVersion && { migrationVersion }), ...(coreMigrationVersion && { coreMigrationVersion }), diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts index 11a6545bfd612..b720260619aca 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/update.ts @@ -62,7 +62,12 @@ export const registerUpdateRoute = ( }); const { type, id } = req.params; const { attributes, version, references, upsert } = req.body; - const options: SavedObjectsUpdateOptions = { version, references, upsert }; + const options: SavedObjectsUpdateOptions = { + version, + references, + upsert, + migrationVersionCompatibility: 'raw' as const, + }; const usageStatsClient = coreUsageData.getClient(); usageStatsClient.incrementSavedObjectsUpdate({ request: req }).catch(() => {}); diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts index 82328c51fd6c1..0efda4a5bce9b 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/saved_objects_service.ts @@ -57,12 +57,13 @@ import { import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal'; import type { DeprecationRegistryProvider } from '@kbn/core-deprecations-server'; import type { NodeInfo } from '@kbn/core-node-server'; -import { MAIN_SAVED_OBJECT_INDEX, ALL_SAVED_OBJECT_INDICES } from '@kbn/core-saved-objects-server'; +import { MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; import { registerRoutes } from './routes'; import { calculateStatus$ } from './status'; import { registerCoreObjectTypes } from './object_types'; import { getSavedObjectsDeprecationsProvider } from './deprecations'; import { applyTypeDefaults } from './apply_type_defaults'; +import { getAllIndices } from './utils'; /** * @internal @@ -202,7 +203,6 @@ export class SavedObjectsService }, getTypeRegistry: () => this.typeRegistry, getDefaultIndex: () => MAIN_SAVED_OBJECT_INDEX, - getAllIndices: () => [...ALL_SAVED_OBJECT_INDICES], }; } @@ -326,6 +326,8 @@ export class SavedObjectsService clientProvider.setClientFactory(clientFactory); } + const allIndices = getAllIndices({ registry: this.typeRegistry }); + this.started = true; return { @@ -361,7 +363,7 @@ export class SavedObjectsService }); return [...indices]; }, - getAllIndices: () => [...ALL_SAVED_OBJECT_INDICES], + getAllIndices: () => [...allIndices], }; } diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/get_all_indices.test.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/get_all_indices.test.ts new file mode 100644 index 0000000000000..c3a09df0ed529 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/get_all_indices.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 SavedObjectsType, MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { SavedObjectTypeRegistry } from '@kbn/core-saved-objects-base-server-internal'; +import { getAllIndices } from './get_all_indices'; + +describe('getAllIndices', () => { + const createType = (parts: Partial): SavedObjectsType => ({ + name: 'test', + hidden: false, + namespaceType: 'single', + mappings: { properties: {} }, + ...parts, + }); + + const createRegistry = (...types: Array>): SavedObjectTypeRegistry => { + const registry = new SavedObjectTypeRegistry(); + types.forEach((type) => { + registry.registerType(createType(type)); + }); + + return registry; + }; + + it('returns the indices that are used by registered types', () => { + const registry = createRegistry( + { name: 'type_1' }, + { name: 'type_2', indexPattern: '.kibana_ingest' } + ); + expect(getAllIndices({ registry })).toEqual([MAIN_SAVED_OBJECT_INDEX, '.kibana_ingest']); + }); + + it('returns each index only once', () => { + const registry = createRegistry( + { name: 'type_1' }, + { name: 'type_2', indexPattern: '.kibana_foo' }, + { name: 'type_3' }, + { name: 'type_4', indexPattern: '.kibana_foo' } + ); + expect(getAllIndices({ registry })).toEqual([MAIN_SAVED_OBJECT_INDEX, '.kibana_foo']); + }); +}); diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/get_all_indices.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/get_all_indices.ts new file mode 100644 index 0000000000000..166cbf8f78ef1 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/get_all_indices.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { MAIN_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import type { SavedObjectTypeRegistry } from '@kbn/core-saved-objects-base-server-internal'; + +export const getAllIndices = ({ registry }: { registry: SavedObjectTypeRegistry }): string[] => { + return [ + ...new Set(registry.getAllTypes().map((type) => type.indexPattern ?? MAIN_SAVED_OBJECT_INDEX)), + ]; +}; diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/index.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/index.ts new file mode 100644 index 0000000000000..e931a9c64c039 --- /dev/null +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/utils/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 { getAllIndices } from './get_all_indices'; diff --git a/packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts b/packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts index 2d7d5ff847330..58b7c424ac19a 100644 --- a/packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts +++ b/packages/core/saved-objects/core-saved-objects-server-mocks/src/saved_objects_service.mock.ts @@ -77,11 +77,9 @@ const createSetupContractMock = () => { setSpacesExtension: jest.fn(), registerType: jest.fn(), getDefaultIndex: jest.fn(), - getAllIndices: jest.fn(), }; setupContract.getDefaultIndex.mockReturnValue(MAIN_SAVED_OBJECT_INDEX); - setupContract.getAllIndices.mockReturnValue([MAIN_SAVED_OBJECT_INDEX]); return setupContract; }; diff --git a/packages/core/saved-objects/core-saved-objects-server/src/contracts.ts b/packages/core/saved-objects/core-saved-objects-server/src/contracts.ts index e08da10172f3c..1f20524f9a114 100644 --- a/packages/core/saved-objects/core-saved-objects-server/src/contracts.ts +++ b/packages/core/saved-objects/core-saved-objects-server/src/contracts.ts @@ -137,13 +137,6 @@ export interface SavedObjectsServiceSetup { * Returns the default index used for saved objects. */ getDefaultIndex: () => string; - - /** - * Returns all (aliases to) kibana system indices used for saved object storage. - * - * @deprecated use the `start` contract counterpart. - */ - getAllIndices: () => string[]; } /** @@ -235,6 +228,8 @@ export interface SavedObjectsServiceStart { getDefaultIndex: () => string; /** * Returns all (aliases to) kibana system indices used for saved object storage. + * + * @remarks Only the indices effectively present in the current running environment will be returned. */ getAllIndices: () => string[]; } diff --git a/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts b/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts index 8b3b6b4924d79..a5fbf87145d8d 100644 --- a/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts +++ b/packages/core/saved-objects/core-saved-objects-server/src/serialization.ts @@ -73,7 +73,12 @@ export interface SavedObjectsRawDoc { _primary_term?: number; } -/** @public */ +/** + * Saved object document as stored in `_source` of doc in ES index + * Similar to SavedObjectDoc and excludes `version`, includes `references`, has `attributes` in [typeMapping] + * + * @public + */ export interface SavedObjectsRawDocSource { type: string; namespace?: string; diff --git a/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_serverless_root.ts b/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_serverless_root.ts index 0562112218455..3e12b16832714 100644 --- a/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_serverless_root.ts +++ b/packages/core/test-helpers/core-test-helpers-kbn-server/src/create_serverless_root.ts @@ -6,13 +6,12 @@ * Side Public License, v 1. */ +import Path from 'path'; import { defaultsDeep } from 'lodash'; import { Client, HttpConnection } from '@elastic/elasticsearch'; import { Cluster } from '@kbn/es'; -import Path from 'path'; import { REPO_ROOT } from '@kbn/repo-info'; import { ToolingLog } from '@kbn/tooling-log'; -import execa from 'execa'; import { CliArgs } from '@kbn/config'; import { createRoot, type TestElasticsearchUtils, type TestKibanaUtils } from './create_root'; @@ -64,6 +63,7 @@ export function createTestServerlessInstances({ }; } +const ES_BASE_PATH_DIR = Path.join(REPO_ROOT, '.es/es_test_serverless'); function createServerlessES() { const log = new ToolingLog({ level: 'info', @@ -74,37 +74,23 @@ function createServerlessES() { es, start: async () => { await es.runServerless({ - basePath: Path.join(REPO_ROOT, '.es/es_test_serverless'), + basePath: ES_BASE_PATH_DIR, + teardown: true, + background: true, + clean: true, + kill: true, + waitForReady: true, }); - // runServerless doesn't wait until the nodes are up - await waitUntilClusterReady(getServerlessESClient()); return { getClient: getServerlessESClient, stop: async () => { - // hack to stop the ES cluster - await execa('docker', ['container', 'stop', 'es01', 'es02', 'es03']); + await es.stop(); }, }; }, }; } -const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -const waitUntilClusterReady = async (client: Client, timeoutMs = 60 * 1000) => { - const started = Date.now(); - - while (started + timeoutMs > Date.now()) { - try { - await client.info(); - break; - } catch (e) { - await delay(1000); - /* trap to continue */ - } - } -}; - const getServerlessESClient = () => { return new Client({ // node ports not configurable from diff --git a/packages/kbn-discover-utils/index.ts b/packages/kbn-discover-utils/index.ts index b94d71b5540eb..d19f50c5dc646 100644 --- a/packages/kbn-discover-utils/index.ts +++ b/packages/kbn-discover-utils/index.ts @@ -13,7 +13,7 @@ export { DEFAULT_COLUMNS_SETTING, DOC_HIDE_TIME_COLUMN_SETTING, DOC_TABLE_LEGACY, - ENABLE_SQL, + ENABLE_ESQL, FIELDS_LIMIT_SETTING, HIDE_ANNOUNCEMENTS, KNOWN_FIELD_TYPE_LIST, diff --git a/packages/kbn-discover-utils/src/constants.ts b/packages/kbn-discover-utils/src/constants.ts index 60aaf63d9c70e..7582b610c6638 100644 --- a/packages/kbn-discover-utils/src/constants.ts +++ b/packages/kbn-discover-utils/src/constants.ts @@ -12,7 +12,7 @@ export const CONTEXT_TIE_BREAKER_FIELDS_SETTING = 'context:tieBreakerFields'; export const DEFAULT_COLUMNS_SETTING = 'defaultColumns'; export const DOC_HIDE_TIME_COLUMN_SETTING = 'doc_table:hideTimeColumn'; export const DOC_TABLE_LEGACY = 'doc_table:legacy'; -export const ENABLE_SQL = 'discover:enableSql'; +export const ENABLE_ESQL = 'discover:enableESQL'; export const FIELDS_LIMIT_SETTING = 'fields:popularLimit'; export const HIDE_ANNOUNCEMENTS = 'hideAnnouncements'; export const MAX_DOC_FIELDS_DISPLAYED = 'discover:maxDocFieldsDisplayed'; diff --git a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts index 2c23eec3ca2aa..42df7340c1853 100644 --- a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts +++ b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts @@ -8,25 +8,15 @@ import type { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/tooling-log'; -import { KbnClient } from '@kbn/test'; import { ALL_SAVED_OBJECT_INDICES } from '@kbn/core-saved-objects-server'; -import { migrateSavedObjectIndices, createStats, cleanSavedObjectIndices } from '../lib'; +import { createStats, cleanSavedObjectIndices } from '../lib'; -export async function emptyKibanaIndexAction({ - client, - log, - kbnClient, -}: { - client: Client; - log: ToolingLog; - kbnClient: KbnClient; -}) { +export async function emptyKibanaIndexAction({ client, log }: { client: Client; log: ToolingLog }) { const stats = createStats('emptyKibanaIndex', log); await cleanSavedObjectIndices({ client, stats, log }); - await migrateSavedObjectIndices(kbnClient); await client.indices.refresh({ index: ALL_SAVED_OBJECT_INDICES }); - ALL_SAVED_OBJECT_INDICES.forEach((indexPattern) => stats.createdIndex(indexPattern)); + return stats.toJSON(); } diff --git a/packages/kbn-es-archiver/src/es_archiver.ts b/packages/kbn-es-archiver/src/es_archiver.ts index 65de41148d8db..d5c989f080486 100644 --- a/packages/kbn-es-archiver/src/es_archiver.ts +++ b/packages/kbn-es-archiver/src/es_archiver.ts @@ -154,14 +154,12 @@ export class EsArchiver { } /** - * Delete any Kibana indices, and initialize the Kibana index as Kibana would do - * on startup. + * Cleanup saved object indices, preserving the space:default saved object. */ async emptyKibanaIndex() { return await emptyKibanaIndexAction({ client: this.client, log: this.log, - kbnClient: this.kbnClient, }); } diff --git a/packages/kbn-es-query/index.ts b/packages/kbn-es-query/index.ts index 1e0d9092adefb..a14724fc3a748 100644 --- a/packages/kbn-es-query/index.ts +++ b/packages/kbn-es-query/index.ts @@ -54,6 +54,8 @@ export { isOfAggregateQueryType, getAggregateQueryMode, getIndexPatternFromSQLQuery, + getIndexPatternFromESQLQuery, + getLanguageDisplayName, } from './src/es_query'; export { diff --git a/packages/kbn-es-query/src/es_query/build_es_query.ts b/packages/kbn-es-query/src/es_query/build_es_query.ts index 9d1b0b1c6b139..ff9908bcb0cc3 100644 --- a/packages/kbn-es-query/src/es_query/build_es_query.ts +++ b/packages/kbn-es-query/src/es_query/build_es_query.ts @@ -12,7 +12,7 @@ import { buildQueryFromKuery } from './from_kuery'; import { buildQueryFromFilters } from './from_filters'; import { buildQueryFromLucene } from './from_lucene'; import { Filter, Query, AggregateQuery } from '../filters'; -import { isOfQueryType } from './es_query_sql'; +import { isOfQueryType } from './es_aggregate_query'; import { BoolQuery, DataViewBase } from './types'; import type { KueryQueryOptions } from '../kuery'; import type { EsQueryFiltersConfig } from './from_filters'; diff --git a/packages/kbn-es-query/src/es_query/es_query_sql.test.ts b/packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts similarity index 81% rename from packages/kbn-es-query/src/es_query/es_query_sql.test.ts rename to packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts index da909c6e5f9b4..2ab161e0f7517 100644 --- a/packages/kbn-es-query/src/es_query/es_query_sql.test.ts +++ b/packages/kbn-es-query/src/es_query/es_aggregate_query.test.ts @@ -11,7 +11,8 @@ import { isOfAggregateQueryType, getAggregateQueryMode, getIndexPatternFromSQLQuery, -} from './es_query_sql'; + getIndexPatternFromESQLQuery, +} from './es_aggregate_query'; describe('sql query helpers', () => { describe('isOfQueryType', () => { @@ -81,4 +82,20 @@ describe('sql query helpers', () => { expect(idxPattern8).toBe('logstash-1234!'); }); }); + + describe('getIndexPatternFromESQLQuery', () => { + it('should return the index pattern string from esql queries', () => { + const idxPattern1 = getIndexPatternFromESQLQuery('FROM foo'); + expect(idxPattern1).toBe('foo'); + + const idxPattern3 = getIndexPatternFromESQLQuery('from foo | project abc, def'); + expect(idxPattern3).toBe('foo'); + + const idxPattern4 = getIndexPatternFromESQLQuery('from foo | project a | limit 2'); + expect(idxPattern4).toBe('foo'); + + const idxPattern5 = getIndexPatternFromESQLQuery('from foo | limit 2'); + expect(idxPattern5).toBe('foo'); + }); + }); }); diff --git a/packages/kbn-es-query/src/es_query/es_query_sql.ts b/packages/kbn-es-query/src/es_query/es_aggregate_query.ts similarity index 67% rename from packages/kbn-es-query/src/es_query/es_query_sql.ts rename to packages/kbn-es-query/src/es_query/es_aggregate_query.ts index 46de33dc04e86..1e87552e98b83 100644 --- a/packages/kbn-es-query/src/es_query/es_query_sql.ts +++ b/packages/kbn-es-query/src/es_query/es_aggregate_query.ts @@ -28,7 +28,11 @@ export function getAggregateQueryMode(query: AggregateQuery): Language { return Object.keys(query)[0] as Language; } -// retrieves the index pattern from the aggregate query +export function getLanguageDisplayName(language: string): string { + return language === 'esql' ? 'es|ql' : language; +} + +// retrieves the index pattern from the aggregate query for SQL export function getIndexPatternFromSQLQuery(sqlQuery?: string): string { let sql = sqlQuery?.replaceAll('"', '').replaceAll("'", ''); const splitFroms = sql?.split(new RegExp(/FROM\s/, 'ig')); @@ -44,3 +48,20 @@ export function getIndexPatternFromSQLQuery(sqlQuery?: string): string { } return ''; } + +// retrieves the index pattern from the aggregate query for ES|QL +export function getIndexPatternFromESQLQuery(esql?: string): string { + const splitFroms = esql?.split(new RegExp(/FROM\s/, 'ig')); + const fromsLength = splitFroms?.length ?? 0; + if (splitFroms && splitFroms?.length > 2) { + esql = `${splitFroms[fromsLength - 2]} FROM ${splitFroms[fromsLength - 1]}`; + } + const parsedString = esql?.replaceAll('`', ''); + // case insensitive match for the index pattern + const regex = new RegExp(/FROM\s+([\w*-.!@$^()~;]+)/, 'i'); + const matches = parsedString?.match(regex); + if (matches) { + return matches[1]; + } + return ''; +} diff --git a/packages/kbn-es-query/src/es_query/index.ts b/packages/kbn-es-query/src/es_query/index.ts index 1dca3a5524cfb..22141a52e93f5 100644 --- a/packages/kbn-es-query/src/es_query/index.ts +++ b/packages/kbn-es-query/src/es_query/index.ts @@ -18,7 +18,9 @@ export { isOfAggregateQueryType, getAggregateQueryMode, getIndexPatternFromSQLQuery, -} from './es_query_sql'; + getLanguageDisplayName, + getIndexPatternFromESQLQuery, +} from './es_aggregate_query'; export { fromCombinedFilter } from './from_combined_filter'; export type { IFieldSubType, diff --git a/packages/kbn-es/README.mdx b/packages/kbn-es/README.mdx index e6e5727ccb897..90bc36bc1da58 100644 --- a/packages/kbn-es/README.mdx +++ b/packages/kbn-es/README.mdx @@ -10,13 +10,19 @@ tags: ['kibana', 'dev', 'contributor', 'operations', 'es'] > A command line utility for running elasticsearch from snapshot, source, archive, docker, serverless or even building snapshot artifacts. ## Getting started +To run, go to the Kibana root and run `node scripts/es --help` to get the latest command line options. + +The script attempts to preserve the existing interfaces used by Elasticsearch CLI. This includes passing through options with the `-E` argument and the `ES_JAVA_OPTS` environment variable for Java options. + If running elasticsearch from source, elasticsearch needs to be cloned to a sibling directory of Kibana. -If running elasticsearch serverless or a docker container, docker is required to be installed locally. Installation instructions can be found [here](https://www.docker.com/). +### Serverless & Docker Prerequisites +If running elasticsearch serverless or a docker container, there is some required initial setup: -To run, go to the Kibana root and run `node scripts/es --help` to get the latest command line options. +1. Install Docker. Instructions can be found [here](https://www.docker.com/). +1. Authentication with Elastic's Docker registry [here](https://docker-auth.elastic.co/github_auth). +1. Increase OS virtual memory limits. More info in the [ES docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/vm-max-map-count.html). -The script attempts to preserve the existing interfaces used by Elasticsearch CLI. This includes passing through options with the `-E` argument and the `ES_JAVA_OPTS` environment variable for Java options. ### Examples diff --git a/packages/kbn-es/src/cli_commands/docker.ts b/packages/kbn-es/src/cli_commands/docker.ts index 07e4a64263b4a..aad68bf0a1dae 100644 --- a/packages/kbn-es/src/cli_commands/docker.ts +++ b/packages/kbn-es/src/cli_commands/docker.ts @@ -28,7 +28,7 @@ export const docker: Command = { --image Full path to image of ES to run, has precedence over tag. [default: ${DOCKER_IMG}] --password Sets password for elastic user [default: ${password}] --port The port to bind to on 127.0.0.1 [default: ${DEFAULT_PORT}] - --ssl Sets up SSL on Elasticsearch + --ssl Sets up SSL and enables security plugin on Elasticsearch --kill Kill running ES nodes if detected -E Additional key=value settings to pass to Elasticsearch -D Override Docker command diff --git a/packages/kbn-es/src/cli_commands/serverless.ts b/packages/kbn-es/src/cli_commands/serverless.ts index 9be9e850a3e6e..51cc1b619017a 100644 --- a/packages/kbn-es/src/cli_commands/serverless.ts +++ b/packages/kbn-es/src/cli_commands/serverless.ts @@ -11,7 +11,7 @@ import getopts from 'getopts'; import { ToolingLog } from '@kbn/tooling-log'; import { getTimeReporter } from '@kbn/ci-stats-reporter'; -import { Cluster } from '../cluster'; +import { Cluster, type ServerlessOptions } from '../cluster'; import { SERVERLESS_REPO, SERVERLESS_TAG, SERVERLESS_IMG, DEFAULT_PORT } from '../utils'; import { Command } from './types'; @@ -26,7 +26,7 @@ export const serverless: Command = { --image Full path of ESS image to run, has precedence over tag. [default: ${SERVERLESS_IMG}] --clean Remove existing file system object store before running --port The port to bind to on 127.0.0.1 [default: ${DEFAULT_PORT}] - --ssl Sets up SSL on Elasticsearch + --ssl Sets up SSL and enables security plugin on Elasticsearch --kill Kill running ESS nodes if detected --background Start ESS without attaching to the first node's logs -E Additional key=value settings to pass to Elasticsearch @@ -58,7 +58,7 @@ export const serverless: Command = { boolean: ['clean', 'ssl', 'kill', 'background'], default: defaults, - }); + }) as unknown as ServerlessOptions; const cluster = new Cluster(); await cluster.runServerless({ diff --git a/packages/kbn-es/src/cluster.js b/packages/kbn-es/src/cluster.js index dbbe3930c734f..084cb9c601578 100644 --- a/packages/kbn-es/src/cluster.js +++ b/packages/kbn-es/src/cluster.js @@ -36,7 +36,7 @@ const DEFAULT_READY_TIMEOUT = parseTimeoutToMs('1m'); /** @typedef {import('./cluster_exec_options').EsClusterExecOptions} ExecOptions */ /** @typedef {import('./utils').DockerOptions} DockerOptions */ -/** @typedef {import('./utils').ServerlessOptions}ServerlessrOptions */ +/** @typedef {import('./utils').ServerlessOptions}ServerlessOptions */ // listen to data on stream until map returns anything but undefined const first = (stream, map) => diff --git a/packages/kbn-es/src/utils/docker.test.ts b/packages/kbn-es/src/utils/docker.test.ts index c42ac1af577f0..35696e1f91af8 100644 --- a/packages/kbn-es/src/utils/docker.test.ts +++ b/packages/kbn-es/src/utils/docker.test.ts @@ -34,6 +34,11 @@ import { ESS_RESOURCES_PATHS } from '../paths'; jest.mock('execa'); const execa = jest.requireMock('execa'); +jest.mock('@elastic/elasticsearch', () => { + return { + Client: jest.fn(), + }; +}); const log = new ToolingLog(); const logWriter = new ToolingLogCollectingWriter(); @@ -465,6 +470,22 @@ describe('runServerlessCluster()', () => { // setupDocker execa calls then run three nodes and attach logger expect(execa.mock.calls).toHaveLength(8); }); + describe('waitForReady', () => { + test('should wait for serverless nodes to be ready to serve requests', async () => { + mockFs({ + [baseEsPath]: {}, + }); + execa.mockImplementation(() => Promise.resolve({ stdout: '' })); + const info = jest.fn(); + jest.requireMock('@elastic/elasticsearch').Client.mockImplementation(() => ({ info })); + + info.mockImplementationOnce(() => Promise.reject()); // first call fails + info.mockImplementationOnce(() => Promise.resolve()); // then succeeds + + await runServerlessCluster(log, { basePath: baseEsPath, waitForReady: true }); + expect(info).toHaveBeenCalledTimes(2); + }); + }); }); describe('stopServerlessCluster()', () => { diff --git a/packages/kbn-es/src/utils/docker.ts b/packages/kbn-es/src/utils/docker.ts index 381d3c13769d8..01db89a14c6ab 100644 --- a/packages/kbn-es/src/utils/docker.ts +++ b/packages/kbn-es/src/utils/docker.ts @@ -10,6 +10,7 @@ import execa from 'execa'; import fs from 'fs'; import Fsp from 'fs/promises'; import { resolve, basename, join } from 'path'; +import { Client, HttpConnection } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/tooling-log'; import { kibanaPackageJson as pkg, REPO_ROOT } from '@kbn/repo-info'; @@ -24,12 +25,18 @@ import { ESS_CONFIG_PATH, ESS_FILES_PATH, } from '../paths'; +import { + ELASTIC_SERVERLESS_SUPERUSER, + ELASTIC_SERVERLESS_SUPERUSER_PASSWORD, +} from './ess_file_realm'; +import { SYSTEM_INDICES_SUPERUSER } from './native_realm'; interface BaseOptions { tag?: string; image?: string; port?: number; ssl?: boolean; + /** Kill running cluster before starting a new cluster */ kill?: boolean; files?: string | string[]; } @@ -39,10 +46,16 @@ export interface DockerOptions extends EsClusterExecOptions, BaseOptions { } export interface ServerlessOptions extends EsClusterExecOptions, BaseOptions { + /** Clean (or delete) all data created by the ES cluster after it is stopped */ clean?: boolean; + /** Path to the directory where the ES cluster will store data */ basePath: string; + /** If this process exits, teardown the ES cluster as well */ teardown?: boolean; + /** Start the ES cluster in the background instead of remaining attached: useful for running tests */ background?: boolean; + /** Wait for the ES cluster to be ready to serve requests */ + waitForReady?: boolean; } interface ServerlessEsNodeArgs { @@ -320,10 +333,14 @@ export async function maybePullDockerImage(log: ToolingLog, image: string) { log.info(chalk.bold(`Checking for image: ${image}`)); await execa('docker', ['pull', image], { - // inherit is required to show Docker output - stdio: ['ignore', 'inherit', 'inherit'], - }).catch(({ message }) => { - throw createCliError(message); + // inherit is required to show Docker pull output + stdio: ['ignore', 'inherit', 'pipe'], + }).catch(({ message, stderr }) => { + throw createCliError( + stderr.includes('unauthorized: authentication required') + ? `Error authenticating with ${DOCKER_REGISTRY}. Visit https://docker-auth.elastic.co/github_auth to login.` + : message + ); }); } @@ -393,6 +410,14 @@ export function resolveEsArgs( args.forEach((arg) => { const [key, ...value] = arg.split('='); + + // Guide the user to use SSL flag instead of manual setup + if (key === 'xpack.security.enabled' && value?.[0] === 'true') { + throw createCliError( + 'Use the --ssl flag to automatically enable and set up the security plugin.' + ); + } + esArgs.set(key.trim(), value.join('=').trim()); }); } @@ -522,6 +547,30 @@ export async function runServerlessEsNode( ); } +function getESClient( + { node }: { node: string } = { node: `http://localhost:${DEFAULT_PORT}` } +): Client { + return new Client({ + node, + Connection: HttpConnection, + }); +} + +const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)); +async function waitUntilClusterReady(timeoutMs = 60 * 1000): Promise { + const started = Date.now(); + const client = getESClient(); + while (started + timeoutMs > Date.now()) { + try { + await client.info(); + break; + } catch (e) { + await delay(1000); + /* trap to continue */ + } + } +} + /** * Runs an ES Serverless Cluster through Docker */ @@ -556,6 +605,26 @@ export async function runServerlessCluster(log: ToolingLog, options: ServerlessO Stop the cluster: ${chalk.bold(`docker container stop ${nodeNames.join(' ')}`)} `); + if (options.ssl) { + log.success(`SSL and Security have been enabled for ES. + Login through your browser with username ${chalk.bold.cyan( + ELASTIC_SERVERLESS_SUPERUSER + )} or ${chalk.bold.cyan(SYSTEM_INDICES_SUPERUSER)} and password ${chalk.bold.magenta( + ELASTIC_SERVERLESS_SUPERUSER_PASSWORD + )}. + `); + + log.warning(`Kibana should be started with the SSL flag so that it can authenticate with ES. + See packages/kbn-es/src/ess_resources/README.md for additional information on authentication. + `); + } + + if (options.waitForReady) { + log.info('Waiting until ES is ready to serve requests...'); + await waitUntilClusterReady(); + log.success('ES is ready'); + } + if (!options.background) { // The ESS cluster has to be started detached, so we attach a logger afterwards for output await execa('docker', ['logs', '-f', SERVERLESS_NODES[0].name], { diff --git a/packages/kbn-monaco/src/esql/antlr/.gitignore b/packages/kbn-monaco/src/esql/antlr/.gitignore new file mode 100644 index 0000000000000..f7754e5f01083 --- /dev/null +++ b/packages/kbn-monaco/src/esql/antlr/.gitignore @@ -0,0 +1 @@ +.antlr/* \ No newline at end of file diff --git a/packages/kbn-monaco/src/esql/antlr/esql_lexer.g4 b/packages/kbn-monaco/src/esql/antlr/esql_lexer.g4 index 49d73416712a8..b5688e0915a33 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_lexer.g4 +++ b/packages/kbn-monaco/src/esql/antlr/esql_lexer.g4 @@ -7,15 +7,23 @@ lexer grammar esql_lexer; -EVAL : 'eval' -> pushMode(EXPRESSION); -EXPLAIN : 'explain' -> pushMode(EXPRESSION); -FROM : 'from' -> pushMode(SOURCE_IDENTIFIERS); -ROW : 'row' -> pushMode(EXPRESSION); -STATS : 'stats' -> pushMode(EXPRESSION); -WHERE : 'where' -> pushMode(EXPRESSION); -SORT : 'sort' -> pushMode(EXPRESSION); -LIMIT : 'limit' -> pushMode(EXPRESSION); -PROJECT : 'project' -> pushMode(SOURCE_IDENTIFIERS); +DISSECT : D I S S E C T -> pushMode(EXPRESSION); +GROK : G R O K -> pushMode(EXPRESSION); +EVAL : E V A L -> pushMode(EXPRESSION); +EXPLAIN : E X P L A I N -> pushMode(EXPLAIN_MODE); +FROM : F R O M -> pushMode(SOURCE_IDENTIFIERS); +ROW : R O W -> pushMode(EXPRESSION); +STATS : S T A T S -> pushMode(EXPRESSION); +WHERE : W H E R E -> pushMode(EXPRESSION); +SORT : S O R T -> pushMode(EXPRESSION); +MV_EXPAND : M V UNDERSCORE E X P A N D -> pushMode(EXPRESSION); +LIMIT : L I M I T -> pushMode(EXPRESSION); +PROJECT : P R O J E C T -> pushMode(EXPRESSION); +DROP : D R O P -> pushMode(EXPRESSION); +RENAME : R E N A M E -> pushMode(EXPRESSION); +SHOW : S H O W -> pushMode(EXPRESSION); +ENRICH : E N R I C H -> pushMode(ENRICH_IDENTIFIERS); +KEEP : K E E P -> pushMode(EXPRESSION); LINE_COMMENT : '//' ~[\r\n]* '\r'? '\n'? -> channel(HIDDEN) @@ -28,7 +36,12 @@ MULTILINE_COMMENT WS : [ \r\n\t]+ -> channel(HIDDEN) ; - +mode EXPLAIN_MODE; +EXPLAIN_OPENING_BRACKET : '[' -> type(OPENING_BRACKET), pushMode(DEFAULT_MODE); +EXPLAIN_PIPE : '|' -> type(PIPE), popMode; +EXPLAIN_WS : WS -> channel(HIDDEN); +EXPLAIN_LINE_COMMENT : LINE_COMMENT -> channel(HIDDEN); +EXPLAIN_MULTILINE_COMMENT : MULTILINE_COMMENT -> channel(HIDDEN); mode EXPRESSION; PIPE : '|' -> popMode; @@ -71,17 +84,34 @@ DECIMAL_LITERAL BY : 'by'; +DATE_LITERAL + : 'year' + | 'month' + | 'day' + | 'second' + | 'minute' + | 'hour' + ; + AND : 'and'; ASSIGN : '='; COMMA : ','; DOT : '.'; LP : '('; -OPENING_BRACKET : '[' -> pushMode(DEFAULT_MODE); -CLOSING_BRACKET : ']' -> popMode, popMode; // pop twice, once to clear mode of current cmd and once to exit DEFAULT_MODE -NOT : 'not'; -NULL : 'null'; +OPENING_BRACKET : '[' -> pushMode(EXPRESSION), pushMode(EXPRESSION); +CLOSING_BRACKET : ']' -> popMode, popMode; +NOT : N O T; +LIKE: L I K E; +RLIKE: R L I K E; +IN: I N; +IS: I S; +AS: A S; +NULL : N U L L; OR : 'or'; RP : ')'; +UNDERSCORE: '_'; +INFO : 'info'; +FUNCTIONS : 'functions'; BOOLEAN_VALUE : 'true' @@ -102,6 +132,7 @@ MINUS : '-'; ASTERISK : '*'; SLASH : '/'; PERCENT : '%'; +TEN: '10'; ORDERING : 'asc' @@ -114,16 +145,74 @@ NULLS_ORDERING_DIRECTION | 'last' ; +MATH_FUNCTION + : R O U N D + | A B S + | P O W + | L O G TEN + | P I + | T A U + | E + | S U B S T R I N G + | T R I M + | C O N C A T + | S T A R T S UNDERSCORE W I T H + | D A T E UNDERSCORE F O R M A T + | D A T E UNDERSCORE T R U N C + | D A T E UNDERSCORE P A R S E + | A U T O UNDERSCORE B U C K E T + | I S UNDERSCORE F I N I T E + | I S UNDERSCORE I N F I N I T E + | C A S E + | L E N G T H + | M V UNDERSCORE M A X + | M V UNDERSCORE M I N + | M V UNDERSCORE A V G + | M V UNDERSCORE S U M + | M V UNDERSCORE C O U N T + | M V UNDERSCORE C O N C A T + | M V UNDERSCORE J O I N + | M V UNDERSCORE M E D I A N + | M V UNDERSCORE D E D U P E + | M E T A D A T A + | S P L I T + | T O UNDERSCORE S T R I N G + | T O UNDERSCORE S T R + | T O UNDERSCORE B O O L + | T O UNDERSCORE B O O L E A N + | T O UNDERSCORE D A T E T I M E + | T O UNDERSCORE D T + | T O UNDERSCORE D B L + | T O UNDERSCORE D O U B L E + | T O UNDERSCORE I N T + | T O UNDERSCORE I N T E G E R + | T O UNDERSCORE L O N G + | T O UNDERSCORE I P + | T O UNDERSCORE V E R S I O N + | T O UNDERSCORE U N S I G N E D UNDERSCORE L O N G + ; + UNARY_FUNCTION - : 'round' - | 'avg' - | 'min' - | 'max' - | 'sum' + : A V G + | M I N + | M A X + | S U M + | C O U N T + | C O U N T UNDERSCORE D I S T I N C T + | P E R C E N T I L E + | M E D I A N + | M E D I A N UNDERSCORE A B S O L U T E UNDERSCORE D E V I A T I O N + ; + +WHERE_FUNCTIONS + : C I D R UNDERSCORE M A T C H ; UNQUOTED_IDENTIFIER - : (LETTER | '_') (LETTER | DIGIT | '_')* + : LETTER (LETTER | DIGIT | '_' | ASTERISK)* + // only allow @ at beginning of identifier to keep the option to allow @ as infix operator in the future + // also, single `_` and `@` characters are not valid identifiers + | ('_' | '@') (LETTER | DIGIT | '_' | ASTERISK)+ ; QUOTED_IDENTIFIER @@ -146,9 +235,11 @@ EXPR_WS mode SOURCE_IDENTIFIERS; SRC_PIPE : '|' -> type(PIPE), popMode; +SRC_OPENING_BRACKET : '[' -> type(OPENING_BRACKET), pushMode(SOURCE_IDENTIFIERS), pushMode(SOURCE_IDENTIFIERS); SRC_CLOSING_BRACKET : ']' -> popMode, popMode, type(CLOSING_BRACKET); SRC_COMMA : ',' -> type(COMMA); SRC_ASSIGN : '=' -> type(ASSIGN); +METADATA: M E T A D A T A; SRC_UNQUOTED_IDENTIFIER : SRC_UNQUOTED_IDENTIFIER_PART+ @@ -174,3 +265,65 @@ SRC_MULTILINE_COMMENT SRC_WS : WS -> channel(HIDDEN) ; + +mode ENRICH_IDENTIFIERS; + +ON : O N; +WITH : W I T H; + +ENR_PIPE : '|' -> type(PIPE), popMode; +ENR_CLOSING_BRACKET : ']' -> popMode, popMode, type(CLOSING_BRACKET); +ENR_COMMA : ',' -> type(COMMA); +ENR_ASSIGN : '=' -> type(ASSIGN); + +ENR_UNQUOTED_IDENTIFIER + : ENR_UNQUOTED_IDENTIFIER_PART+ + ; + +fragment ENR_UNQUOTED_IDENTIFIER_PART + : ~[=`|,[\]/ \t\r\n]+ + | '/' ~[*/] // allow single / but not followed by another / or * which would start a comment + ; + +ENR_QUOTED_IDENTIFIER + : QUOTED_IDENTIFIER + ; + +ENR_LINE_COMMENT + : LINE_COMMENT -> channel(HIDDEN) + ; + +ENR_MULTILINE_COMMENT + : MULTILINE_COMMENT -> channel(HIDDEN) + ; + +ENR_WS + : WS -> channel(HIDDEN) + ; + +fragment A : [aA]; // match either an 'a' or 'A' +fragment B : [bB]; +fragment C : [cC]; +fragment D : [dD]; +fragment E : [eE]; +fragment F : [fF]; +fragment G : [gG]; +fragment H : [hH]; +fragment I : [iI]; +fragment J : [jJ]; +fragment K : [kK]; +fragment L : [lL]; +fragment M : [mM]; +fragment N : [nN]; +fragment O : [oO]; +fragment P : [pP]; +fragment Q : [qQ]; +fragment R : [rR]; +fragment S : [sS]; +fragment T : [tT]; +fragment U : [uU]; +fragment V : [vV]; +fragment W : [wW]; +fragment X : [xX]; +fragment Y : [yY]; +fragment Z : [zZ]; \ No newline at end of file diff --git a/packages/kbn-monaco/src/esql/antlr/esql_lexer.interp b/packages/kbn-monaco/src/esql/antlr/esql_lexer.interp index a7fee84591c3b..394ed7fc4ee63 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_lexer.interp +++ b/packages/kbn-monaco/src/esql/antlr/esql_lexer.interp @@ -1,14 +1,25 @@ token literal names: null -'eval' -'explain' -'from' -'row' -'stats' -'where' -'sort' -'limit' -'project' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null null null null @@ -17,17 +28,26 @@ null null null 'by' +null 'and' null null '.' '(' -'[' +null ']' -'not' -'null' +null +null +null +null +null +null +null 'or' ')' +'_' +'info' +'functions' null null '+' @@ -35,6 +55,7 @@ null '*' '/' '%' +'10' null 'nulls' null @@ -49,9 +70,22 @@ null null null null +null +null +null +null +null +null +null +null +null +null +null token symbolic names: null +DISSECT +GROK EVAL EXPLAIN FROM @@ -59,16 +93,26 @@ ROW STATS WHERE SORT +MV_EXPAND LIMIT PROJECT +DROP +RENAME +SHOW +ENRICH +KEEP LINE_COMMENT MULTILINE_COMMENT WS +EXPLAIN_WS +EXPLAIN_LINE_COMMENT +EXPLAIN_MULTILINE_COMMENT PIPE STRING INTEGER_LITERAL DECIMAL_LITERAL BY +DATE_LITERAL AND ASSIGN COMMA @@ -77,9 +121,17 @@ LP OPENING_BRACKET CLOSING_BRACKET NOT +LIKE +RLIKE +IN +IS +AS NULL OR RP +UNDERSCORE +INFO +FUNCTIONS BOOLEAN_VALUE COMPARISON_OPERATOR PLUS @@ -87,22 +139,36 @@ MINUS ASTERISK SLASH PERCENT +TEN ORDERING NULLS_ORDERING NULLS_ORDERING_DIRECTION +MATH_FUNCTION UNARY_FUNCTION +WHERE_FUNCTIONS UNQUOTED_IDENTIFIER QUOTED_IDENTIFIER EXPR_LINE_COMMENT EXPR_MULTILINE_COMMENT EXPR_WS +METADATA SRC_UNQUOTED_IDENTIFIER SRC_QUOTED_IDENTIFIER SRC_LINE_COMMENT SRC_MULTILINE_COMMENT SRC_WS +ON +WITH +ENR_UNQUOTED_IDENTIFIER +ENR_QUOTED_IDENTIFIER +ENR_LINE_COMMENT +ENR_MULTILINE_COMMENT +ENR_WS +EXPLAIN_PIPE rule names: +DISSECT +GROK EVAL EXPLAIN FROM @@ -110,11 +176,22 @@ ROW STATS WHERE SORT +MV_EXPAND LIMIT PROJECT +DROP +RENAME +SHOW +ENRICH +KEEP LINE_COMMENT MULTILINE_COMMENT WS +EXPLAIN_OPENING_BRACKET +EXPLAIN_PIPE +EXPLAIN_WS +EXPLAIN_LINE_COMMENT +EXPLAIN_MULTILINE_COMMENT PIPE DIGIT LETTER @@ -125,6 +202,7 @@ STRING INTEGER_LITERAL DECIMAL_LITERAL BY +DATE_LITERAL AND ASSIGN COMMA @@ -133,9 +211,17 @@ LP OPENING_BRACKET CLOSING_BRACKET NOT +LIKE +RLIKE +IN +IS +AS NULL OR RP +UNDERSCORE +INFO +FUNCTIONS BOOLEAN_VALUE COMPARISON_OPERATOR PLUS @@ -143,25 +229,68 @@ MINUS ASTERISK SLASH PERCENT +TEN ORDERING NULLS_ORDERING NULLS_ORDERING_DIRECTION +MATH_FUNCTION UNARY_FUNCTION +WHERE_FUNCTIONS UNQUOTED_IDENTIFIER QUOTED_IDENTIFIER EXPR_LINE_COMMENT EXPR_MULTILINE_COMMENT EXPR_WS SRC_PIPE +SRC_OPENING_BRACKET SRC_CLOSING_BRACKET SRC_COMMA SRC_ASSIGN +METADATA SRC_UNQUOTED_IDENTIFIER SRC_UNQUOTED_IDENTIFIER_PART SRC_QUOTED_IDENTIFIER SRC_LINE_COMMENT SRC_MULTILINE_COMMENT SRC_WS +ON +WITH +ENR_PIPE +ENR_CLOSING_BRACKET +ENR_COMMA +ENR_ASSIGN +ENR_UNQUOTED_IDENTIFIER +ENR_UNQUOTED_IDENTIFIER_PART +ENR_QUOTED_IDENTIFIER +ENR_LINE_COMMENT +ENR_MULTILINE_COMMENT +ENR_WS +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +X +Y +Z channel names: DEFAULT_TOKEN_CHANNEL @@ -169,8 +298,10 @@ HIDDEN mode names: DEFAULT_MODE +EXPLAIN_MODE EXPRESSION SOURCE_IDENTIFIERS +ENRICH_IDENTIFIERS atn: -[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 2, 51, 533, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 199, 10, 11, 12, 11, 14, 11, 202, 11, 11, 3, 11, 5, 11, 205, 10, 11, 3, 11, 5, 11, 208, 10, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 7, 12, 217, 10, 12, 12, 12, 14, 12, 220, 11, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 6, 13, 228, 10, 13, 13, 13, 14, 13, 229, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 5, 19, 249, 10, 19, 3, 19, 6, 19, 252, 10, 19, 13, 19, 14, 19, 253, 3, 20, 3, 20, 3, 20, 7, 20, 259, 10, 20, 12, 20, 14, 20, 262, 11, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 7, 20, 270, 10, 20, 12, 20, 14, 20, 273, 11, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 280, 10, 20, 3, 20, 5, 20, 283, 10, 20, 5, 20, 285, 10, 20, 3, 21, 6, 21, 288, 10, 21, 13, 21, 14, 21, 289, 3, 22, 6, 22, 293, 10, 22, 13, 22, 14, 22, 294, 3, 22, 3, 22, 7, 22, 299, 10, 22, 12, 22, 14, 22, 302, 11, 22, 3, 22, 3, 22, 6, 22, 306, 10, 22, 13, 22, 14, 22, 307, 3, 22, 6, 22, 311, 10, 22, 13, 22, 14, 22, 312, 3, 22, 3, 22, 7, 22, 317, 10, 22, 12, 22, 14, 22, 320, 11, 22, 5, 22, 322, 10, 22, 3, 22, 3, 22, 3, 22, 3, 22, 6, 22, 328, 10, 22, 13, 22, 14, 22, 329, 3, 22, 3, 22, 5, 22, 334, 10, 22, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 3, 35, 5, 35, 383, 10, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 5, 36, 395, 10, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 5, 42, 414, 10, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 5, 44, 431, 10, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 5, 45, 450, 10, 45, 3, 46, 3, 46, 5, 46, 454, 10, 46, 3, 46, 3, 46, 3, 46, 7, 46, 459, 10, 46, 12, 46, 14, 46, 462, 11, 46, 3, 47, 3, 47, 3, 47, 3, 47, 7, 47, 468, 10, 47, 12, 47, 14, 47, 471, 11, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 6, 55, 507, 10, 55, 13, 55, 14, 55, 508, 3, 56, 6, 56, 512, 10, 56, 13, 56, 14, 56, 513, 3, 56, 3, 56, 5, 56, 518, 10, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 60, 3, 60, 3, 60, 3, 60, 4, 218, 271, 2, 2, 61, 5, 2, 3, 7, 2, 4, 9, 2, 5, 11, 2, 6, 13, 2, 7, 15, 2, 8, 17, 2, 9, 19, 2, 10, 21, 2, 11, 23, 2, 12, 25, 2, 13, 27, 2, 14, 29, 2, 15, 31, 2, 2, 33, 2, 2, 35, 2, 2, 37, 2, 2, 39, 2, 2, 41, 2, 16, 43, 2, 17, 45, 2, 18, 47, 2, 19, 49, 2, 20, 51, 2, 21, 53, 2, 22, 55, 2, 23, 57, 2, 24, 59, 2, 25, 61, 2, 26, 63, 2, 27, 65, 2, 28, 67, 2, 29, 69, 2, 30, 71, 2, 31, 73, 2, 32, 75, 2, 33, 77, 2, 34, 79, 2, 35, 81, 2, 36, 83, 2, 37, 85, 2, 38, 87, 2, 39, 89, 2, 40, 91, 2, 41, 93, 2, 42, 95, 2, 43, 97, 2, 44, 99, 2, 45, 101, 2, 46, 103, 2, 2, 105, 2, 2, 107, 2, 2, 109, 2, 2, 111, 2, 47, 113, 2, 2, 115, 2, 48, 117, 2, 49, 119, 2, 50, 121, 2, 51, 5, 2, 3, 4, 13, 4, 2, 12, 12, 15, 15, 5, 2, 11, 12, 15, 15, 34, 34, 3, 2, 50, 59, 4, 2, 67, 92, 99, 124, 7, 2, 36, 36, 94, 94, 112, 112, 116, 116, 118, 118, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 3, 2, 98, 98, 12, 2, 11, 12, 15, 15, 34, 34, 46, 46, 49, 49, 63, 63, 93, 93, 95, 95, 98, 98, 126, 126, 4, 2, 44, 44, 49, 49, 2, 570, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 3, 29, 3, 2, 2, 2, 3, 41, 3, 2, 2, 2, 3, 43, 3, 2, 2, 2, 3, 45, 3, 2, 2, 2, 3, 47, 3, 2, 2, 2, 3, 49, 3, 2, 2, 2, 3, 51, 3, 2, 2, 2, 3, 53, 3, 2, 2, 2, 3, 55, 3, 2, 2, 2, 3, 57, 3, 2, 2, 2, 3, 59, 3, 2, 2, 2, 3, 61, 3, 2, 2, 2, 3, 63, 3, 2, 2, 2, 3, 65, 3, 2, 2, 2, 3, 67, 3, 2, 2, 2, 3, 69, 3, 2, 2, 2, 3, 71, 3, 2, 2, 2, 3, 73, 3, 2, 2, 2, 3, 75, 3, 2, 2, 2, 3, 77, 3, 2, 2, 2, 3, 79, 3, 2, 2, 2, 3, 81, 3, 2, 2, 2, 3, 83, 3, 2, 2, 2, 3, 85, 3, 2, 2, 2, 3, 87, 3, 2, 2, 2, 3, 89, 3, 2, 2, 2, 3, 91, 3, 2, 2, 2, 3, 93, 3, 2, 2, 2, 3, 95, 3, 2, 2, 2, 3, 97, 3, 2, 2, 2, 3, 99, 3, 2, 2, 2, 3, 101, 3, 2, 2, 2, 4, 103, 3, 2, 2, 2, 4, 105, 3, 2, 2, 2, 4, 107, 3, 2, 2, 2, 4, 109, 3, 2, 2, 2, 4, 111, 3, 2, 2, 2, 4, 115, 3, 2, 2, 2, 4, 117, 3, 2, 2, 2, 4, 119, 3, 2, 2, 2, 4, 121, 3, 2, 2, 2, 5, 123, 3, 2, 2, 2, 7, 130, 3, 2, 2, 2, 9, 140, 3, 2, 2, 2, 11, 147, 3, 2, 2, 2, 13, 153, 3, 2, 2, 2, 15, 161, 3, 2, 2, 2, 17, 169, 3, 2, 2, 2, 19, 176, 3, 2, 2, 2, 21, 184, 3, 2, 2, 2, 23, 194, 3, 2, 2, 2, 25, 211, 3, 2, 2, 2, 27, 227, 3, 2, 2, 2, 29, 233, 3, 2, 2, 2, 31, 237, 3, 2, 2, 2, 33, 239, 3, 2, 2, 2, 35, 241, 3, 2, 2, 2, 37, 244, 3, 2, 2, 2, 39, 246, 3, 2, 2, 2, 41, 284, 3, 2, 2, 2, 43, 287, 3, 2, 2, 2, 45, 333, 3, 2, 2, 2, 47, 335, 3, 2, 2, 2, 49, 338, 3, 2, 2, 2, 51, 342, 3, 2, 2, 2, 53, 344, 3, 2, 2, 2, 55, 346, 3, 2, 2, 2, 57, 348, 3, 2, 2, 2, 59, 350, 3, 2, 2, 2, 61, 354, 3, 2, 2, 2, 63, 359, 3, 2, 2, 2, 65, 363, 3, 2, 2, 2, 67, 368, 3, 2, 2, 2, 69, 371, 3, 2, 2, 2, 71, 382, 3, 2, 2, 2, 73, 394, 3, 2, 2, 2, 75, 396, 3, 2, 2, 2, 77, 398, 3, 2, 2, 2, 79, 400, 3, 2, 2, 2, 81, 402, 3, 2, 2, 2, 83, 404, 3, 2, 2, 2, 85, 413, 3, 2, 2, 2, 87, 415, 3, 2, 2, 2, 89, 430, 3, 2, 2, 2, 91, 449, 3, 2, 2, 2, 93, 453, 3, 2, 2, 2, 95, 463, 3, 2, 2, 2, 97, 474, 3, 2, 2, 2, 99, 478, 3, 2, 2, 2, 101, 482, 3, 2, 2, 2, 103, 486, 3, 2, 2, 2, 105, 491, 3, 2, 2, 2, 107, 497, 3, 2, 2, 2, 109, 501, 3, 2, 2, 2, 111, 506, 3, 2, 2, 2, 113, 517, 3, 2, 2, 2, 115, 519, 3, 2, 2, 2, 117, 521, 3, 2, 2, 2, 119, 525, 3, 2, 2, 2, 121, 529, 3, 2, 2, 2, 123, 124, 7, 103, 2, 2, 124, 125, 7, 120, 2, 2, 125, 126, 7, 99, 2, 2, 126, 127, 7, 110, 2, 2, 127, 128, 3, 2, 2, 2, 128, 129, 8, 2, 2, 2, 129, 6, 3, 2, 2, 2, 130, 131, 7, 103, 2, 2, 131, 132, 7, 122, 2, 2, 132, 133, 7, 114, 2, 2, 133, 134, 7, 110, 2, 2, 134, 135, 7, 99, 2, 2, 135, 136, 7, 107, 2, 2, 136, 137, 7, 112, 2, 2, 137, 138, 3, 2, 2, 2, 138, 139, 8, 3, 2, 2, 139, 8, 3, 2, 2, 2, 140, 141, 7, 104, 2, 2, 141, 142, 7, 116, 2, 2, 142, 143, 7, 113, 2, 2, 143, 144, 7, 111, 2, 2, 144, 145, 3, 2, 2, 2, 145, 146, 8, 4, 3, 2, 146, 10, 3, 2, 2, 2, 147, 148, 7, 116, 2, 2, 148, 149, 7, 113, 2, 2, 149, 150, 7, 121, 2, 2, 150, 151, 3, 2, 2, 2, 151, 152, 8, 5, 2, 2, 152, 12, 3, 2, 2, 2, 153, 154, 7, 117, 2, 2, 154, 155, 7, 118, 2, 2, 155, 156, 7, 99, 2, 2, 156, 157, 7, 118, 2, 2, 157, 158, 7, 117, 2, 2, 158, 159, 3, 2, 2, 2, 159, 160, 8, 6, 2, 2, 160, 14, 3, 2, 2, 2, 161, 162, 7, 121, 2, 2, 162, 163, 7, 106, 2, 2, 163, 164, 7, 103, 2, 2, 164, 165, 7, 116, 2, 2, 165, 166, 7, 103, 2, 2, 166, 167, 3, 2, 2, 2, 167, 168, 8, 7, 2, 2, 168, 16, 3, 2, 2, 2, 169, 170, 7, 117, 2, 2, 170, 171, 7, 113, 2, 2, 171, 172, 7, 116, 2, 2, 172, 173, 7, 118, 2, 2, 173, 174, 3, 2, 2, 2, 174, 175, 8, 8, 2, 2, 175, 18, 3, 2, 2, 2, 176, 177, 7, 110, 2, 2, 177, 178, 7, 107, 2, 2, 178, 179, 7, 111, 2, 2, 179, 180, 7, 107, 2, 2, 180, 181, 7, 118, 2, 2, 181, 182, 3, 2, 2, 2, 182, 183, 8, 9, 2, 2, 183, 20, 3, 2, 2, 2, 184, 185, 7, 114, 2, 2, 185, 186, 7, 116, 2, 2, 186, 187, 7, 113, 2, 2, 187, 188, 7, 108, 2, 2, 188, 189, 7, 103, 2, 2, 189, 190, 7, 101, 2, 2, 190, 191, 7, 118, 2, 2, 191, 192, 3, 2, 2, 2, 192, 193, 8, 10, 3, 2, 193, 22, 3, 2, 2, 2, 194, 195, 7, 49, 2, 2, 195, 196, 7, 49, 2, 2, 196, 200, 3, 2, 2, 2, 197, 199, 10, 2, 2, 2, 198, 197, 3, 2, 2, 2, 199, 202, 3, 2, 2, 2, 200, 198, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 204, 3, 2, 2, 2, 202, 200, 3, 2, 2, 2, 203, 205, 7, 15, 2, 2, 204, 203, 3, 2, 2, 2, 204, 205, 3, 2, 2, 2, 205, 207, 3, 2, 2, 2, 206, 208, 7, 12, 2, 2, 207, 206, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 209, 3, 2, 2, 2, 209, 210, 8, 11, 4, 2, 210, 24, 3, 2, 2, 2, 211, 212, 7, 49, 2, 2, 212, 213, 7, 44, 2, 2, 213, 218, 3, 2, 2, 2, 214, 217, 5, 25, 12, 2, 215, 217, 11, 2, 2, 2, 216, 214, 3, 2, 2, 2, 216, 215, 3, 2, 2, 2, 217, 220, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 221, 3, 2, 2, 2, 220, 218, 3, 2, 2, 2, 221, 222, 7, 44, 2, 2, 222, 223, 7, 49, 2, 2, 223, 224, 3, 2, 2, 2, 224, 225, 8, 12, 4, 2, 225, 26, 3, 2, 2, 2, 226, 228, 9, 3, 2, 2, 227, 226, 3, 2, 2, 2, 228, 229, 3, 2, 2, 2, 229, 227, 3, 2, 2, 2, 229, 230, 3, 2, 2, 2, 230, 231, 3, 2, 2, 2, 231, 232, 8, 13, 4, 2, 232, 28, 3, 2, 2, 2, 233, 234, 7, 126, 2, 2, 234, 235, 3, 2, 2, 2, 235, 236, 8, 14, 5, 2, 236, 30, 3, 2, 2, 2, 237, 238, 9, 4, 2, 2, 238, 32, 3, 2, 2, 2, 239, 240, 9, 5, 2, 2, 240, 34, 3, 2, 2, 2, 241, 242, 7, 94, 2, 2, 242, 243, 9, 6, 2, 2, 243, 36, 3, 2, 2, 2, 244, 245, 10, 7, 2, 2, 245, 38, 3, 2, 2, 2, 246, 248, 9, 8, 2, 2, 247, 249, 9, 9, 2, 2, 248, 247, 3, 2, 2, 2, 248, 249, 3, 2, 2, 2, 249, 251, 3, 2, 2, 2, 250, 252, 5, 31, 15, 2, 251, 250, 3, 2, 2, 2, 252, 253, 3, 2, 2, 2, 253, 251, 3, 2, 2, 2, 253, 254, 3, 2, 2, 2, 254, 40, 3, 2, 2, 2, 255, 260, 7, 36, 2, 2, 256, 259, 5, 35, 17, 2, 257, 259, 5, 37, 18, 2, 258, 256, 3, 2, 2, 2, 258, 257, 3, 2, 2, 2, 259, 262, 3, 2, 2, 2, 260, 258, 3, 2, 2, 2, 260, 261, 3, 2, 2, 2, 261, 263, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 263, 285, 7, 36, 2, 2, 264, 265, 7, 36, 2, 2, 265, 266, 7, 36, 2, 2, 266, 267, 7, 36, 2, 2, 267, 271, 3, 2, 2, 2, 268, 270, 10, 2, 2, 2, 269, 268, 3, 2, 2, 2, 270, 273, 3, 2, 2, 2, 271, 272, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 272, 274, 3, 2, 2, 2, 273, 271, 3, 2, 2, 2, 274, 275, 7, 36, 2, 2, 275, 276, 7, 36, 2, 2, 276, 277, 7, 36, 2, 2, 277, 279, 3, 2, 2, 2, 278, 280, 7, 36, 2, 2, 279, 278, 3, 2, 2, 2, 279, 280, 3, 2, 2, 2, 280, 282, 3, 2, 2, 2, 281, 283, 7, 36, 2, 2, 282, 281, 3, 2, 2, 2, 282, 283, 3, 2, 2, 2, 283, 285, 3, 2, 2, 2, 284, 255, 3, 2, 2, 2, 284, 264, 3, 2, 2, 2, 285, 42, 3, 2, 2, 2, 286, 288, 5, 31, 15, 2, 287, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 287, 3, 2, 2, 2, 289, 290, 3, 2, 2, 2, 290, 44, 3, 2, 2, 2, 291, 293, 5, 31, 15, 2, 292, 291, 3, 2, 2, 2, 293, 294, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 296, 3, 2, 2, 2, 296, 300, 5, 55, 27, 2, 297, 299, 5, 31, 15, 2, 298, 297, 3, 2, 2, 2, 299, 302, 3, 2, 2, 2, 300, 298, 3, 2, 2, 2, 300, 301, 3, 2, 2, 2, 301, 334, 3, 2, 2, 2, 302, 300, 3, 2, 2, 2, 303, 305, 5, 55, 27, 2, 304, 306, 5, 31, 15, 2, 305, 304, 3, 2, 2, 2, 306, 307, 3, 2, 2, 2, 307, 305, 3, 2, 2, 2, 307, 308, 3, 2, 2, 2, 308, 334, 3, 2, 2, 2, 309, 311, 5, 31, 15, 2, 310, 309, 3, 2, 2, 2, 311, 312, 3, 2, 2, 2, 312, 310, 3, 2, 2, 2, 312, 313, 3, 2, 2, 2, 313, 321, 3, 2, 2, 2, 314, 318, 5, 55, 27, 2, 315, 317, 5, 31, 15, 2, 316, 315, 3, 2, 2, 2, 317, 320, 3, 2, 2, 2, 318, 316, 3, 2, 2, 2, 318, 319, 3, 2, 2, 2, 319, 322, 3, 2, 2, 2, 320, 318, 3, 2, 2, 2, 321, 314, 3, 2, 2, 2, 321, 322, 3, 2, 2, 2, 322, 323, 3, 2, 2, 2, 323, 324, 5, 39, 19, 2, 324, 334, 3, 2, 2, 2, 325, 327, 5, 55, 27, 2, 326, 328, 5, 31, 15, 2, 327, 326, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 327, 3, 2, 2, 2, 329, 330, 3, 2, 2, 2, 330, 331, 3, 2, 2, 2, 331, 332, 5, 39, 19, 2, 332, 334, 3, 2, 2, 2, 333, 292, 3, 2, 2, 2, 333, 303, 3, 2, 2, 2, 333, 310, 3, 2, 2, 2, 333, 325, 3, 2, 2, 2, 334, 46, 3, 2, 2, 2, 335, 336, 7, 100, 2, 2, 336, 337, 7, 123, 2, 2, 337, 48, 3, 2, 2, 2, 338, 339, 7, 99, 2, 2, 339, 340, 7, 112, 2, 2, 340, 341, 7, 102, 2, 2, 341, 50, 3, 2, 2, 2, 342, 343, 7, 63, 2, 2, 343, 52, 3, 2, 2, 2, 344, 345, 7, 46, 2, 2, 345, 54, 3, 2, 2, 2, 346, 347, 7, 48, 2, 2, 347, 56, 3, 2, 2, 2, 348, 349, 7, 42, 2, 2, 349, 58, 3, 2, 2, 2, 350, 351, 7, 93, 2, 2, 351, 352, 3, 2, 2, 2, 352, 353, 8, 29, 6, 2, 353, 60, 3, 2, 2, 2, 354, 355, 7, 95, 2, 2, 355, 356, 3, 2, 2, 2, 356, 357, 8, 30, 5, 2, 357, 358, 8, 30, 5, 2, 358, 62, 3, 2, 2, 2, 359, 360, 7, 112, 2, 2, 360, 361, 7, 113, 2, 2, 361, 362, 7, 118, 2, 2, 362, 64, 3, 2, 2, 2, 363, 364, 7, 112, 2, 2, 364, 365, 7, 119, 2, 2, 365, 366, 7, 110, 2, 2, 366, 367, 7, 110, 2, 2, 367, 66, 3, 2, 2, 2, 368, 369, 7, 113, 2, 2, 369, 370, 7, 116, 2, 2, 370, 68, 3, 2, 2, 2, 371, 372, 7, 43, 2, 2, 372, 70, 3, 2, 2, 2, 373, 374, 7, 118, 2, 2, 374, 375, 7, 116, 2, 2, 375, 376, 7, 119, 2, 2, 376, 383, 7, 103, 2, 2, 377, 378, 7, 104, 2, 2, 378, 379, 7, 99, 2, 2, 379, 380, 7, 110, 2, 2, 380, 381, 7, 117, 2, 2, 381, 383, 7, 103, 2, 2, 382, 373, 3, 2, 2, 2, 382, 377, 3, 2, 2, 2, 383, 72, 3, 2, 2, 2, 384, 385, 7, 63, 2, 2, 385, 395, 7, 63, 2, 2, 386, 387, 7, 35, 2, 2, 387, 395, 7, 63, 2, 2, 388, 395, 7, 62, 2, 2, 389, 390, 7, 62, 2, 2, 390, 395, 7, 63, 2, 2, 391, 395, 7, 64, 2, 2, 392, 393, 7, 64, 2, 2, 393, 395, 7, 63, 2, 2, 394, 384, 3, 2, 2, 2, 394, 386, 3, 2, 2, 2, 394, 388, 3, 2, 2, 2, 394, 389, 3, 2, 2, 2, 394, 391, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 395, 74, 3, 2, 2, 2, 396, 397, 7, 45, 2, 2, 397, 76, 3, 2, 2, 2, 398, 399, 7, 47, 2, 2, 399, 78, 3, 2, 2, 2, 400, 401, 7, 44, 2, 2, 401, 80, 3, 2, 2, 2, 402, 403, 7, 49, 2, 2, 403, 82, 3, 2, 2, 2, 404, 405, 7, 39, 2, 2, 405, 84, 3, 2, 2, 2, 406, 407, 7, 99, 2, 2, 407, 408, 7, 117, 2, 2, 408, 414, 7, 101, 2, 2, 409, 410, 7, 102, 2, 2, 410, 411, 7, 103, 2, 2, 411, 412, 7, 117, 2, 2, 412, 414, 7, 101, 2, 2, 413, 406, 3, 2, 2, 2, 413, 409, 3, 2, 2, 2, 414, 86, 3, 2, 2, 2, 415, 416, 7, 112, 2, 2, 416, 417, 7, 119, 2, 2, 417, 418, 7, 110, 2, 2, 418, 419, 7, 110, 2, 2, 419, 420, 7, 117, 2, 2, 420, 88, 3, 2, 2, 2, 421, 422, 7, 104, 2, 2, 422, 423, 7, 107, 2, 2, 423, 424, 7, 116, 2, 2, 424, 425, 7, 117, 2, 2, 425, 431, 7, 118, 2, 2, 426, 427, 7, 110, 2, 2, 427, 428, 7, 99, 2, 2, 428, 429, 7, 117, 2, 2, 429, 431, 7, 118, 2, 2, 430, 421, 3, 2, 2, 2, 430, 426, 3, 2, 2, 2, 431, 90, 3, 2, 2, 2, 432, 433, 7, 116, 2, 2, 433, 434, 7, 113, 2, 2, 434, 435, 7, 119, 2, 2, 435, 436, 7, 112, 2, 2, 436, 450, 7, 102, 2, 2, 437, 438, 7, 99, 2, 2, 438, 439, 7, 120, 2, 2, 439, 450, 7, 105, 2, 2, 440, 441, 7, 111, 2, 2, 441, 442, 7, 107, 2, 2, 442, 450, 7, 112, 2, 2, 443, 444, 7, 111, 2, 2, 444, 445, 7, 99, 2, 2, 445, 450, 7, 122, 2, 2, 446, 447, 7, 117, 2, 2, 447, 448, 7, 119, 2, 2, 448, 450, 7, 111, 2, 2, 449, 432, 3, 2, 2, 2, 449, 437, 3, 2, 2, 2, 449, 440, 3, 2, 2, 2, 449, 443, 3, 2, 2, 2, 449, 446, 3, 2, 2, 2, 450, 92, 3, 2, 2, 2, 451, 454, 5, 33, 16, 2, 452, 454, 7, 97, 2, 2, 453, 451, 3, 2, 2, 2, 453, 452, 3, 2, 2, 2, 454, 460, 3, 2, 2, 2, 455, 459, 5, 33, 16, 2, 456, 459, 5, 31, 15, 2, 457, 459, 7, 97, 2, 2, 458, 455, 3, 2, 2, 2, 458, 456, 3, 2, 2, 2, 458, 457, 3, 2, 2, 2, 459, 462, 3, 2, 2, 2, 460, 458, 3, 2, 2, 2, 460, 461, 3, 2, 2, 2, 461, 94, 3, 2, 2, 2, 462, 460, 3, 2, 2, 2, 463, 469, 7, 98, 2, 2, 464, 468, 10, 10, 2, 2, 465, 466, 7, 98, 2, 2, 466, 468, 7, 98, 2, 2, 467, 464, 3, 2, 2, 2, 467, 465, 3, 2, 2, 2, 468, 471, 3, 2, 2, 2, 469, 467, 3, 2, 2, 2, 469, 470, 3, 2, 2, 2, 470, 472, 3, 2, 2, 2, 471, 469, 3, 2, 2, 2, 472, 473, 7, 98, 2, 2, 473, 96, 3, 2, 2, 2, 474, 475, 5, 23, 11, 2, 475, 476, 3, 2, 2, 2, 476, 477, 8, 48, 4, 2, 477, 98, 3, 2, 2, 2, 478, 479, 5, 25, 12, 2, 479, 480, 3, 2, 2, 2, 480, 481, 8, 49, 4, 2, 481, 100, 3, 2, 2, 2, 482, 483, 5, 27, 13, 2, 483, 484, 3, 2, 2, 2, 484, 485, 8, 50, 4, 2, 485, 102, 3, 2, 2, 2, 486, 487, 7, 126, 2, 2, 487, 488, 3, 2, 2, 2, 488, 489, 8, 51, 7, 2, 489, 490, 8, 51, 5, 2, 490, 104, 3, 2, 2, 2, 491, 492, 7, 95, 2, 2, 492, 493, 3, 2, 2, 2, 493, 494, 8, 52, 5, 2, 494, 495, 8, 52, 5, 2, 495, 496, 8, 52, 8, 2, 496, 106, 3, 2, 2, 2, 497, 498, 7, 46, 2, 2, 498, 499, 3, 2, 2, 2, 499, 500, 8, 53, 9, 2, 500, 108, 3, 2, 2, 2, 501, 502, 7, 63, 2, 2, 502, 503, 3, 2, 2, 2, 503, 504, 8, 54, 10, 2, 504, 110, 3, 2, 2, 2, 505, 507, 5, 113, 56, 2, 506, 505, 3, 2, 2, 2, 507, 508, 3, 2, 2, 2, 508, 506, 3, 2, 2, 2, 508, 509, 3, 2, 2, 2, 509, 112, 3, 2, 2, 2, 510, 512, 10, 11, 2, 2, 511, 510, 3, 2, 2, 2, 512, 513, 3, 2, 2, 2, 513, 511, 3, 2, 2, 2, 513, 514, 3, 2, 2, 2, 514, 518, 3, 2, 2, 2, 515, 516, 7, 49, 2, 2, 516, 518, 10, 12, 2, 2, 517, 511, 3, 2, 2, 2, 517, 515, 3, 2, 2, 2, 518, 114, 3, 2, 2, 2, 519, 520, 5, 95, 47, 2, 520, 116, 3, 2, 2, 2, 521, 522, 5, 23, 11, 2, 522, 523, 3, 2, 2, 2, 523, 524, 8, 58, 4, 2, 524, 118, 3, 2, 2, 2, 525, 526, 5, 25, 12, 2, 526, 527, 3, 2, 2, 2, 527, 528, 8, 59, 4, 2, 528, 120, 3, 2, 2, 2, 529, 530, 5, 27, 13, 2, 530, 531, 3, 2, 2, 2, 531, 532, 8, 60, 4, 2, 532, 122, 3, 2, 2, 2, 41, 2, 3, 4, 200, 204, 207, 216, 218, 229, 248, 253, 258, 260, 271, 279, 282, 284, 289, 294, 300, 307, 312, 318, 321, 329, 333, 382, 394, 413, 430, 449, 453, 458, 460, 467, 469, 508, 513, 517, 11, 7, 3, 2, 7, 4, 2, 2, 3, 2, 6, 2, 2, 7, 2, 2, 9, 15, 2, 9, 26, 2, 9, 22, 2, 9, 21, 2] \ No newline at end of file +[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 2, 83, 1396, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 4, 72, 9, 72, 4, 73, 9, 73, 4, 74, 9, 74, 4, 75, 9, 75, 4, 76, 9, 76, 4, 77, 9, 77, 4, 78, 9, 78, 4, 79, 9, 79, 4, 80, 9, 80, 4, 81, 9, 81, 4, 82, 9, 82, 4, 83, 9, 83, 4, 84, 9, 84, 4, 85, 9, 85, 4, 86, 9, 86, 4, 87, 9, 87, 4, 88, 9, 88, 4, 89, 9, 89, 4, 90, 9, 90, 4, 91, 9, 91, 4, 92, 9, 92, 4, 93, 9, 93, 4, 94, 9, 94, 4, 95, 9, 95, 4, 96, 9, 96, 4, 97, 9, 97, 4, 98, 9, 98, 4, 99, 9, 99, 4, 100, 9, 100, 4, 101, 9, 101, 4, 102, 9, 102, 4, 103, 9, 103, 4, 104, 9, 104, 4, 105, 9, 105, 4, 106, 9, 106, 4, 107, 9, 107, 4, 108, 9, 108, 4, 109, 9, 109, 4, 110, 9, 110, 4, 111, 9, 111, 4, 112, 9, 112, 4, 113, 9, 113, 4, 114, 9, 114, 4, 115, 9, 115, 4, 116, 9, 116, 4, 117, 9, 117, 4, 118, 9, 118, 4, 119, 9, 119, 4, 120, 9, 120, 4, 121, 9, 121, 4, 122, 9, 122, 4, 123, 9, 123, 4, 124, 9, 124, 4, 125, 9, 125, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 7, 19, 399, 10, 19, 12, 19, 14, 19, 402, 11, 19, 3, 19, 5, 19, 405, 10, 19, 3, 19, 5, 19, 408, 10, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 7, 20, 417, 10, 20, 12, 20, 14, 20, 420, 11, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 6, 21, 428, 10, 21, 13, 21, 14, 21, 429, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 23, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 5, 32, 471, 10, 32, 3, 32, 6, 32, 474, 10, 32, 13, 32, 14, 32, 475, 3, 33, 3, 33, 3, 33, 7, 33, 481, 10, 33, 12, 33, 14, 33, 484, 11, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 7, 33, 492, 10, 33, 12, 33, 14, 33, 495, 11, 33, 3, 33, 3, 33, 3, 33, 3, 33, 3, 33, 5, 33, 502, 10, 33, 3, 33, 5, 33, 505, 10, 33, 5, 33, 507, 10, 33, 3, 34, 6, 34, 510, 10, 34, 13, 34, 14, 34, 511, 3, 35, 6, 35, 515, 10, 35, 13, 35, 14, 35, 516, 3, 35, 3, 35, 7, 35, 521, 10, 35, 12, 35, 14, 35, 524, 11, 35, 3, 35, 3, 35, 6, 35, 528, 10, 35, 13, 35, 14, 35, 529, 3, 35, 6, 35, 533, 10, 35, 13, 35, 14, 35, 534, 3, 35, 3, 35, 7, 35, 539, 10, 35, 12, 35, 14, 35, 542, 11, 35, 5, 35, 544, 10, 35, 3, 35, 3, 35, 3, 35, 3, 35, 6, 35, 550, 10, 35, 13, 35, 14, 35, 551, 3, 35, 3, 35, 5, 35, 556, 10, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 5, 37, 589, 10, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 5, 57, 673, 10, 57, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 5, 58, 685, 10, 58, 3, 59, 3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 3, 65, 5, 65, 707, 10, 65, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 66, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 5, 67, 724, 10, 67, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 3, 68, 5, 68, 1088, 10, 68, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 3, 69, 5, 69, 1171, 10, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 7, 71, 1189, 10, 71, 12, 71, 14, 71, 1192, 11, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 6, 71, 1199, 10, 71, 13, 71, 14, 71, 1200, 5, 71, 1203, 10, 71, 3, 72, 3, 72, 3, 72, 3, 72, 7, 72, 1209, 10, 72, 12, 72, 14, 72, 1212, 11, 72, 3, 72, 3, 72, 3, 73, 3, 73, 3, 73, 3, 73, 3, 74, 3, 74, 3, 74, 3, 74, 3, 75, 3, 75, 3, 75, 3, 75, 3, 76, 3, 76, 3, 76, 3, 76, 3, 76, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 77, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 78, 3, 79, 3, 79, 3, 79, 3, 79, 3, 80, 3, 80, 3, 80, 3, 80, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 81, 3, 82, 6, 82, 1263, 10, 82, 13, 82, 14, 82, 1264, 3, 83, 6, 83, 1268, 10, 83, 13, 83, 14, 83, 1269, 3, 83, 3, 83, 5, 83, 1274, 10, 83, 3, 84, 3, 84, 3, 85, 3, 85, 3, 85, 3, 85, 3, 86, 3, 86, 3, 86, 3, 86, 3, 87, 3, 87, 3, 87, 3, 87, 3, 88, 3, 88, 3, 88, 3, 89, 3, 89, 3, 89, 3, 89, 3, 89, 3, 90, 3, 90, 3, 90, 3, 90, 3, 90, 3, 91, 3, 91, 3, 91, 3, 91, 3, 91, 3, 91, 3, 92, 3, 92, 3, 92, 3, 92, 3, 93, 3, 93, 3, 93, 3, 93, 3, 94, 6, 94, 1318, 10, 94, 13, 94, 14, 94, 1319, 3, 95, 6, 95, 1323, 10, 95, 13, 95, 14, 95, 1324, 3, 95, 3, 95, 5, 95, 1329, 10, 95, 3, 96, 3, 96, 3, 97, 3, 97, 3, 97, 3, 97, 3, 98, 3, 98, 3, 98, 3, 98, 3, 99, 3, 99, 3, 99, 3, 99, 3, 100, 3, 100, 3, 101, 3, 101, 3, 102, 3, 102, 3, 103, 3, 103, 3, 104, 3, 104, 3, 105, 3, 105, 3, 106, 3, 106, 3, 107, 3, 107, 3, 108, 3, 108, 3, 109, 3, 109, 3, 110, 3, 110, 3, 111, 3, 111, 3, 112, 3, 112, 3, 113, 3, 113, 3, 114, 3, 114, 3, 115, 3, 115, 3, 116, 3, 116, 3, 117, 3, 117, 3, 118, 3, 118, 3, 119, 3, 119, 3, 120, 3, 120, 3, 121, 3, 121, 3, 122, 3, 122, 3, 123, 3, 123, 3, 124, 3, 124, 3, 125, 3, 125, 4, 418, 493, 2, 2, 126, 7, 2, 3, 9, 2, 4, 11, 2, 5, 13, 2, 6, 15, 2, 7, 17, 2, 8, 19, 2, 9, 21, 2, 10, 23, 2, 11, 25, 2, 12, 27, 2, 13, 29, 2, 14, 31, 2, 15, 33, 2, 16, 35, 2, 17, 37, 2, 18, 39, 2, 19, 41, 2, 20, 43, 2, 21, 45, 2, 22, 47, 2, 2, 49, 2, 83, 51, 2, 23, 53, 2, 24, 55, 2, 25, 57, 2, 26, 59, 2, 2, 61, 2, 2, 63, 2, 2, 65, 2, 2, 67, 2, 2, 69, 2, 27, 71, 2, 28, 73, 2, 29, 75, 2, 30, 77, 2, 31, 79, 2, 32, 81, 2, 33, 83, 2, 34, 85, 2, 35, 87, 2, 36, 89, 2, 37, 91, 2, 38, 93, 2, 39, 95, 2, 40, 97, 2, 41, 99, 2, 42, 101, 2, 43, 103, 2, 44, 105, 2, 45, 107, 2, 46, 109, 2, 47, 111, 2, 48, 113, 2, 49, 115, 2, 50, 117, 2, 51, 119, 2, 52, 121, 2, 53, 123, 2, 54, 125, 2, 55, 127, 2, 56, 129, 2, 57, 131, 2, 58, 133, 2, 59, 135, 2, 60, 137, 2, 61, 139, 2, 62, 141, 2, 63, 143, 2, 64, 145, 2, 65, 147, 2, 66, 149, 2, 67, 151, 2, 68, 153, 2, 69, 155, 2, 2, 157, 2, 2, 159, 2, 2, 161, 2, 2, 163, 2, 2, 165, 2, 70, 167, 2, 71, 169, 2, 2, 171, 2, 72, 173, 2, 73, 175, 2, 74, 177, 2, 75, 179, 2, 76, 181, 2, 77, 183, 2, 2, 185, 2, 2, 187, 2, 2, 189, 2, 2, 191, 2, 78, 193, 2, 2, 195, 2, 79, 197, 2, 80, 199, 2, 81, 201, 2, 82, 203, 2, 2, 205, 2, 2, 207, 2, 2, 209, 2, 2, 211, 2, 2, 213, 2, 2, 215, 2, 2, 217, 2, 2, 219, 2, 2, 221, 2, 2, 223, 2, 2, 225, 2, 2, 227, 2, 2, 229, 2, 2, 231, 2, 2, 233, 2, 2, 235, 2, 2, 237, 2, 2, 239, 2, 2, 241, 2, 2, 243, 2, 2, 245, 2, 2, 247, 2, 2, 249, 2, 2, 251, 2, 2, 253, 2, 2, 7, 2, 3, 4, 5, 6, 39, 4, 2, 12, 12, 15, 15, 5, 2, 11, 12, 15, 15, 34, 34, 3, 2, 50, 59, 4, 2, 67, 92, 99, 124, 7, 2, 36, 36, 94, 94, 112, 112, 116, 116, 118, 118, 6, 2, 12, 12, 15, 15, 36, 36, 94, 94, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 66, 66, 97, 97, 3, 2, 98, 98, 12, 2, 11, 12, 15, 15, 34, 34, 46, 46, 49, 49, 63, 63, 93, 93, 95, 95, 98, 98, 126, 126, 4, 2, 44, 44, 49, 49, 4, 2, 67, 67, 99, 99, 4, 2, 68, 68, 100, 100, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102, 4, 2, 72, 72, 104, 104, 4, 2, 73, 73, 105, 105, 4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 76, 76, 108, 108, 4, 2, 77, 77, 109, 109, 4, 2, 78, 78, 110, 110, 4, 2, 79, 79, 111, 111, 4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114, 4, 2, 83, 83, 115, 115, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117, 4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120, 4, 2, 89, 89, 121, 121, 4, 2, 90, 90, 122, 122, 4, 2, 91, 91, 123, 123, 4, 2, 92, 92, 124, 124, 2, 1464, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 3, 47, 3, 2, 2, 2, 3, 49, 3, 2, 2, 2, 3, 51, 3, 2, 2, 2, 3, 53, 3, 2, 2, 2, 3, 55, 3, 2, 2, 2, 4, 57, 3, 2, 2, 2, 4, 69, 3, 2, 2, 2, 4, 71, 3, 2, 2, 2, 4, 73, 3, 2, 2, 2, 4, 75, 3, 2, 2, 2, 4, 77, 3, 2, 2, 2, 4, 79, 3, 2, 2, 2, 4, 81, 3, 2, 2, 2, 4, 83, 3, 2, 2, 2, 4, 85, 3, 2, 2, 2, 4, 87, 3, 2, 2, 2, 4, 89, 3, 2, 2, 2, 4, 91, 3, 2, 2, 2, 4, 93, 3, 2, 2, 2, 4, 95, 3, 2, 2, 2, 4, 97, 3, 2, 2, 2, 4, 99, 3, 2, 2, 2, 4, 101, 3, 2, 2, 2, 4, 103, 3, 2, 2, 2, 4, 105, 3, 2, 2, 2, 4, 107, 3, 2, 2, 2, 4, 109, 3, 2, 2, 2, 4, 111, 3, 2, 2, 2, 4, 113, 3, 2, 2, 2, 4, 115, 3, 2, 2, 2, 4, 117, 3, 2, 2, 2, 4, 119, 3, 2, 2, 2, 4, 121, 3, 2, 2, 2, 4, 123, 3, 2, 2, 2, 4, 125, 3, 2, 2, 2, 4, 127, 3, 2, 2, 2, 4, 129, 3, 2, 2, 2, 4, 131, 3, 2, 2, 2, 4, 133, 3, 2, 2, 2, 4, 135, 3, 2, 2, 2, 4, 137, 3, 2, 2, 2, 4, 139, 3, 2, 2, 2, 4, 141, 3, 2, 2, 2, 4, 143, 3, 2, 2, 2, 4, 145, 3, 2, 2, 2, 4, 147, 3, 2, 2, 2, 4, 149, 3, 2, 2, 2, 4, 151, 3, 2, 2, 2, 4, 153, 3, 2, 2, 2, 5, 155, 3, 2, 2, 2, 5, 157, 3, 2, 2, 2, 5, 159, 3, 2, 2, 2, 5, 161, 3, 2, 2, 2, 5, 163, 3, 2, 2, 2, 5, 165, 3, 2, 2, 2, 5, 167, 3, 2, 2, 2, 5, 171, 3, 2, 2, 2, 5, 173, 3, 2, 2, 2, 5, 175, 3, 2, 2, 2, 5, 177, 3, 2, 2, 2, 6, 179, 3, 2, 2, 2, 6, 181, 3, 2, 2, 2, 6, 183, 3, 2, 2, 2, 6, 185, 3, 2, 2, 2, 6, 187, 3, 2, 2, 2, 6, 189, 3, 2, 2, 2, 6, 191, 3, 2, 2, 2, 6, 195, 3, 2, 2, 2, 6, 197, 3, 2, 2, 2, 6, 199, 3, 2, 2, 2, 6, 201, 3, 2, 2, 2, 7, 255, 3, 2, 2, 2, 9, 265, 3, 2, 2, 2, 11, 272, 3, 2, 2, 2, 13, 279, 3, 2, 2, 2, 15, 289, 3, 2, 2, 2, 17, 296, 3, 2, 2, 2, 19, 302, 3, 2, 2, 2, 21, 310, 3, 2, 2, 2, 23, 318, 3, 2, 2, 2, 25, 325, 3, 2, 2, 2, 27, 337, 3, 2, 2, 2, 29, 345, 3, 2, 2, 2, 31, 355, 3, 2, 2, 2, 33, 362, 3, 2, 2, 2, 35, 371, 3, 2, 2, 2, 37, 378, 3, 2, 2, 2, 39, 387, 3, 2, 2, 2, 41, 394, 3, 2, 2, 2, 43, 411, 3, 2, 2, 2, 45, 427, 3, 2, 2, 2, 47, 433, 3, 2, 2, 2, 49, 438, 3, 2, 2, 2, 51, 443, 3, 2, 2, 2, 53, 447, 3, 2, 2, 2, 55, 451, 3, 2, 2, 2, 57, 455, 3, 2, 2, 2, 59, 459, 3, 2, 2, 2, 61, 461, 3, 2, 2, 2, 63, 463, 3, 2, 2, 2, 65, 466, 3, 2, 2, 2, 67, 468, 3, 2, 2, 2, 69, 506, 3, 2, 2, 2, 71, 509, 3, 2, 2, 2, 73, 555, 3, 2, 2, 2, 75, 557, 3, 2, 2, 2, 77, 588, 3, 2, 2, 2, 79, 590, 3, 2, 2, 2, 81, 594, 3, 2, 2, 2, 83, 596, 3, 2, 2, 2, 85, 598, 3, 2, 2, 2, 87, 600, 3, 2, 2, 2, 89, 602, 3, 2, 2, 2, 91, 607, 3, 2, 2, 2, 93, 612, 3, 2, 2, 2, 95, 616, 3, 2, 2, 2, 97, 621, 3, 2, 2, 2, 99, 627, 3, 2, 2, 2, 101, 630, 3, 2, 2, 2, 103, 633, 3, 2, 2, 2, 105, 636, 3, 2, 2, 2, 107, 641, 3, 2, 2, 2, 109, 644, 3, 2, 2, 2, 111, 646, 3, 2, 2, 2, 113, 648, 3, 2, 2, 2, 115, 653, 3, 2, 2, 2, 117, 672, 3, 2, 2, 2, 119, 684, 3, 2, 2, 2, 121, 686, 3, 2, 2, 2, 123, 688, 3, 2, 2, 2, 125, 690, 3, 2, 2, 2, 127, 692, 3, 2, 2, 2, 129, 694, 3, 2, 2, 2, 131, 696, 3, 2, 2, 2, 133, 706, 3, 2, 2, 2, 135, 708, 3, 2, 2, 2, 137, 723, 3, 2, 2, 2, 139, 1087, 3, 2, 2, 2, 141, 1170, 3, 2, 2, 2, 143, 1172, 3, 2, 2, 2, 145, 1202, 3, 2, 2, 2, 147, 1204, 3, 2, 2, 2, 149, 1215, 3, 2, 2, 2, 151, 1219, 3, 2, 2, 2, 153, 1223, 3, 2, 2, 2, 155, 1227, 3, 2, 2, 2, 157, 1232, 3, 2, 2, 2, 159, 1238, 3, 2, 2, 2, 161, 1244, 3, 2, 2, 2, 163, 1248, 3, 2, 2, 2, 165, 1252, 3, 2, 2, 2, 167, 1262, 3, 2, 2, 2, 169, 1273, 3, 2, 2, 2, 171, 1275, 3, 2, 2, 2, 173, 1277, 3, 2, 2, 2, 175, 1281, 3, 2, 2, 2, 177, 1285, 3, 2, 2, 2, 179, 1289, 3, 2, 2, 2, 181, 1292, 3, 2, 2, 2, 183, 1297, 3, 2, 2, 2, 185, 1302, 3, 2, 2, 2, 187, 1308, 3, 2, 2, 2, 189, 1312, 3, 2, 2, 2, 191, 1317, 3, 2, 2, 2, 193, 1328, 3, 2, 2, 2, 195, 1330, 3, 2, 2, 2, 197, 1332, 3, 2, 2, 2, 199, 1336, 3, 2, 2, 2, 201, 1340, 3, 2, 2, 2, 203, 1344, 3, 2, 2, 2, 205, 1346, 3, 2, 2, 2, 207, 1348, 3, 2, 2, 2, 209, 1350, 3, 2, 2, 2, 211, 1352, 3, 2, 2, 2, 213, 1354, 3, 2, 2, 2, 215, 1356, 3, 2, 2, 2, 217, 1358, 3, 2, 2, 2, 219, 1360, 3, 2, 2, 2, 221, 1362, 3, 2, 2, 2, 223, 1364, 3, 2, 2, 2, 225, 1366, 3, 2, 2, 2, 227, 1368, 3, 2, 2, 2, 229, 1370, 3, 2, 2, 2, 231, 1372, 3, 2, 2, 2, 233, 1374, 3, 2, 2, 2, 235, 1376, 3, 2, 2, 2, 237, 1378, 3, 2, 2, 2, 239, 1380, 3, 2, 2, 2, 241, 1382, 3, 2, 2, 2, 243, 1384, 3, 2, 2, 2, 245, 1386, 3, 2, 2, 2, 247, 1388, 3, 2, 2, 2, 249, 1390, 3, 2, 2, 2, 251, 1392, 3, 2, 2, 2, 253, 1394, 3, 2, 2, 2, 255, 256, 5, 209, 103, 2, 256, 257, 5, 219, 108, 2, 257, 258, 5, 239, 118, 2, 258, 259, 5, 239, 118, 2, 259, 260, 5, 211, 104, 2, 260, 261, 5, 207, 102, 2, 261, 262, 5, 241, 119, 2, 262, 263, 3, 2, 2, 2, 263, 264, 8, 2, 2, 2, 264, 8, 3, 2, 2, 2, 265, 266, 5, 215, 106, 2, 266, 267, 5, 237, 117, 2, 267, 268, 5, 231, 114, 2, 268, 269, 5, 223, 110, 2, 269, 270, 3, 2, 2, 2, 270, 271, 8, 3, 2, 2, 271, 10, 3, 2, 2, 2, 272, 273, 5, 211, 104, 2, 273, 274, 5, 245, 121, 2, 274, 275, 5, 203, 100, 2, 275, 276, 5, 225, 111, 2, 276, 277, 3, 2, 2, 2, 277, 278, 8, 4, 2, 2, 278, 12, 3, 2, 2, 2, 279, 280, 5, 211, 104, 2, 280, 281, 5, 249, 123, 2, 281, 282, 5, 233, 115, 2, 282, 283, 5, 225, 111, 2, 283, 284, 5, 203, 100, 2, 284, 285, 5, 219, 108, 2, 285, 286, 5, 229, 113, 2, 286, 287, 3, 2, 2, 2, 287, 288, 8, 5, 3, 2, 288, 14, 3, 2, 2, 2, 289, 290, 5, 213, 105, 2, 290, 291, 5, 237, 117, 2, 291, 292, 5, 231, 114, 2, 292, 293, 5, 227, 112, 2, 293, 294, 3, 2, 2, 2, 294, 295, 8, 6, 4, 2, 295, 16, 3, 2, 2, 2, 296, 297, 5, 237, 117, 2, 297, 298, 5, 231, 114, 2, 298, 299, 5, 247, 122, 2, 299, 300, 3, 2, 2, 2, 300, 301, 8, 7, 2, 2, 301, 18, 3, 2, 2, 2, 302, 303, 5, 239, 118, 2, 303, 304, 5, 241, 119, 2, 304, 305, 5, 203, 100, 2, 305, 306, 5, 241, 119, 2, 306, 307, 5, 239, 118, 2, 307, 308, 3, 2, 2, 2, 308, 309, 8, 8, 2, 2, 309, 20, 3, 2, 2, 2, 310, 311, 5, 247, 122, 2, 311, 312, 5, 217, 107, 2, 312, 313, 5, 211, 104, 2, 313, 314, 5, 237, 117, 2, 314, 315, 5, 211, 104, 2, 315, 316, 3, 2, 2, 2, 316, 317, 8, 9, 2, 2, 317, 22, 3, 2, 2, 2, 318, 319, 5, 239, 118, 2, 319, 320, 5, 231, 114, 2, 320, 321, 5, 237, 117, 2, 321, 322, 5, 241, 119, 2, 322, 323, 3, 2, 2, 2, 323, 324, 8, 10, 2, 2, 324, 24, 3, 2, 2, 2, 325, 326, 5, 227, 112, 2, 326, 327, 5, 245, 121, 2, 327, 328, 5, 111, 54, 2, 328, 329, 5, 211, 104, 2, 329, 330, 5, 249, 123, 2, 330, 331, 5, 233, 115, 2, 331, 332, 5, 203, 100, 2, 332, 333, 5, 229, 113, 2, 333, 334, 5, 209, 103, 2, 334, 335, 3, 2, 2, 2, 335, 336, 8, 11, 2, 2, 336, 26, 3, 2, 2, 2, 337, 338, 5, 225, 111, 2, 338, 339, 5, 219, 108, 2, 339, 340, 5, 227, 112, 2, 340, 341, 5, 219, 108, 2, 341, 342, 5, 241, 119, 2, 342, 343, 3, 2, 2, 2, 343, 344, 8, 12, 2, 2, 344, 28, 3, 2, 2, 2, 345, 346, 5, 233, 115, 2, 346, 347, 5, 237, 117, 2, 347, 348, 5, 231, 114, 2, 348, 349, 5, 221, 109, 2, 349, 350, 5, 211, 104, 2, 350, 351, 5, 207, 102, 2, 351, 352, 5, 241, 119, 2, 352, 353, 3, 2, 2, 2, 353, 354, 8, 13, 2, 2, 354, 30, 3, 2, 2, 2, 355, 356, 5, 209, 103, 2, 356, 357, 5, 237, 117, 2, 357, 358, 5, 231, 114, 2, 358, 359, 5, 233, 115, 2, 359, 360, 3, 2, 2, 2, 360, 361, 8, 14, 2, 2, 361, 32, 3, 2, 2, 2, 362, 363, 5, 237, 117, 2, 363, 364, 5, 211, 104, 2, 364, 365, 5, 229, 113, 2, 365, 366, 5, 203, 100, 2, 366, 367, 5, 227, 112, 2, 367, 368, 5, 211, 104, 2, 368, 369, 3, 2, 2, 2, 369, 370, 8, 15, 2, 2, 370, 34, 3, 2, 2, 2, 371, 372, 5, 239, 118, 2, 372, 373, 5, 217, 107, 2, 373, 374, 5, 231, 114, 2, 374, 375, 5, 247, 122, 2, 375, 376, 3, 2, 2, 2, 376, 377, 8, 16, 2, 2, 377, 36, 3, 2, 2, 2, 378, 379, 5, 211, 104, 2, 379, 380, 5, 229, 113, 2, 380, 381, 5, 237, 117, 2, 381, 382, 5, 219, 108, 2, 382, 383, 5, 207, 102, 2, 383, 384, 5, 217, 107, 2, 384, 385, 3, 2, 2, 2, 385, 386, 8, 17, 5, 2, 386, 38, 3, 2, 2, 2, 387, 388, 5, 223, 110, 2, 388, 389, 5, 211, 104, 2, 389, 390, 5, 211, 104, 2, 390, 391, 5, 233, 115, 2, 391, 392, 3, 2, 2, 2, 392, 393, 8, 18, 2, 2, 393, 40, 3, 2, 2, 2, 394, 395, 7, 49, 2, 2, 395, 396, 7, 49, 2, 2, 396, 400, 3, 2, 2, 2, 397, 399, 10, 2, 2, 2, 398, 397, 3, 2, 2, 2, 399, 402, 3, 2, 2, 2, 400, 398, 3, 2, 2, 2, 400, 401, 3, 2, 2, 2, 401, 404, 3, 2, 2, 2, 402, 400, 3, 2, 2, 2, 403, 405, 7, 15, 2, 2, 404, 403, 3, 2, 2, 2, 404, 405, 3, 2, 2, 2, 405, 407, 3, 2, 2, 2, 406, 408, 7, 12, 2, 2, 407, 406, 3, 2, 2, 2, 407, 408, 3, 2, 2, 2, 408, 409, 3, 2, 2, 2, 409, 410, 8, 19, 6, 2, 410, 42, 3, 2, 2, 2, 411, 412, 7, 49, 2, 2, 412, 413, 7, 44, 2, 2, 413, 418, 3, 2, 2, 2, 414, 417, 5, 43, 20, 2, 415, 417, 11, 2, 2, 2, 416, 414, 3, 2, 2, 2, 416, 415, 3, 2, 2, 2, 417, 420, 3, 2, 2, 2, 418, 419, 3, 2, 2, 2, 418, 416, 3, 2, 2, 2, 419, 421, 3, 2, 2, 2, 420, 418, 3, 2, 2, 2, 421, 422, 7, 44, 2, 2, 422, 423, 7, 49, 2, 2, 423, 424, 3, 2, 2, 2, 424, 425, 8, 20, 6, 2, 425, 44, 3, 2, 2, 2, 426, 428, 9, 3, 2, 2, 427, 426, 3, 2, 2, 2, 428, 429, 3, 2, 2, 2, 429, 427, 3, 2, 2, 2, 429, 430, 3, 2, 2, 2, 430, 431, 3, 2, 2, 2, 431, 432, 8, 21, 6, 2, 432, 46, 3, 2, 2, 2, 433, 434, 7, 93, 2, 2, 434, 435, 3, 2, 2, 2, 435, 436, 8, 22, 7, 2, 436, 437, 8, 22, 8, 2, 437, 48, 3, 2, 2, 2, 438, 439, 7, 126, 2, 2, 439, 440, 3, 2, 2, 2, 440, 441, 8, 23, 9, 2, 441, 442, 8, 23, 10, 2, 442, 50, 3, 2, 2, 2, 443, 444, 5, 45, 21, 2, 444, 445, 3, 2, 2, 2, 445, 446, 8, 24, 6, 2, 446, 52, 3, 2, 2, 2, 447, 448, 5, 41, 19, 2, 448, 449, 3, 2, 2, 2, 449, 450, 8, 25, 6, 2, 450, 54, 3, 2, 2, 2, 451, 452, 5, 43, 20, 2, 452, 453, 3, 2, 2, 2, 453, 454, 8, 26, 6, 2, 454, 56, 3, 2, 2, 2, 455, 456, 7, 126, 2, 2, 456, 457, 3, 2, 2, 2, 457, 458, 8, 27, 10, 2, 458, 58, 3, 2, 2, 2, 459, 460, 9, 4, 2, 2, 460, 60, 3, 2, 2, 2, 461, 462, 9, 5, 2, 2, 462, 62, 3, 2, 2, 2, 463, 464, 7, 94, 2, 2, 464, 465, 9, 6, 2, 2, 465, 64, 3, 2, 2, 2, 466, 467, 10, 7, 2, 2, 467, 66, 3, 2, 2, 2, 468, 470, 9, 8, 2, 2, 469, 471, 9, 9, 2, 2, 470, 469, 3, 2, 2, 2, 470, 471, 3, 2, 2, 2, 471, 473, 3, 2, 2, 2, 472, 474, 5, 59, 28, 2, 473, 472, 3, 2, 2, 2, 474, 475, 3, 2, 2, 2, 475, 473, 3, 2, 2, 2, 475, 476, 3, 2, 2, 2, 476, 68, 3, 2, 2, 2, 477, 482, 7, 36, 2, 2, 478, 481, 5, 63, 30, 2, 479, 481, 5, 65, 31, 2, 480, 478, 3, 2, 2, 2, 480, 479, 3, 2, 2, 2, 481, 484, 3, 2, 2, 2, 482, 480, 3, 2, 2, 2, 482, 483, 3, 2, 2, 2, 483, 485, 3, 2, 2, 2, 484, 482, 3, 2, 2, 2, 485, 507, 7, 36, 2, 2, 486, 487, 7, 36, 2, 2, 487, 488, 7, 36, 2, 2, 488, 489, 7, 36, 2, 2, 489, 493, 3, 2, 2, 2, 490, 492, 10, 2, 2, 2, 491, 490, 3, 2, 2, 2, 492, 495, 3, 2, 2, 2, 493, 494, 3, 2, 2, 2, 493, 491, 3, 2, 2, 2, 494, 496, 3, 2, 2, 2, 495, 493, 3, 2, 2, 2, 496, 497, 7, 36, 2, 2, 497, 498, 7, 36, 2, 2, 498, 499, 7, 36, 2, 2, 499, 501, 3, 2, 2, 2, 500, 502, 7, 36, 2, 2, 501, 500, 3, 2, 2, 2, 501, 502, 3, 2, 2, 2, 502, 504, 3, 2, 2, 2, 503, 505, 7, 36, 2, 2, 504, 503, 3, 2, 2, 2, 504, 505, 3, 2, 2, 2, 505, 507, 3, 2, 2, 2, 506, 477, 3, 2, 2, 2, 506, 486, 3, 2, 2, 2, 507, 70, 3, 2, 2, 2, 508, 510, 5, 59, 28, 2, 509, 508, 3, 2, 2, 2, 510, 511, 3, 2, 2, 2, 511, 509, 3, 2, 2, 2, 511, 512, 3, 2, 2, 2, 512, 72, 3, 2, 2, 2, 513, 515, 5, 59, 28, 2, 514, 513, 3, 2, 2, 2, 515, 516, 3, 2, 2, 2, 516, 514, 3, 2, 2, 2, 516, 517, 3, 2, 2, 2, 517, 518, 3, 2, 2, 2, 518, 522, 5, 85, 41, 2, 519, 521, 5, 59, 28, 2, 520, 519, 3, 2, 2, 2, 521, 524, 3, 2, 2, 2, 522, 520, 3, 2, 2, 2, 522, 523, 3, 2, 2, 2, 523, 556, 3, 2, 2, 2, 524, 522, 3, 2, 2, 2, 525, 527, 5, 85, 41, 2, 526, 528, 5, 59, 28, 2, 527, 526, 3, 2, 2, 2, 528, 529, 3, 2, 2, 2, 529, 527, 3, 2, 2, 2, 529, 530, 3, 2, 2, 2, 530, 556, 3, 2, 2, 2, 531, 533, 5, 59, 28, 2, 532, 531, 3, 2, 2, 2, 533, 534, 3, 2, 2, 2, 534, 532, 3, 2, 2, 2, 534, 535, 3, 2, 2, 2, 535, 543, 3, 2, 2, 2, 536, 540, 5, 85, 41, 2, 537, 539, 5, 59, 28, 2, 538, 537, 3, 2, 2, 2, 539, 542, 3, 2, 2, 2, 540, 538, 3, 2, 2, 2, 540, 541, 3, 2, 2, 2, 541, 544, 3, 2, 2, 2, 542, 540, 3, 2, 2, 2, 543, 536, 3, 2, 2, 2, 543, 544, 3, 2, 2, 2, 544, 545, 3, 2, 2, 2, 545, 546, 5, 67, 32, 2, 546, 556, 3, 2, 2, 2, 547, 549, 5, 85, 41, 2, 548, 550, 5, 59, 28, 2, 549, 548, 3, 2, 2, 2, 550, 551, 3, 2, 2, 2, 551, 549, 3, 2, 2, 2, 551, 552, 3, 2, 2, 2, 552, 553, 3, 2, 2, 2, 553, 554, 5, 67, 32, 2, 554, 556, 3, 2, 2, 2, 555, 514, 3, 2, 2, 2, 555, 525, 3, 2, 2, 2, 555, 532, 3, 2, 2, 2, 555, 547, 3, 2, 2, 2, 556, 74, 3, 2, 2, 2, 557, 558, 7, 100, 2, 2, 558, 559, 7, 123, 2, 2, 559, 76, 3, 2, 2, 2, 560, 561, 7, 123, 2, 2, 561, 562, 7, 103, 2, 2, 562, 563, 7, 99, 2, 2, 563, 589, 7, 116, 2, 2, 564, 565, 7, 111, 2, 2, 565, 566, 7, 113, 2, 2, 566, 567, 7, 112, 2, 2, 567, 568, 7, 118, 2, 2, 568, 589, 7, 106, 2, 2, 569, 570, 7, 102, 2, 2, 570, 571, 7, 99, 2, 2, 571, 589, 7, 123, 2, 2, 572, 573, 7, 117, 2, 2, 573, 574, 7, 103, 2, 2, 574, 575, 7, 101, 2, 2, 575, 576, 7, 113, 2, 2, 576, 577, 7, 112, 2, 2, 577, 589, 7, 102, 2, 2, 578, 579, 7, 111, 2, 2, 579, 580, 7, 107, 2, 2, 580, 581, 7, 112, 2, 2, 581, 582, 7, 119, 2, 2, 582, 583, 7, 118, 2, 2, 583, 589, 7, 103, 2, 2, 584, 585, 7, 106, 2, 2, 585, 586, 7, 113, 2, 2, 586, 587, 7, 119, 2, 2, 587, 589, 7, 116, 2, 2, 588, 560, 3, 2, 2, 2, 588, 564, 3, 2, 2, 2, 588, 569, 3, 2, 2, 2, 588, 572, 3, 2, 2, 2, 588, 578, 3, 2, 2, 2, 588, 584, 3, 2, 2, 2, 589, 78, 3, 2, 2, 2, 590, 591, 7, 99, 2, 2, 591, 592, 7, 112, 2, 2, 592, 593, 7, 102, 2, 2, 593, 80, 3, 2, 2, 2, 594, 595, 7, 63, 2, 2, 595, 82, 3, 2, 2, 2, 596, 597, 7, 46, 2, 2, 597, 84, 3, 2, 2, 2, 598, 599, 7, 48, 2, 2, 599, 86, 3, 2, 2, 2, 600, 601, 7, 42, 2, 2, 601, 88, 3, 2, 2, 2, 602, 603, 7, 93, 2, 2, 603, 604, 3, 2, 2, 2, 604, 605, 8, 43, 2, 2, 605, 606, 8, 43, 2, 2, 606, 90, 3, 2, 2, 2, 607, 608, 7, 95, 2, 2, 608, 609, 3, 2, 2, 2, 609, 610, 8, 44, 10, 2, 610, 611, 8, 44, 10, 2, 611, 92, 3, 2, 2, 2, 612, 613, 5, 229, 113, 2, 613, 614, 5, 231, 114, 2, 614, 615, 5, 241, 119, 2, 615, 94, 3, 2, 2, 2, 616, 617, 5, 225, 111, 2, 617, 618, 5, 219, 108, 2, 618, 619, 5, 223, 110, 2, 619, 620, 5, 211, 104, 2, 620, 96, 3, 2, 2, 2, 621, 622, 5, 237, 117, 2, 622, 623, 5, 225, 111, 2, 623, 624, 5, 219, 108, 2, 624, 625, 5, 223, 110, 2, 625, 626, 5, 211, 104, 2, 626, 98, 3, 2, 2, 2, 627, 628, 5, 219, 108, 2, 628, 629, 5, 229, 113, 2, 629, 100, 3, 2, 2, 2, 630, 631, 5, 219, 108, 2, 631, 632, 5, 239, 118, 2, 632, 102, 3, 2, 2, 2, 633, 634, 5, 203, 100, 2, 634, 635, 5, 239, 118, 2, 635, 104, 3, 2, 2, 2, 636, 637, 5, 229, 113, 2, 637, 638, 5, 243, 120, 2, 638, 639, 5, 225, 111, 2, 639, 640, 5, 225, 111, 2, 640, 106, 3, 2, 2, 2, 641, 642, 7, 113, 2, 2, 642, 643, 7, 116, 2, 2, 643, 108, 3, 2, 2, 2, 644, 645, 7, 43, 2, 2, 645, 110, 3, 2, 2, 2, 646, 647, 7, 97, 2, 2, 647, 112, 3, 2, 2, 2, 648, 649, 7, 107, 2, 2, 649, 650, 7, 112, 2, 2, 650, 651, 7, 104, 2, 2, 651, 652, 7, 113, 2, 2, 652, 114, 3, 2, 2, 2, 653, 654, 7, 104, 2, 2, 654, 655, 7, 119, 2, 2, 655, 656, 7, 112, 2, 2, 656, 657, 7, 101, 2, 2, 657, 658, 7, 118, 2, 2, 658, 659, 7, 107, 2, 2, 659, 660, 7, 113, 2, 2, 660, 661, 7, 112, 2, 2, 661, 662, 7, 117, 2, 2, 662, 116, 3, 2, 2, 2, 663, 664, 7, 118, 2, 2, 664, 665, 7, 116, 2, 2, 665, 666, 7, 119, 2, 2, 666, 673, 7, 103, 2, 2, 667, 668, 7, 104, 2, 2, 668, 669, 7, 99, 2, 2, 669, 670, 7, 110, 2, 2, 670, 671, 7, 117, 2, 2, 671, 673, 7, 103, 2, 2, 672, 663, 3, 2, 2, 2, 672, 667, 3, 2, 2, 2, 673, 118, 3, 2, 2, 2, 674, 675, 7, 63, 2, 2, 675, 685, 7, 63, 2, 2, 676, 677, 7, 35, 2, 2, 677, 685, 7, 63, 2, 2, 678, 685, 7, 62, 2, 2, 679, 680, 7, 62, 2, 2, 680, 685, 7, 63, 2, 2, 681, 685, 7, 64, 2, 2, 682, 683, 7, 64, 2, 2, 683, 685, 7, 63, 2, 2, 684, 674, 3, 2, 2, 2, 684, 676, 3, 2, 2, 2, 684, 678, 3, 2, 2, 2, 684, 679, 3, 2, 2, 2, 684, 681, 3, 2, 2, 2, 684, 682, 3, 2, 2, 2, 685, 120, 3, 2, 2, 2, 686, 687, 7, 45, 2, 2, 687, 122, 3, 2, 2, 2, 688, 689, 7, 47, 2, 2, 689, 124, 3, 2, 2, 2, 690, 691, 7, 44, 2, 2, 691, 126, 3, 2, 2, 2, 692, 693, 7, 49, 2, 2, 693, 128, 3, 2, 2, 2, 694, 695, 7, 39, 2, 2, 695, 130, 3, 2, 2, 2, 696, 697, 7, 51, 2, 2, 697, 698, 7, 50, 2, 2, 698, 132, 3, 2, 2, 2, 699, 700, 7, 99, 2, 2, 700, 701, 7, 117, 2, 2, 701, 707, 7, 101, 2, 2, 702, 703, 7, 102, 2, 2, 703, 704, 7, 103, 2, 2, 704, 705, 7, 117, 2, 2, 705, 707, 7, 101, 2, 2, 706, 699, 3, 2, 2, 2, 706, 702, 3, 2, 2, 2, 707, 134, 3, 2, 2, 2, 708, 709, 7, 112, 2, 2, 709, 710, 7, 119, 2, 2, 710, 711, 7, 110, 2, 2, 711, 712, 7, 110, 2, 2, 712, 713, 7, 117, 2, 2, 713, 136, 3, 2, 2, 2, 714, 715, 7, 104, 2, 2, 715, 716, 7, 107, 2, 2, 716, 717, 7, 116, 2, 2, 717, 718, 7, 117, 2, 2, 718, 724, 7, 118, 2, 2, 719, 720, 7, 110, 2, 2, 720, 721, 7, 99, 2, 2, 721, 722, 7, 117, 2, 2, 722, 724, 7, 118, 2, 2, 723, 714, 3, 2, 2, 2, 723, 719, 3, 2, 2, 2, 724, 138, 3, 2, 2, 2, 725, 726, 5, 237, 117, 2, 726, 727, 5, 231, 114, 2, 727, 728, 5, 243, 120, 2, 728, 729, 5, 229, 113, 2, 729, 730, 5, 209, 103, 2, 730, 1088, 3, 2, 2, 2, 731, 732, 5, 203, 100, 2, 732, 733, 5, 205, 101, 2, 733, 734, 5, 239, 118, 2, 734, 1088, 3, 2, 2, 2, 735, 736, 5, 233, 115, 2, 736, 737, 5, 231, 114, 2, 737, 738, 5, 247, 122, 2, 738, 1088, 3, 2, 2, 2, 739, 740, 5, 225, 111, 2, 740, 741, 5, 231, 114, 2, 741, 742, 5, 215, 106, 2, 742, 743, 5, 131, 64, 2, 743, 1088, 3, 2, 2, 2, 744, 745, 5, 233, 115, 2, 745, 746, 5, 219, 108, 2, 746, 1088, 3, 2, 2, 2, 747, 748, 5, 241, 119, 2, 748, 749, 5, 203, 100, 2, 749, 750, 5, 243, 120, 2, 750, 1088, 3, 2, 2, 2, 751, 1088, 5, 211, 104, 2, 752, 753, 5, 239, 118, 2, 753, 754, 5, 243, 120, 2, 754, 755, 5, 205, 101, 2, 755, 756, 5, 239, 118, 2, 756, 757, 5, 241, 119, 2, 757, 758, 5, 237, 117, 2, 758, 759, 5, 219, 108, 2, 759, 760, 5, 229, 113, 2, 760, 761, 5, 215, 106, 2, 761, 1088, 3, 2, 2, 2, 762, 763, 5, 241, 119, 2, 763, 764, 5, 237, 117, 2, 764, 765, 5, 219, 108, 2, 765, 766, 5, 227, 112, 2, 766, 1088, 3, 2, 2, 2, 767, 768, 5, 207, 102, 2, 768, 769, 5, 231, 114, 2, 769, 770, 5, 229, 113, 2, 770, 771, 5, 207, 102, 2, 771, 772, 5, 203, 100, 2, 772, 773, 5, 241, 119, 2, 773, 1088, 3, 2, 2, 2, 774, 775, 5, 239, 118, 2, 775, 776, 5, 241, 119, 2, 776, 777, 5, 203, 100, 2, 777, 778, 5, 237, 117, 2, 778, 779, 5, 241, 119, 2, 779, 780, 5, 239, 118, 2, 780, 781, 5, 111, 54, 2, 781, 782, 5, 247, 122, 2, 782, 783, 5, 219, 108, 2, 783, 784, 5, 241, 119, 2, 784, 785, 5, 217, 107, 2, 785, 1088, 3, 2, 2, 2, 786, 787, 5, 209, 103, 2, 787, 788, 5, 203, 100, 2, 788, 789, 5, 241, 119, 2, 789, 790, 5, 211, 104, 2, 790, 791, 5, 111, 54, 2, 791, 792, 5, 213, 105, 2, 792, 793, 5, 231, 114, 2, 793, 794, 5, 237, 117, 2, 794, 795, 5, 227, 112, 2, 795, 796, 5, 203, 100, 2, 796, 797, 5, 241, 119, 2, 797, 1088, 3, 2, 2, 2, 798, 799, 5, 209, 103, 2, 799, 800, 5, 203, 100, 2, 800, 801, 5, 241, 119, 2, 801, 802, 5, 211, 104, 2, 802, 803, 5, 111, 54, 2, 803, 804, 5, 241, 119, 2, 804, 805, 5, 237, 117, 2, 805, 806, 5, 243, 120, 2, 806, 807, 5, 229, 113, 2, 807, 808, 5, 207, 102, 2, 808, 1088, 3, 2, 2, 2, 809, 810, 5, 209, 103, 2, 810, 811, 5, 203, 100, 2, 811, 812, 5, 241, 119, 2, 812, 813, 5, 211, 104, 2, 813, 814, 5, 111, 54, 2, 814, 815, 5, 233, 115, 2, 815, 816, 5, 203, 100, 2, 816, 817, 5, 237, 117, 2, 817, 818, 5, 239, 118, 2, 818, 819, 5, 211, 104, 2, 819, 1088, 3, 2, 2, 2, 820, 821, 5, 203, 100, 2, 821, 822, 5, 243, 120, 2, 822, 823, 5, 241, 119, 2, 823, 824, 5, 231, 114, 2, 824, 825, 5, 111, 54, 2, 825, 826, 5, 205, 101, 2, 826, 827, 5, 243, 120, 2, 827, 828, 5, 207, 102, 2, 828, 829, 5, 223, 110, 2, 829, 830, 5, 211, 104, 2, 830, 831, 5, 241, 119, 2, 831, 1088, 3, 2, 2, 2, 832, 833, 5, 219, 108, 2, 833, 834, 5, 239, 118, 2, 834, 835, 5, 111, 54, 2, 835, 836, 5, 213, 105, 2, 836, 837, 5, 219, 108, 2, 837, 838, 5, 229, 113, 2, 838, 839, 5, 219, 108, 2, 839, 840, 5, 241, 119, 2, 840, 841, 5, 211, 104, 2, 841, 1088, 3, 2, 2, 2, 842, 843, 5, 219, 108, 2, 843, 844, 5, 239, 118, 2, 844, 845, 5, 111, 54, 2, 845, 846, 5, 219, 108, 2, 846, 847, 5, 229, 113, 2, 847, 848, 5, 213, 105, 2, 848, 849, 5, 219, 108, 2, 849, 850, 5, 229, 113, 2, 850, 851, 5, 219, 108, 2, 851, 852, 5, 241, 119, 2, 852, 853, 5, 211, 104, 2, 853, 1088, 3, 2, 2, 2, 854, 855, 5, 207, 102, 2, 855, 856, 5, 203, 100, 2, 856, 857, 5, 239, 118, 2, 857, 858, 5, 211, 104, 2, 858, 1088, 3, 2, 2, 2, 859, 860, 5, 225, 111, 2, 860, 861, 5, 211, 104, 2, 861, 862, 5, 229, 113, 2, 862, 863, 5, 215, 106, 2, 863, 864, 5, 241, 119, 2, 864, 865, 5, 217, 107, 2, 865, 1088, 3, 2, 2, 2, 866, 867, 5, 227, 112, 2, 867, 868, 5, 245, 121, 2, 868, 869, 5, 111, 54, 2, 869, 870, 5, 227, 112, 2, 870, 871, 5, 203, 100, 2, 871, 872, 5, 249, 123, 2, 872, 1088, 3, 2, 2, 2, 873, 874, 5, 227, 112, 2, 874, 875, 5, 245, 121, 2, 875, 876, 5, 111, 54, 2, 876, 877, 5, 227, 112, 2, 877, 878, 5, 219, 108, 2, 878, 879, 5, 229, 113, 2, 879, 1088, 3, 2, 2, 2, 880, 881, 5, 227, 112, 2, 881, 882, 5, 245, 121, 2, 882, 883, 5, 111, 54, 2, 883, 884, 5, 203, 100, 2, 884, 885, 5, 245, 121, 2, 885, 886, 5, 215, 106, 2, 886, 1088, 3, 2, 2, 2, 887, 888, 5, 227, 112, 2, 888, 889, 5, 245, 121, 2, 889, 890, 5, 111, 54, 2, 890, 891, 5, 239, 118, 2, 891, 892, 5, 243, 120, 2, 892, 893, 5, 227, 112, 2, 893, 1088, 3, 2, 2, 2, 894, 895, 5, 227, 112, 2, 895, 896, 5, 245, 121, 2, 896, 897, 5, 111, 54, 2, 897, 898, 5, 207, 102, 2, 898, 899, 5, 231, 114, 2, 899, 900, 5, 243, 120, 2, 900, 901, 5, 229, 113, 2, 901, 902, 5, 241, 119, 2, 902, 1088, 3, 2, 2, 2, 903, 904, 5, 227, 112, 2, 904, 905, 5, 245, 121, 2, 905, 906, 5, 111, 54, 2, 906, 907, 5, 207, 102, 2, 907, 908, 5, 231, 114, 2, 908, 909, 5, 229, 113, 2, 909, 910, 5, 207, 102, 2, 910, 911, 5, 203, 100, 2, 911, 912, 5, 241, 119, 2, 912, 1088, 3, 2, 2, 2, 913, 914, 5, 227, 112, 2, 914, 915, 5, 245, 121, 2, 915, 916, 5, 111, 54, 2, 916, 917, 5, 221, 109, 2, 917, 918, 5, 231, 114, 2, 918, 919, 5, 219, 108, 2, 919, 920, 5, 229, 113, 2, 920, 1088, 3, 2, 2, 2, 921, 922, 5, 227, 112, 2, 922, 923, 5, 245, 121, 2, 923, 924, 5, 111, 54, 2, 924, 925, 5, 227, 112, 2, 925, 926, 5, 211, 104, 2, 926, 927, 5, 209, 103, 2, 927, 928, 5, 219, 108, 2, 928, 929, 5, 203, 100, 2, 929, 930, 5, 229, 113, 2, 930, 1088, 3, 2, 2, 2, 931, 932, 5, 227, 112, 2, 932, 933, 5, 245, 121, 2, 933, 934, 5, 111, 54, 2, 934, 935, 5, 209, 103, 2, 935, 936, 5, 211, 104, 2, 936, 937, 5, 209, 103, 2, 937, 938, 5, 243, 120, 2, 938, 939, 5, 233, 115, 2, 939, 940, 5, 211, 104, 2, 940, 1088, 3, 2, 2, 2, 941, 942, 5, 227, 112, 2, 942, 943, 5, 211, 104, 2, 943, 944, 5, 241, 119, 2, 944, 945, 5, 203, 100, 2, 945, 946, 5, 209, 103, 2, 946, 947, 5, 203, 100, 2, 947, 948, 5, 241, 119, 2, 948, 949, 5, 203, 100, 2, 949, 1088, 3, 2, 2, 2, 950, 951, 5, 239, 118, 2, 951, 952, 5, 233, 115, 2, 952, 953, 5, 225, 111, 2, 953, 954, 5, 219, 108, 2, 954, 955, 5, 241, 119, 2, 955, 1088, 3, 2, 2, 2, 956, 957, 5, 241, 119, 2, 957, 958, 5, 231, 114, 2, 958, 959, 5, 111, 54, 2, 959, 960, 5, 239, 118, 2, 960, 961, 5, 241, 119, 2, 961, 962, 5, 237, 117, 2, 962, 963, 5, 219, 108, 2, 963, 964, 5, 229, 113, 2, 964, 965, 5, 215, 106, 2, 965, 1088, 3, 2, 2, 2, 966, 967, 5, 241, 119, 2, 967, 968, 5, 231, 114, 2, 968, 969, 5, 111, 54, 2, 969, 970, 5, 239, 118, 2, 970, 971, 5, 241, 119, 2, 971, 972, 5, 237, 117, 2, 972, 1088, 3, 2, 2, 2, 973, 974, 5, 241, 119, 2, 974, 975, 5, 231, 114, 2, 975, 976, 5, 111, 54, 2, 976, 977, 5, 205, 101, 2, 977, 978, 5, 231, 114, 2, 978, 979, 5, 231, 114, 2, 979, 980, 5, 225, 111, 2, 980, 1088, 3, 2, 2, 2, 981, 982, 5, 241, 119, 2, 982, 983, 5, 231, 114, 2, 983, 984, 5, 111, 54, 2, 984, 985, 5, 205, 101, 2, 985, 986, 5, 231, 114, 2, 986, 987, 5, 231, 114, 2, 987, 988, 5, 225, 111, 2, 988, 989, 5, 211, 104, 2, 989, 990, 5, 203, 100, 2, 990, 991, 5, 229, 113, 2, 991, 1088, 3, 2, 2, 2, 992, 993, 5, 241, 119, 2, 993, 994, 5, 231, 114, 2, 994, 995, 5, 111, 54, 2, 995, 996, 5, 209, 103, 2, 996, 997, 5, 203, 100, 2, 997, 998, 5, 241, 119, 2, 998, 999, 5, 211, 104, 2, 999, 1000, 5, 241, 119, 2, 1000, 1001, 5, 219, 108, 2, 1001, 1002, 5, 227, 112, 2, 1002, 1003, 5, 211, 104, 2, 1003, 1088, 3, 2, 2, 2, 1004, 1005, 5, 241, 119, 2, 1005, 1006, 5, 231, 114, 2, 1006, 1007, 5, 111, 54, 2, 1007, 1008, 5, 209, 103, 2, 1008, 1009, 5, 241, 119, 2, 1009, 1088, 3, 2, 2, 2, 1010, 1011, 5, 241, 119, 2, 1011, 1012, 5, 231, 114, 2, 1012, 1013, 5, 111, 54, 2, 1013, 1014, 5, 209, 103, 2, 1014, 1015, 5, 205, 101, 2, 1015, 1016, 5, 225, 111, 2, 1016, 1088, 3, 2, 2, 2, 1017, 1018, 5, 241, 119, 2, 1018, 1019, 5, 231, 114, 2, 1019, 1020, 5, 111, 54, 2, 1020, 1021, 5, 209, 103, 2, 1021, 1022, 5, 231, 114, 2, 1022, 1023, 5, 243, 120, 2, 1023, 1024, 5, 205, 101, 2, 1024, 1025, 5, 225, 111, 2, 1025, 1026, 5, 211, 104, 2, 1026, 1088, 3, 2, 2, 2, 1027, 1028, 5, 241, 119, 2, 1028, 1029, 5, 231, 114, 2, 1029, 1030, 5, 111, 54, 2, 1030, 1031, 5, 219, 108, 2, 1031, 1032, 5, 229, 113, 2, 1032, 1033, 5, 241, 119, 2, 1033, 1088, 3, 2, 2, 2, 1034, 1035, 5, 241, 119, 2, 1035, 1036, 5, 231, 114, 2, 1036, 1037, 5, 111, 54, 2, 1037, 1038, 5, 219, 108, 2, 1038, 1039, 5, 229, 113, 2, 1039, 1040, 5, 241, 119, 2, 1040, 1041, 5, 211, 104, 2, 1041, 1042, 5, 215, 106, 2, 1042, 1043, 5, 211, 104, 2, 1043, 1044, 5, 237, 117, 2, 1044, 1088, 3, 2, 2, 2, 1045, 1046, 5, 241, 119, 2, 1046, 1047, 5, 231, 114, 2, 1047, 1048, 5, 111, 54, 2, 1048, 1049, 5, 225, 111, 2, 1049, 1050, 5, 231, 114, 2, 1050, 1051, 5, 229, 113, 2, 1051, 1052, 5, 215, 106, 2, 1052, 1088, 3, 2, 2, 2, 1053, 1054, 5, 241, 119, 2, 1054, 1055, 5, 231, 114, 2, 1055, 1056, 5, 111, 54, 2, 1056, 1057, 5, 219, 108, 2, 1057, 1058, 5, 233, 115, 2, 1058, 1088, 3, 2, 2, 2, 1059, 1060, 5, 241, 119, 2, 1060, 1061, 5, 231, 114, 2, 1061, 1062, 5, 111, 54, 2, 1062, 1063, 5, 245, 121, 2, 1063, 1064, 5, 211, 104, 2, 1064, 1065, 5, 237, 117, 2, 1065, 1066, 5, 239, 118, 2, 1066, 1067, 5, 219, 108, 2, 1067, 1068, 5, 231, 114, 2, 1068, 1069, 5, 229, 113, 2, 1069, 1088, 3, 2, 2, 2, 1070, 1071, 5, 241, 119, 2, 1071, 1072, 5, 231, 114, 2, 1072, 1073, 5, 111, 54, 2, 1073, 1074, 5, 243, 120, 2, 1074, 1075, 5, 229, 113, 2, 1075, 1076, 5, 239, 118, 2, 1076, 1077, 5, 219, 108, 2, 1077, 1078, 5, 215, 106, 2, 1078, 1079, 5, 229, 113, 2, 1079, 1080, 5, 211, 104, 2, 1080, 1081, 5, 209, 103, 2, 1081, 1082, 5, 111, 54, 2, 1082, 1083, 5, 225, 111, 2, 1083, 1084, 5, 231, 114, 2, 1084, 1085, 5, 229, 113, 2, 1085, 1086, 5, 215, 106, 2, 1086, 1088, 3, 2, 2, 2, 1087, 725, 3, 2, 2, 2, 1087, 731, 3, 2, 2, 2, 1087, 735, 3, 2, 2, 2, 1087, 739, 3, 2, 2, 2, 1087, 744, 3, 2, 2, 2, 1087, 747, 3, 2, 2, 2, 1087, 751, 3, 2, 2, 2, 1087, 752, 3, 2, 2, 2, 1087, 762, 3, 2, 2, 2, 1087, 767, 3, 2, 2, 2, 1087, 774, 3, 2, 2, 2, 1087, 786, 3, 2, 2, 2, 1087, 798, 3, 2, 2, 2, 1087, 809, 3, 2, 2, 2, 1087, 820, 3, 2, 2, 2, 1087, 832, 3, 2, 2, 2, 1087, 842, 3, 2, 2, 2, 1087, 854, 3, 2, 2, 2, 1087, 859, 3, 2, 2, 2, 1087, 866, 3, 2, 2, 2, 1087, 873, 3, 2, 2, 2, 1087, 880, 3, 2, 2, 2, 1087, 887, 3, 2, 2, 2, 1087, 894, 3, 2, 2, 2, 1087, 903, 3, 2, 2, 2, 1087, 913, 3, 2, 2, 2, 1087, 921, 3, 2, 2, 2, 1087, 931, 3, 2, 2, 2, 1087, 941, 3, 2, 2, 2, 1087, 950, 3, 2, 2, 2, 1087, 956, 3, 2, 2, 2, 1087, 966, 3, 2, 2, 2, 1087, 973, 3, 2, 2, 2, 1087, 981, 3, 2, 2, 2, 1087, 992, 3, 2, 2, 2, 1087, 1004, 3, 2, 2, 2, 1087, 1010, 3, 2, 2, 2, 1087, 1017, 3, 2, 2, 2, 1087, 1027, 3, 2, 2, 2, 1087, 1034, 3, 2, 2, 2, 1087, 1045, 3, 2, 2, 2, 1087, 1053, 3, 2, 2, 2, 1087, 1059, 3, 2, 2, 2, 1087, 1070, 3, 2, 2, 2, 1088, 140, 3, 2, 2, 2, 1089, 1090, 5, 203, 100, 2, 1090, 1091, 5, 245, 121, 2, 1091, 1092, 5, 215, 106, 2, 1092, 1171, 3, 2, 2, 2, 1093, 1094, 5, 227, 112, 2, 1094, 1095, 5, 219, 108, 2, 1095, 1096, 5, 229, 113, 2, 1096, 1171, 3, 2, 2, 2, 1097, 1098, 5, 227, 112, 2, 1098, 1099, 5, 203, 100, 2, 1099, 1100, 5, 249, 123, 2, 1100, 1171, 3, 2, 2, 2, 1101, 1102, 5, 239, 118, 2, 1102, 1103, 5, 243, 120, 2, 1103, 1104, 5, 227, 112, 2, 1104, 1171, 3, 2, 2, 2, 1105, 1106, 5, 207, 102, 2, 1106, 1107, 5, 231, 114, 2, 1107, 1108, 5, 243, 120, 2, 1108, 1109, 5, 229, 113, 2, 1109, 1110, 5, 241, 119, 2, 1110, 1171, 3, 2, 2, 2, 1111, 1112, 5, 207, 102, 2, 1112, 1113, 5, 231, 114, 2, 1113, 1114, 5, 243, 120, 2, 1114, 1115, 5, 229, 113, 2, 1115, 1116, 5, 241, 119, 2, 1116, 1117, 5, 111, 54, 2, 1117, 1118, 5, 209, 103, 2, 1118, 1119, 5, 219, 108, 2, 1119, 1120, 5, 239, 118, 2, 1120, 1121, 5, 241, 119, 2, 1121, 1122, 5, 219, 108, 2, 1122, 1123, 5, 229, 113, 2, 1123, 1124, 5, 207, 102, 2, 1124, 1125, 5, 241, 119, 2, 1125, 1171, 3, 2, 2, 2, 1126, 1127, 5, 233, 115, 2, 1127, 1128, 5, 211, 104, 2, 1128, 1129, 5, 237, 117, 2, 1129, 1130, 5, 207, 102, 2, 1130, 1131, 5, 211, 104, 2, 1131, 1132, 5, 229, 113, 2, 1132, 1133, 5, 241, 119, 2, 1133, 1134, 5, 219, 108, 2, 1134, 1135, 5, 225, 111, 2, 1135, 1136, 5, 211, 104, 2, 1136, 1171, 3, 2, 2, 2, 1137, 1138, 5, 227, 112, 2, 1138, 1139, 5, 211, 104, 2, 1139, 1140, 5, 209, 103, 2, 1140, 1141, 5, 219, 108, 2, 1141, 1142, 5, 203, 100, 2, 1142, 1143, 5, 229, 113, 2, 1143, 1171, 3, 2, 2, 2, 1144, 1145, 5, 227, 112, 2, 1145, 1146, 5, 211, 104, 2, 1146, 1147, 5, 209, 103, 2, 1147, 1148, 5, 219, 108, 2, 1148, 1149, 5, 203, 100, 2, 1149, 1150, 5, 229, 113, 2, 1150, 1151, 5, 111, 54, 2, 1151, 1152, 5, 203, 100, 2, 1152, 1153, 5, 205, 101, 2, 1153, 1154, 5, 239, 118, 2, 1154, 1155, 5, 231, 114, 2, 1155, 1156, 5, 225, 111, 2, 1156, 1157, 5, 243, 120, 2, 1157, 1158, 5, 241, 119, 2, 1158, 1159, 5, 211, 104, 2, 1159, 1160, 5, 111, 54, 2, 1160, 1161, 5, 209, 103, 2, 1161, 1162, 5, 211, 104, 2, 1162, 1163, 5, 245, 121, 2, 1163, 1164, 5, 219, 108, 2, 1164, 1165, 5, 203, 100, 2, 1165, 1166, 5, 241, 119, 2, 1166, 1167, 5, 219, 108, 2, 1167, 1168, 5, 231, 114, 2, 1168, 1169, 5, 229, 113, 2, 1169, 1171, 3, 2, 2, 2, 1170, 1089, 3, 2, 2, 2, 1170, 1093, 3, 2, 2, 2, 1170, 1097, 3, 2, 2, 2, 1170, 1101, 3, 2, 2, 2, 1170, 1105, 3, 2, 2, 2, 1170, 1111, 3, 2, 2, 2, 1170, 1126, 3, 2, 2, 2, 1170, 1137, 3, 2, 2, 2, 1170, 1144, 3, 2, 2, 2, 1171, 142, 3, 2, 2, 2, 1172, 1173, 5, 207, 102, 2, 1173, 1174, 5, 219, 108, 2, 1174, 1175, 5, 209, 103, 2, 1175, 1176, 5, 237, 117, 2, 1176, 1177, 5, 111, 54, 2, 1177, 1178, 5, 227, 112, 2, 1178, 1179, 5, 203, 100, 2, 1179, 1180, 5, 241, 119, 2, 1180, 1181, 5, 207, 102, 2, 1181, 1182, 5, 217, 107, 2, 1182, 144, 3, 2, 2, 2, 1183, 1190, 5, 61, 29, 2, 1184, 1189, 5, 61, 29, 2, 1185, 1189, 5, 59, 28, 2, 1186, 1189, 7, 97, 2, 2, 1187, 1189, 5, 125, 61, 2, 1188, 1184, 3, 2, 2, 2, 1188, 1185, 3, 2, 2, 2, 1188, 1186, 3, 2, 2, 2, 1188, 1187, 3, 2, 2, 2, 1189, 1192, 3, 2, 2, 2, 1190, 1188, 3, 2, 2, 2, 1190, 1191, 3, 2, 2, 2, 1191, 1203, 3, 2, 2, 2, 1192, 1190, 3, 2, 2, 2, 1193, 1198, 9, 10, 2, 2, 1194, 1199, 5, 61, 29, 2, 1195, 1199, 5, 59, 28, 2, 1196, 1199, 7, 97, 2, 2, 1197, 1199, 5, 125, 61, 2, 1198, 1194, 3, 2, 2, 2, 1198, 1195, 3, 2, 2, 2, 1198, 1196, 3, 2, 2, 2, 1198, 1197, 3, 2, 2, 2, 1199, 1200, 3, 2, 2, 2, 1200, 1198, 3, 2, 2, 2, 1200, 1201, 3, 2, 2, 2, 1201, 1203, 3, 2, 2, 2, 1202, 1183, 3, 2, 2, 2, 1202, 1193, 3, 2, 2, 2, 1203, 146, 3, 2, 2, 2, 1204, 1210, 7, 98, 2, 2, 1205, 1209, 10, 11, 2, 2, 1206, 1207, 7, 98, 2, 2, 1207, 1209, 7, 98, 2, 2, 1208, 1205, 3, 2, 2, 2, 1208, 1206, 3, 2, 2, 2, 1209, 1212, 3, 2, 2, 2, 1210, 1208, 3, 2, 2, 2, 1210, 1211, 3, 2, 2, 2, 1211, 1213, 3, 2, 2, 2, 1212, 1210, 3, 2, 2, 2, 1213, 1214, 7, 98, 2, 2, 1214, 148, 3, 2, 2, 2, 1215, 1216, 5, 41, 19, 2, 1216, 1217, 3, 2, 2, 2, 1217, 1218, 8, 73, 6, 2, 1218, 150, 3, 2, 2, 2, 1219, 1220, 5, 43, 20, 2, 1220, 1221, 3, 2, 2, 2, 1221, 1222, 8, 74, 6, 2, 1222, 152, 3, 2, 2, 2, 1223, 1224, 5, 45, 21, 2, 1224, 1225, 3, 2, 2, 2, 1225, 1226, 8, 75, 6, 2, 1226, 154, 3, 2, 2, 2, 1227, 1228, 7, 126, 2, 2, 1228, 1229, 3, 2, 2, 2, 1229, 1230, 8, 76, 9, 2, 1230, 1231, 8, 76, 10, 2, 1231, 156, 3, 2, 2, 2, 1232, 1233, 7, 93, 2, 2, 1233, 1234, 3, 2, 2, 2, 1234, 1235, 8, 77, 7, 2, 1235, 1236, 8, 77, 4, 2, 1236, 1237, 8, 77, 4, 2, 1237, 158, 3, 2, 2, 2, 1238, 1239, 7, 95, 2, 2, 1239, 1240, 3, 2, 2, 2, 1240, 1241, 8, 78, 10, 2, 1241, 1242, 8, 78, 10, 2, 1242, 1243, 8, 78, 11, 2, 1243, 160, 3, 2, 2, 2, 1244, 1245, 7, 46, 2, 2, 1245, 1246, 3, 2, 2, 2, 1246, 1247, 8, 79, 12, 2, 1247, 162, 3, 2, 2, 2, 1248, 1249, 7, 63, 2, 2, 1249, 1250, 3, 2, 2, 2, 1250, 1251, 8, 80, 13, 2, 1251, 164, 3, 2, 2, 2, 1252, 1253, 5, 227, 112, 2, 1253, 1254, 5, 211, 104, 2, 1254, 1255, 5, 241, 119, 2, 1255, 1256, 5, 203, 100, 2, 1256, 1257, 5, 209, 103, 2, 1257, 1258, 5, 203, 100, 2, 1258, 1259, 5, 241, 119, 2, 1259, 1260, 5, 203, 100, 2, 1260, 166, 3, 2, 2, 2, 1261, 1263, 5, 169, 83, 2, 1262, 1261, 3, 2, 2, 2, 1263, 1264, 3, 2, 2, 2, 1264, 1262, 3, 2, 2, 2, 1264, 1265, 3, 2, 2, 2, 1265, 168, 3, 2, 2, 2, 1266, 1268, 10, 12, 2, 2, 1267, 1266, 3, 2, 2, 2, 1268, 1269, 3, 2, 2, 2, 1269, 1267, 3, 2, 2, 2, 1269, 1270, 3, 2, 2, 2, 1270, 1274, 3, 2, 2, 2, 1271, 1272, 7, 49, 2, 2, 1272, 1274, 10, 13, 2, 2, 1273, 1267, 3, 2, 2, 2, 1273, 1271, 3, 2, 2, 2, 1274, 170, 3, 2, 2, 2, 1275, 1276, 5, 147, 72, 2, 1276, 172, 3, 2, 2, 2, 1277, 1278, 5, 41, 19, 2, 1278, 1279, 3, 2, 2, 2, 1279, 1280, 8, 85, 6, 2, 1280, 174, 3, 2, 2, 2, 1281, 1282, 5, 43, 20, 2, 1282, 1283, 3, 2, 2, 2, 1283, 1284, 8, 86, 6, 2, 1284, 176, 3, 2, 2, 2, 1285, 1286, 5, 45, 21, 2, 1286, 1287, 3, 2, 2, 2, 1287, 1288, 8, 87, 6, 2, 1288, 178, 3, 2, 2, 2, 1289, 1290, 5, 231, 114, 2, 1290, 1291, 5, 229, 113, 2, 1291, 180, 3, 2, 2, 2, 1292, 1293, 5, 247, 122, 2, 1293, 1294, 5, 219, 108, 2, 1294, 1295, 5, 241, 119, 2, 1295, 1296, 5, 217, 107, 2, 1296, 182, 3, 2, 2, 2, 1297, 1298, 7, 126, 2, 2, 1298, 1299, 3, 2, 2, 2, 1299, 1300, 8, 90, 9, 2, 1300, 1301, 8, 90, 10, 2, 1301, 184, 3, 2, 2, 2, 1302, 1303, 7, 95, 2, 2, 1303, 1304, 3, 2, 2, 2, 1304, 1305, 8, 91, 10, 2, 1305, 1306, 8, 91, 10, 2, 1306, 1307, 8, 91, 11, 2, 1307, 186, 3, 2, 2, 2, 1308, 1309, 7, 46, 2, 2, 1309, 1310, 3, 2, 2, 2, 1310, 1311, 8, 92, 12, 2, 1311, 188, 3, 2, 2, 2, 1312, 1313, 7, 63, 2, 2, 1313, 1314, 3, 2, 2, 2, 1314, 1315, 8, 93, 13, 2, 1315, 190, 3, 2, 2, 2, 1316, 1318, 5, 193, 95, 2, 1317, 1316, 3, 2, 2, 2, 1318, 1319, 3, 2, 2, 2, 1319, 1317, 3, 2, 2, 2, 1319, 1320, 3, 2, 2, 2, 1320, 192, 3, 2, 2, 2, 1321, 1323, 10, 12, 2, 2, 1322, 1321, 3, 2, 2, 2, 1323, 1324, 3, 2, 2, 2, 1324, 1322, 3, 2, 2, 2, 1324, 1325, 3, 2, 2, 2, 1325, 1329, 3, 2, 2, 2, 1326, 1327, 7, 49, 2, 2, 1327, 1329, 10, 13, 2, 2, 1328, 1322, 3, 2, 2, 2, 1328, 1326, 3, 2, 2, 2, 1329, 194, 3, 2, 2, 2, 1330, 1331, 5, 147, 72, 2, 1331, 196, 3, 2, 2, 2, 1332, 1333, 5, 41, 19, 2, 1333, 1334, 3, 2, 2, 2, 1334, 1335, 8, 97, 6, 2, 1335, 198, 3, 2, 2, 2, 1336, 1337, 5, 43, 20, 2, 1337, 1338, 3, 2, 2, 2, 1338, 1339, 8, 98, 6, 2, 1339, 200, 3, 2, 2, 2, 1340, 1341, 5, 45, 21, 2, 1341, 1342, 3, 2, 2, 2, 1342, 1343, 8, 99, 6, 2, 1343, 202, 3, 2, 2, 2, 1344, 1345, 9, 14, 2, 2, 1345, 204, 3, 2, 2, 2, 1346, 1347, 9, 15, 2, 2, 1347, 206, 3, 2, 2, 2, 1348, 1349, 9, 16, 2, 2, 1349, 208, 3, 2, 2, 2, 1350, 1351, 9, 17, 2, 2, 1351, 210, 3, 2, 2, 2, 1352, 1353, 9, 8, 2, 2, 1353, 212, 3, 2, 2, 2, 1354, 1355, 9, 18, 2, 2, 1355, 214, 3, 2, 2, 2, 1356, 1357, 9, 19, 2, 2, 1357, 216, 3, 2, 2, 2, 1358, 1359, 9, 20, 2, 2, 1359, 218, 3, 2, 2, 2, 1360, 1361, 9, 21, 2, 2, 1361, 220, 3, 2, 2, 2, 1362, 1363, 9, 22, 2, 2, 1363, 222, 3, 2, 2, 2, 1364, 1365, 9, 23, 2, 2, 1365, 224, 3, 2, 2, 2, 1366, 1367, 9, 24, 2, 2, 1367, 226, 3, 2, 2, 2, 1368, 1369, 9, 25, 2, 2, 1369, 228, 3, 2, 2, 2, 1370, 1371, 9, 26, 2, 2, 1371, 230, 3, 2, 2, 2, 1372, 1373, 9, 27, 2, 2, 1373, 232, 3, 2, 2, 2, 1374, 1375, 9, 28, 2, 2, 1375, 234, 3, 2, 2, 2, 1376, 1377, 9, 29, 2, 2, 1377, 236, 3, 2, 2, 2, 1378, 1379, 9, 30, 2, 2, 1379, 238, 3, 2, 2, 2, 1380, 1381, 9, 31, 2, 2, 1381, 240, 3, 2, 2, 2, 1382, 1383, 9, 32, 2, 2, 1383, 242, 3, 2, 2, 2, 1384, 1385, 9, 33, 2, 2, 1385, 244, 3, 2, 2, 2, 1386, 1387, 9, 34, 2, 2, 1387, 246, 3, 2, 2, 2, 1388, 1389, 9, 35, 2, 2, 1389, 248, 3, 2, 2, 2, 1390, 1391, 9, 36, 2, 2, 1391, 250, 3, 2, 2, 2, 1392, 1393, 9, 37, 2, 2, 1393, 252, 3, 2, 2, 2, 1394, 1395, 9, 38, 2, 2, 1395, 254, 3, 2, 2, 2, 50, 2, 3, 4, 5, 6, 400, 404, 407, 416, 418, 429, 470, 475, 480, 482, 493, 501, 504, 506, 511, 516, 522, 529, 534, 540, 543, 551, 555, 588, 672, 684, 706, 723, 1087, 1170, 1188, 1190, 1198, 1200, 1202, 1208, 1210, 1264, 1269, 1273, 1319, 1324, 1328, 14, 7, 4, 2, 7, 3, 2, 7, 5, 2, 7, 6, 2, 2, 3, 2, 9, 37, 2, 7, 2, 2, 9, 26, 2, 6, 2, 2, 9, 38, 2, 9, 34, 2, 9, 33, 2] \ No newline at end of file diff --git a/packages/kbn-monaco/src/esql/antlr/esql_lexer.tokens b/packages/kbn-monaco/src/esql/antlr/esql_lexer.tokens index c2dafff2f222c..b72e97b9a2961 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_lexer.tokens +++ b/packages/kbn-monaco/src/esql/antlr/esql_lexer.tokens @@ -1,74 +1,98 @@ -EVAL=1 -EXPLAIN=2 -FROM=3 -ROW=4 -STATS=5 -WHERE=6 -SORT=7 -LIMIT=8 -PROJECT=9 -LINE_COMMENT=10 -MULTILINE_COMMENT=11 -WS=12 -PIPE=13 -STRING=14 -INTEGER_LITERAL=15 -DECIMAL_LITERAL=16 -BY=17 -AND=18 -ASSIGN=19 -COMMA=20 -DOT=21 -LP=22 -OPENING_BRACKET=23 -CLOSING_BRACKET=24 -NOT=25 -NULL=26 -OR=27 -RP=28 -BOOLEAN_VALUE=29 -COMPARISON_OPERATOR=30 -PLUS=31 -MINUS=32 -ASTERISK=33 -SLASH=34 -PERCENT=35 -ORDERING=36 -NULLS_ORDERING=37 -NULLS_ORDERING_DIRECTION=38 -UNARY_FUNCTION=39 -UNQUOTED_IDENTIFIER=40 -QUOTED_IDENTIFIER=41 -EXPR_LINE_COMMENT=42 -EXPR_MULTILINE_COMMENT=43 -EXPR_WS=44 -SRC_UNQUOTED_IDENTIFIER=45 -SRC_QUOTED_IDENTIFIER=46 -SRC_LINE_COMMENT=47 -SRC_MULTILINE_COMMENT=48 -SRC_WS=49 -'eval'=1 -'explain'=2 -'from'=3 -'row'=4 -'stats'=5 -'where'=6 -'sort'=7 -'limit'=8 -'project'=9 -'by'=17 -'and'=18 -'.'=21 -'('=22 -'['=23 -']'=24 -'not'=25 -'null'=26 -'or'=27 -')'=28 -'+'=31 -'-'=32 -'*'=33 -'/'=34 -'%'=35 -'nulls'=37 +DISSECT=1 +GROK=2 +EVAL=3 +EXPLAIN=4 +FROM=5 +ROW=6 +STATS=7 +WHERE=8 +SORT=9 +MV_EXPAND=10 +LIMIT=11 +PROJECT=12 +DROP=13 +RENAME=14 +SHOW=15 +ENRICH=16 +KEEP=17 +LINE_COMMENT=18 +MULTILINE_COMMENT=19 +WS=20 +EXPLAIN_WS=21 +EXPLAIN_LINE_COMMENT=22 +EXPLAIN_MULTILINE_COMMENT=23 +PIPE=24 +STRING=25 +INTEGER_LITERAL=26 +DECIMAL_LITERAL=27 +BY=28 +DATE_LITERAL=29 +AND=30 +ASSIGN=31 +COMMA=32 +DOT=33 +LP=34 +OPENING_BRACKET=35 +CLOSING_BRACKET=36 +NOT=37 +LIKE=38 +RLIKE=39 +IN=40 +IS=41 +AS=42 +NULL=43 +OR=44 +RP=45 +UNDERSCORE=46 +INFO=47 +FUNCTIONS=48 +BOOLEAN_VALUE=49 +COMPARISON_OPERATOR=50 +PLUS=51 +MINUS=52 +ASTERISK=53 +SLASH=54 +PERCENT=55 +TEN=56 +ORDERING=57 +NULLS_ORDERING=58 +NULLS_ORDERING_DIRECTION=59 +MATH_FUNCTION=60 +UNARY_FUNCTION=61 +WHERE_FUNCTIONS=62 +UNQUOTED_IDENTIFIER=63 +QUOTED_IDENTIFIER=64 +EXPR_LINE_COMMENT=65 +EXPR_MULTILINE_COMMENT=66 +EXPR_WS=67 +METADATA=68 +SRC_UNQUOTED_IDENTIFIER=69 +SRC_QUOTED_IDENTIFIER=70 +SRC_LINE_COMMENT=71 +SRC_MULTILINE_COMMENT=72 +SRC_WS=73 +ON=74 +WITH=75 +ENR_UNQUOTED_IDENTIFIER=76 +ENR_QUOTED_IDENTIFIER=77 +ENR_LINE_COMMENT=78 +ENR_MULTILINE_COMMENT=79 +ENR_WS=80 +EXPLAIN_PIPE=81 +'by'=28 +'and'=30 +'.'=33 +'('=34 +']'=36 +'or'=44 +')'=45 +'_'=46 +'info'=47 +'functions'=48 +'+'=51 +'-'=52 +'*'=53 +'/'=54 +'%'=55 +'10'=56 +'nulls'=58 diff --git a/packages/kbn-monaco/src/esql/antlr/esql_lexer.ts b/packages/kbn-monaco/src/esql/antlr/esql_lexer.ts index 064b2fe2c02d1..6d8ddeb0f848e 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_lexer.ts +++ b/packages/kbn-monaco/src/esql/antlr/esql_lexer.ts @@ -17,57 +17,91 @@ import * as Utils from "antlr4ts/misc/Utils"; export class esql_lexer extends Lexer { - public static readonly EVAL = 1; - public static readonly EXPLAIN = 2; - public static readonly FROM = 3; - public static readonly ROW = 4; - public static readonly STATS = 5; - public static readonly WHERE = 6; - public static readonly SORT = 7; - public static readonly LIMIT = 8; - public static readonly PROJECT = 9; - public static readonly LINE_COMMENT = 10; - public static readonly MULTILINE_COMMENT = 11; - public static readonly WS = 12; - public static readonly PIPE = 13; - public static readonly STRING = 14; - public static readonly INTEGER_LITERAL = 15; - public static readonly DECIMAL_LITERAL = 16; - public static readonly BY = 17; - public static readonly AND = 18; - public static readonly ASSIGN = 19; - public static readonly COMMA = 20; - public static readonly DOT = 21; - public static readonly LP = 22; - public static readonly OPENING_BRACKET = 23; - public static readonly CLOSING_BRACKET = 24; - public static readonly NOT = 25; - public static readonly NULL = 26; - public static readonly OR = 27; - public static readonly RP = 28; - public static readonly BOOLEAN_VALUE = 29; - public static readonly COMPARISON_OPERATOR = 30; - public static readonly PLUS = 31; - public static readonly MINUS = 32; - public static readonly ASTERISK = 33; - public static readonly SLASH = 34; - public static readonly PERCENT = 35; - public static readonly ORDERING = 36; - public static readonly NULLS_ORDERING = 37; - public static readonly NULLS_ORDERING_DIRECTION = 38; - public static readonly UNARY_FUNCTION = 39; - public static readonly UNQUOTED_IDENTIFIER = 40; - public static readonly QUOTED_IDENTIFIER = 41; - public static readonly EXPR_LINE_COMMENT = 42; - public static readonly EXPR_MULTILINE_COMMENT = 43; - public static readonly EXPR_WS = 44; - public static readonly SRC_UNQUOTED_IDENTIFIER = 45; - public static readonly SRC_QUOTED_IDENTIFIER = 46; - public static readonly SRC_LINE_COMMENT = 47; - public static readonly SRC_MULTILINE_COMMENT = 48; - public static readonly SRC_WS = 49; - public static readonly EXPRESSION = 1; - public static readonly SOURCE_IDENTIFIERS = 2; + public static readonly DISSECT = 1; + public static readonly GROK = 2; + public static readonly EVAL = 3; + public static readonly EXPLAIN = 4; + public static readonly FROM = 5; + public static readonly ROW = 6; + public static readonly STATS = 7; + public static readonly WHERE = 8; + public static readonly SORT = 9; + public static readonly MV_EXPAND = 10; + public static readonly LIMIT = 11; + public static readonly PROJECT = 12; + public static readonly DROP = 13; + public static readonly RENAME = 14; + public static readonly SHOW = 15; + public static readonly ENRICH = 16; + public static readonly KEEP = 17; + public static readonly LINE_COMMENT = 18; + public static readonly MULTILINE_COMMENT = 19; + public static readonly WS = 20; + public static readonly EXPLAIN_WS = 21; + public static readonly EXPLAIN_LINE_COMMENT = 22; + public static readonly EXPLAIN_MULTILINE_COMMENT = 23; + public static readonly PIPE = 24; + public static readonly STRING = 25; + public static readonly INTEGER_LITERAL = 26; + public static readonly DECIMAL_LITERAL = 27; + public static readonly BY = 28; + public static readonly DATE_LITERAL = 29; + public static readonly AND = 30; + public static readonly ASSIGN = 31; + public static readonly COMMA = 32; + public static readonly DOT = 33; + public static readonly LP = 34; + public static readonly OPENING_BRACKET = 35; + public static readonly CLOSING_BRACKET = 36; + public static readonly NOT = 37; + public static readonly LIKE = 38; + public static readonly RLIKE = 39; + public static readonly IN = 40; + public static readonly IS = 41; + public static readonly AS = 42; + public static readonly NULL = 43; + public static readonly OR = 44; + public static readonly RP = 45; + public static readonly UNDERSCORE = 46; + public static readonly INFO = 47; + public static readonly FUNCTIONS = 48; + public static readonly BOOLEAN_VALUE = 49; + public static readonly COMPARISON_OPERATOR = 50; + public static readonly PLUS = 51; + public static readonly MINUS = 52; + public static readonly ASTERISK = 53; + public static readonly SLASH = 54; + public static readonly PERCENT = 55; + public static readonly TEN = 56; + public static readonly ORDERING = 57; + public static readonly NULLS_ORDERING = 58; + public static readonly NULLS_ORDERING_DIRECTION = 59; + public static readonly MATH_FUNCTION = 60; + public static readonly UNARY_FUNCTION = 61; + public static readonly WHERE_FUNCTIONS = 62; + public static readonly UNQUOTED_IDENTIFIER = 63; + public static readonly QUOTED_IDENTIFIER = 64; + public static readonly EXPR_LINE_COMMENT = 65; + public static readonly EXPR_MULTILINE_COMMENT = 66; + public static readonly EXPR_WS = 67; + public static readonly METADATA = 68; + public static readonly SRC_UNQUOTED_IDENTIFIER = 69; + public static readonly SRC_QUOTED_IDENTIFIER = 70; + public static readonly SRC_LINE_COMMENT = 71; + public static readonly SRC_MULTILINE_COMMENT = 72; + public static readonly SRC_WS = 73; + public static readonly ON = 74; + public static readonly WITH = 75; + public static readonly ENR_UNQUOTED_IDENTIFIER = 76; + public static readonly ENR_QUOTED_IDENTIFIER = 77; + public static readonly ENR_LINE_COMMENT = 78; + public static readonly ENR_MULTILINE_COMMENT = 79; + public static readonly ENR_WS = 80; + public static readonly EXPLAIN_PIPE = 81; + public static readonly EXPLAIN_MODE = 1; + public static readonly EXPRESSION = 2; + public static readonly SOURCE_IDENTIFIERS = 3; + public static readonly ENRICH_IDENTIFIERS = 4; // tslint:disable:no-trailing-whitespace public static readonly channelNames: string[] = [ @@ -76,40 +110,58 @@ export class esql_lexer extends Lexer { // tslint:disable:no-trailing-whitespace public static readonly modeNames: string[] = [ - "DEFAULT_MODE", "EXPRESSION", "SOURCE_IDENTIFIERS", + "DEFAULT_MODE", "EXPLAIN_MODE", "EXPRESSION", "SOURCE_IDENTIFIERS", "ENRICH_IDENTIFIERS", ]; public static readonly ruleNames: string[] = [ - "EVAL", "EXPLAIN", "FROM", "ROW", "STATS", "WHERE", "SORT", "LIMIT", "PROJECT", - "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", "DIGIT", "LETTER", - "ESCAPE_SEQUENCE", "UNESCAPED_CHARS", "EXPONENT", "STRING", "INTEGER_LITERAL", - "DECIMAL_LITERAL", "BY", "AND", "ASSIGN", "COMMA", "DOT", "LP", "OPENING_BRACKET", - "CLOSING_BRACKET", "NOT", "NULL", "OR", "RP", "BOOLEAN_VALUE", "COMPARISON_OPERATOR", - "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "ORDERING", "NULLS_ORDERING", - "NULLS_ORDERING_DIRECTION", "UNARY_FUNCTION", "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", - "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", "SRC_PIPE", - "SRC_CLOSING_BRACKET", "SRC_COMMA", "SRC_ASSIGN", "SRC_UNQUOTED_IDENTIFIER", - "SRC_UNQUOTED_IDENTIFIER_PART", "SRC_QUOTED_IDENTIFIER", "SRC_LINE_COMMENT", - "SRC_MULTILINE_COMMENT", "SRC_WS", + "DISSECT", "GROK", "EVAL", "EXPLAIN", "FROM", "ROW", "STATS", "WHERE", + "SORT", "MV_EXPAND", "LIMIT", "PROJECT", "DROP", "RENAME", "SHOW", "ENRICH", + "KEEP", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "EXPLAIN_OPENING_BRACKET", + "EXPLAIN_PIPE", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", + "PIPE", "DIGIT", "LETTER", "ESCAPE_SEQUENCE", "UNESCAPED_CHARS", "EXPONENT", + "STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "DATE_LITERAL", + "AND", "ASSIGN", "COMMA", "DOT", "LP", "OPENING_BRACKET", "CLOSING_BRACKET", + "NOT", "LIKE", "RLIKE", "IN", "IS", "AS", "NULL", "OR", "RP", "UNDERSCORE", + "INFO", "FUNCTIONS", "BOOLEAN_VALUE", "COMPARISON_OPERATOR", "PLUS", "MINUS", + "ASTERISK", "SLASH", "PERCENT", "TEN", "ORDERING", "NULLS_ORDERING", "NULLS_ORDERING_DIRECTION", + "MATH_FUNCTION", "UNARY_FUNCTION", "WHERE_FUNCTIONS", "UNQUOTED_IDENTIFIER", + "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", + "SRC_PIPE", "SRC_OPENING_BRACKET", "SRC_CLOSING_BRACKET", "SRC_COMMA", + "SRC_ASSIGN", "METADATA", "SRC_UNQUOTED_IDENTIFIER", "SRC_UNQUOTED_IDENTIFIER_PART", + "SRC_QUOTED_IDENTIFIER", "SRC_LINE_COMMENT", "SRC_MULTILINE_COMMENT", + "SRC_WS", "ON", "WITH", "ENR_PIPE", "ENR_CLOSING_BRACKET", "ENR_COMMA", + "ENR_ASSIGN", "ENR_UNQUOTED_IDENTIFIER", "ENR_UNQUOTED_IDENTIFIER_PART", + "ENR_QUOTED_IDENTIFIER", "ENR_LINE_COMMENT", "ENR_MULTILINE_COMMENT", + "ENR_WS", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", + "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ]; private static readonly _LITERAL_NAMES: Array = [ - undefined, "'eval'", "'explain'", "'from'", "'row'", "'stats'", "'where'", - "'sort'", "'limit'", "'project'", undefined, undefined, undefined, undefined, - undefined, undefined, undefined, "'by'", "'and'", undefined, undefined, - "'.'", "'('", "'['", "']'", "'not'", "'null'", "'or'", "')'", undefined, - undefined, "'+'", "'-'", "'*'", "'/'", "'%'", undefined, "'nulls'", + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + "'by'", undefined, "'and'", undefined, undefined, "'.'", "'('", undefined, + "']'", undefined, undefined, undefined, undefined, undefined, undefined, + undefined, "'or'", "')'", "'_'", "'info'", "'functions'", undefined, undefined, + "'+'", "'-'", "'*'", "'/'", "'%'", "'10'", undefined, "'nulls'", ]; private static readonly _SYMBOLIC_NAMES: Array = [ - undefined, "EVAL", "EXPLAIN", "FROM", "ROW", "STATS", "WHERE", "SORT", - "LIMIT", "PROJECT", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", - "STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASSIGN", - "COMMA", "DOT", "LP", "OPENING_BRACKET", "CLOSING_BRACKET", "NOT", "NULL", - "OR", "RP", "BOOLEAN_VALUE", "COMPARISON_OPERATOR", "PLUS", "MINUS", "ASTERISK", - "SLASH", "PERCENT", "ORDERING", "NULLS_ORDERING", "NULLS_ORDERING_DIRECTION", - "UNARY_FUNCTION", "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", - "EXPR_MULTILINE_COMMENT", "EXPR_WS", "SRC_UNQUOTED_IDENTIFIER", "SRC_QUOTED_IDENTIFIER", - "SRC_LINE_COMMENT", "SRC_MULTILINE_COMMENT", "SRC_WS", + undefined, "DISSECT", "GROK", "EVAL", "EXPLAIN", "FROM", "ROW", "STATS", + "WHERE", "SORT", "MV_EXPAND", "LIMIT", "PROJECT", "DROP", "RENAME", "SHOW", + "ENRICH", "KEEP", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "EXPLAIN_WS", + "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "PIPE", "STRING", + "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "DATE_LITERAL", "AND", "ASSIGN", + "COMMA", "DOT", "LP", "OPENING_BRACKET", "CLOSING_BRACKET", "NOT", "LIKE", + "RLIKE", "IN", "IS", "AS", "NULL", "OR", "RP", "UNDERSCORE", "INFO", "FUNCTIONS", + "BOOLEAN_VALUE", "COMPARISON_OPERATOR", "PLUS", "MINUS", "ASTERISK", "SLASH", + "PERCENT", "TEN", "ORDERING", "NULLS_ORDERING", "NULLS_ORDERING_DIRECTION", + "MATH_FUNCTION", "UNARY_FUNCTION", "WHERE_FUNCTIONS", "UNQUOTED_IDENTIFIER", + "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", + "METADATA", "SRC_UNQUOTED_IDENTIFIER", "SRC_QUOTED_IDENTIFIER", "SRC_LINE_COMMENT", + "SRC_MULTILINE_COMMENT", "SRC_WS", "ON", "WITH", "ENR_UNQUOTED_IDENTIFIER", + "ENR_QUOTED_IDENTIFIER", "ENR_LINE_COMMENT", "ENR_MULTILINE_COMMENT", + "ENR_WS", "EXPLAIN_PIPE", ]; public static readonly VOCABULARY: Vocabulary = new VocabularyImpl(esql_lexer._LITERAL_NAMES, esql_lexer._SYMBOLIC_NAMES, []); @@ -141,266 +193,682 @@ export class esql_lexer extends Lexer { // @Override public get modeNames(): string[] { return esql_lexer.modeNames; } - public static readonly _serializedATN: string = - "\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x023\u0215\b\x01" + - "\b\x01\b\x01\x04\x02\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04" + - "\x06\t\x06\x04\x07\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f" + - "\t\f\x04\r\t\r\x04\x0E\t\x0E\x04\x0F\t\x0F\x04\x10\t\x10\x04\x11\t\x11" + - "\x04\x12\t\x12\x04\x13\t\x13\x04\x14\t\x14\x04\x15\t\x15\x04\x16\t\x16" + - "\x04\x17\t\x17\x04\x18\t\x18\x04\x19\t\x19\x04\x1A\t\x1A\x04\x1B\t\x1B" + - "\x04\x1C\t\x1C\x04\x1D\t\x1D\x04\x1E\t\x1E\x04\x1F\t\x1F\x04 \t \x04!" + - "\t!\x04\"\t\"\x04#\t#\x04$\t$\x04%\t%\x04&\t&\x04\'\t\'\x04(\t(\x04)\t" + - ")\x04*\t*\x04+\t+\x04,\t,\x04-\t-\x04.\t.\x04/\t/\x040\t0\x041\t1\x04" + - "2\t2\x043\t3\x044\t4\x045\t5\x046\t6\x047\t7\x048\t8\x049\t9\x04:\t:\x04" + - ";\t;\x04<\t<\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03" + - "\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03" + - "\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x03" + - "\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03" + - "\x06\x03\x06\x03\x06\x03\x06\x03\x07\x03\x07\x03\x07\x03\x07\x03\x07\x03" + - "\x07\x03\x07\x03\x07\x03\b\x03\b\x03\b\x03\b\x03\b\x03\b\x03\b\x03\t\x03" + - "\t\x03\t\x03\t\x03\t\x03\t\x03\t\x03\t\x03\n\x03\n\x03\n\x03\n\x03\n\x03" + - "\n\x03\n\x03\n\x03\n\x03\n\x03\v\x03\v\x03\v\x03\v\x07\v\xC7\n\v\f\v\x0E" + - "\v\xCA\v\v\x03\v\x05\v\xCD\n\v\x03\v\x05\v\xD0\n\v\x03\v\x03\v\x03\f\x03" + - "\f\x03\f\x03\f\x03\f\x07\f\xD9\n\f\f\f\x0E\f\xDC\v\f\x03\f\x03\f\x03\f" + - "\x03\f\x03\f\x03\r\x06\r\xE4\n\r\r\r\x0E\r\xE5\x03\r\x03\r\x03\x0E\x03" + - "\x0E\x03\x0E\x03\x0E\x03\x0F\x03\x0F\x03\x10\x03\x10\x03\x11\x03\x11\x03" + - "\x11\x03\x12\x03\x12\x03\x13\x03\x13\x05\x13\xF9\n\x13\x03\x13\x06\x13" + - "\xFC\n\x13\r\x13\x0E\x13\xFD\x03\x14\x03\x14\x03\x14\x07\x14\u0103\n\x14" + - "\f\x14\x0E\x14\u0106\v\x14\x03\x14\x03\x14\x03\x14\x03\x14\x03\x14\x03" + - "\x14\x07\x14\u010E\n\x14\f\x14\x0E\x14\u0111\v\x14\x03\x14\x03\x14\x03" + - "\x14\x03\x14\x03\x14\x05\x14\u0118\n\x14\x03\x14\x05\x14\u011B\n\x14\x05" + - "\x14\u011D\n\x14\x03\x15\x06\x15\u0120\n\x15\r\x15\x0E\x15\u0121\x03\x16" + - "\x06\x16\u0125\n\x16\r\x16\x0E\x16\u0126\x03\x16\x03\x16\x07\x16\u012B" + - "\n\x16\f\x16\x0E\x16\u012E\v\x16\x03\x16\x03\x16\x06\x16\u0132\n\x16\r" + - "\x16\x0E\x16\u0133\x03\x16\x06\x16\u0137\n\x16\r\x16\x0E\x16\u0138\x03" + - "\x16\x03\x16\x07\x16\u013D\n\x16\f\x16\x0E\x16\u0140\v\x16\x05\x16\u0142" + - "\n\x16\x03\x16\x03\x16\x03\x16\x03\x16\x06\x16\u0148\n\x16\r\x16\x0E\x16" + - "\u0149\x03\x16\x03\x16\x05\x16\u014E\n\x16\x03\x17\x03\x17\x03\x17\x03" + - "\x18\x03\x18\x03\x18\x03\x18\x03\x19\x03\x19\x03\x1A\x03\x1A\x03\x1B\x03" + - "\x1B\x03\x1C\x03\x1C\x03\x1D\x03\x1D\x03\x1D\x03\x1D\x03\x1E\x03\x1E\x03" + - "\x1E\x03\x1E\x03\x1E\x03\x1F\x03\x1F\x03\x1F\x03\x1F\x03 \x03 \x03 \x03" + - " \x03 \x03!\x03!\x03!\x03\"\x03\"\x03#\x03#\x03#\x03#\x03#\x03#\x03#\x03" + - "#\x03#\x05#\u017F\n#\x03$\x03$\x03$\x03$\x03$\x03$\x03$\x03$\x03$\x03" + - "$\x05$\u018B\n$\x03%\x03%\x03&\x03&\x03\'\x03\'\x03(\x03(\x03)\x03)\x03" + - "*\x03*\x03*\x03*\x03*\x03*\x03*\x05*\u019E\n*\x03+\x03+\x03+\x03+\x03" + - "+\x03+\x03,\x03,\x03,\x03,\x03,\x03,\x03,\x03,\x03,\x05,\u01AF\n,\x03" + - "-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03-\x03" + - "-\x03-\x03-\x05-\u01C2\n-\x03.\x03.\x05.\u01C6\n.\x03.\x03.\x03.\x07." + - "\u01CB\n.\f.\x0E.\u01CE\v.\x03/\x03/\x03/\x03/\x07/\u01D4\n/\f/\x0E/\u01D7" + - "\v/\x03/\x03/\x030\x030\x030\x030\x031\x031\x031\x031\x032\x032\x032\x03" + - "2\x033\x033\x033\x033\x033\x034\x034\x034\x034\x034\x034\x035\x035\x03" + - "5\x035\x036\x036\x036\x036\x037\x067\u01FB\n7\r7\x0E7\u01FC\x038\x068" + - "\u0200\n8\r8\x0E8\u0201\x038\x038\x058\u0206\n8\x039\x039\x03:\x03:\x03" + - ":\x03:\x03;\x03;\x03;\x03;\x03<\x03<\x03<\x03<\x04\xDA\u010F\x02\x02=" + - "\x05\x02\x03\x07\x02\x04\t\x02\x05\v\x02\x06\r\x02\x07\x0F\x02\b\x11\x02" + - "\t\x13\x02\n\x15\x02\v\x17\x02\f\x19\x02\r\x1B\x02\x0E\x1D\x02\x0F\x1F" + - "\x02\x02!\x02\x02#\x02\x02%\x02\x02\'\x02\x02)\x02\x10+\x02\x11-\x02\x12" + - "/\x02\x131\x02\x143\x02\x155\x02\x167\x02\x179\x02\x18;\x02\x19=\x02\x1A" + - "?\x02\x1BA\x02\x1CC\x02\x1DE\x02\x1EG\x02\x1FI\x02 K\x02!M\x02\"O\x02" + - "#Q\x02$S\x02%U\x02&W\x02\'Y\x02([\x02)]\x02*_\x02+a\x02,c\x02-e\x02.g" + - "\x02\x02i\x02\x02k\x02\x02m\x02\x02o\x02/q\x02\x02s\x020u\x021w\x022y" + - "\x023\x05\x02\x03\x04\r\x04\x02\f\f\x0F\x0F\x05\x02\v\f\x0F\x0F\"\"\x03" + - "\x022;\x04\x02C\\c|\x07\x02$$^^ppttvv\x06\x02\f\f\x0F\x0F$$^^\x04\x02" + - "GGgg\x04\x02--//\x03\x02bb\f\x02\v\f\x0F\x0F\"\"..11??]]__bb~~\x04\x02" + - ",,11\x02\u023A\x02\x05\x03\x02\x02\x02\x02\x07\x03\x02\x02\x02\x02\t\x03" + - "\x02\x02\x02\x02\v\x03\x02\x02\x02\x02\r\x03\x02\x02\x02\x02\x0F\x03\x02" + - "\x02\x02\x02\x11\x03\x02\x02\x02\x02\x13\x03\x02\x02\x02\x02\x15\x03\x02" + - "\x02\x02\x02\x17\x03\x02\x02\x02\x02\x19\x03\x02\x02\x02\x02\x1B\x03\x02" + - "\x02\x02\x03\x1D\x03\x02\x02\x02\x03)\x03\x02\x02\x02\x03+\x03\x02\x02" + - "\x02\x03-\x03\x02\x02\x02\x03/\x03\x02\x02\x02\x031\x03\x02\x02\x02\x03" + - "3\x03\x02\x02\x02\x035\x03\x02\x02\x02\x037\x03\x02\x02\x02\x039\x03\x02" + - "\x02\x02\x03;\x03\x02\x02\x02\x03=\x03\x02\x02\x02\x03?\x03\x02\x02\x02" + - "\x03A\x03\x02\x02\x02\x03C\x03\x02\x02\x02\x03E\x03\x02\x02\x02\x03G\x03" + - "\x02\x02\x02\x03I\x03\x02\x02\x02\x03K\x03\x02\x02\x02\x03M\x03\x02\x02" + - "\x02\x03O\x03\x02\x02\x02\x03Q\x03\x02\x02\x02\x03S\x03\x02\x02\x02\x03" + - "U\x03\x02\x02\x02\x03W\x03\x02\x02\x02\x03Y\x03\x02\x02\x02\x03[\x03\x02" + - "\x02\x02\x03]\x03\x02\x02\x02\x03_\x03\x02\x02\x02\x03a\x03\x02\x02\x02" + - "\x03c\x03\x02\x02\x02\x03e\x03\x02\x02\x02\x04g\x03\x02\x02\x02\x04i\x03" + - "\x02\x02\x02\x04k\x03\x02\x02\x02\x04m\x03\x02\x02\x02\x04o\x03\x02\x02" + - "\x02\x04s\x03\x02\x02\x02\x04u\x03\x02\x02\x02\x04w\x03\x02\x02\x02\x04" + - "y\x03\x02\x02\x02\x05{\x03\x02\x02\x02\x07\x82\x03\x02\x02\x02\t\x8C\x03" + - "\x02\x02\x02\v\x93\x03\x02\x02\x02\r\x99\x03\x02\x02\x02\x0F\xA1\x03\x02" + - "\x02\x02\x11\xA9\x03\x02\x02\x02\x13\xB0\x03\x02\x02\x02\x15\xB8\x03\x02" + - "\x02\x02\x17\xC2\x03\x02\x02\x02\x19\xD3\x03\x02\x02\x02\x1B\xE3\x03\x02" + - "\x02\x02\x1D\xE9\x03\x02\x02\x02\x1F\xED\x03\x02\x02\x02!\xEF\x03\x02" + - "\x02\x02#\xF1\x03\x02\x02\x02%\xF4\x03\x02\x02\x02\'\xF6\x03\x02\x02\x02" + - ")\u011C\x03\x02\x02\x02+\u011F\x03\x02\x02\x02-\u014D\x03\x02\x02\x02" + - "/\u014F\x03\x02\x02\x021\u0152\x03\x02\x02\x023\u0156\x03\x02\x02\x02" + - "5\u0158\x03\x02\x02\x027\u015A\x03\x02\x02\x029\u015C\x03\x02\x02\x02" + - ";\u015E\x03\x02\x02\x02=\u0162\x03\x02\x02\x02?\u0167\x03\x02\x02\x02" + - "A\u016B\x03\x02\x02\x02C\u0170\x03\x02\x02\x02E\u0173\x03\x02\x02\x02" + - "G\u017E\x03\x02\x02\x02I\u018A\x03\x02\x02\x02K\u018C\x03\x02\x02\x02" + - "M\u018E\x03\x02\x02\x02O\u0190\x03\x02\x02\x02Q\u0192\x03\x02\x02\x02" + - "S\u0194\x03\x02\x02\x02U\u019D\x03\x02\x02\x02W\u019F\x03\x02\x02\x02" + - "Y\u01AE\x03\x02\x02\x02[\u01C1\x03\x02\x02\x02]\u01C5\x03\x02\x02\x02" + - "_\u01CF\x03\x02\x02\x02a\u01DA\x03\x02\x02\x02c\u01DE\x03\x02\x02\x02" + - "e\u01E2\x03\x02\x02\x02g\u01E6\x03\x02\x02\x02i\u01EB\x03\x02\x02\x02" + - "k\u01F1\x03\x02\x02\x02m\u01F5\x03\x02\x02\x02o\u01FA\x03\x02\x02\x02" + - "q\u0205\x03\x02\x02\x02s\u0207\x03\x02\x02\x02u\u0209\x03\x02\x02\x02" + - "w\u020D\x03\x02\x02\x02y\u0211\x03\x02\x02\x02{|\x07g\x02\x02|}\x07x\x02" + - "\x02}~\x07c\x02\x02~\x7F\x07n\x02\x02\x7F\x80\x03\x02\x02\x02\x80\x81" + - "\b\x02\x02\x02\x81\x06\x03\x02\x02\x02\x82\x83\x07g\x02\x02\x83\x84\x07" + - "z\x02\x02\x84\x85\x07r\x02\x02\x85\x86\x07n\x02\x02\x86\x87\x07c\x02\x02" + - "\x87\x88\x07k\x02\x02\x88\x89\x07p\x02\x02\x89\x8A\x03\x02\x02\x02\x8A" + - "\x8B\b\x03\x02\x02\x8B\b\x03\x02\x02\x02\x8C\x8D\x07h\x02\x02\x8D\x8E" + - "\x07t\x02\x02\x8E\x8F\x07q\x02\x02\x8F\x90\x07o\x02\x02\x90\x91\x03\x02" + - "\x02\x02\x91\x92\b\x04\x03\x02\x92\n\x03\x02\x02\x02\x93\x94\x07t\x02" + - "\x02\x94\x95\x07q\x02\x02\x95\x96\x07y\x02\x02\x96\x97\x03\x02\x02\x02" + - "\x97\x98\b\x05\x02\x02\x98\f\x03\x02\x02\x02\x99\x9A\x07u\x02\x02\x9A" + - "\x9B\x07v\x02\x02\x9B\x9C\x07c\x02\x02\x9C\x9D\x07v\x02\x02\x9D\x9E\x07" + - "u\x02\x02\x9E\x9F\x03\x02\x02\x02\x9F\xA0\b\x06\x02\x02\xA0\x0E\x03\x02" + - "\x02\x02\xA1\xA2\x07y\x02\x02\xA2\xA3\x07j\x02\x02\xA3\xA4\x07g\x02\x02" + - "\xA4\xA5\x07t\x02\x02\xA5\xA6\x07g\x02\x02\xA6\xA7\x03\x02\x02\x02\xA7" + - "\xA8\b\x07\x02\x02\xA8\x10\x03\x02\x02\x02\xA9\xAA\x07u\x02\x02\xAA\xAB" + - "\x07q\x02\x02\xAB\xAC\x07t\x02\x02\xAC\xAD\x07v\x02\x02\xAD\xAE\x03\x02" + - "\x02\x02\xAE\xAF\b\b\x02\x02\xAF\x12\x03\x02\x02\x02\xB0\xB1\x07n\x02" + - "\x02\xB1\xB2\x07k\x02\x02\xB2\xB3\x07o\x02\x02\xB3\xB4\x07k\x02\x02\xB4" + - "\xB5\x07v\x02\x02\xB5\xB6\x03\x02\x02\x02\xB6\xB7\b\t\x02\x02\xB7\x14" + - "\x03\x02\x02\x02\xB8\xB9\x07r\x02\x02\xB9\xBA\x07t\x02\x02\xBA\xBB\x07" + - "q\x02\x02\xBB\xBC\x07l\x02\x02\xBC\xBD\x07g\x02\x02\xBD\xBE\x07e\x02\x02" + - "\xBE\xBF\x07v\x02\x02\xBF\xC0\x03\x02\x02\x02\xC0\xC1\b\n\x03\x02\xC1" + - "\x16\x03\x02\x02\x02\xC2\xC3\x071\x02\x02\xC3\xC4\x071\x02\x02\xC4\xC8" + - "\x03\x02\x02\x02\xC5\xC7\n\x02\x02\x02\xC6\xC5\x03\x02\x02\x02\xC7\xCA" + - "\x03\x02\x02\x02\xC8\xC6\x03\x02\x02\x02\xC8\xC9\x03\x02\x02\x02\xC9\xCC" + - "\x03\x02\x02\x02\xCA\xC8\x03\x02\x02\x02\xCB\xCD\x07\x0F\x02\x02\xCC\xCB" + - "\x03\x02\x02\x02\xCC\xCD\x03\x02\x02\x02\xCD\xCF\x03\x02\x02\x02\xCE\xD0" + - "\x07\f\x02\x02\xCF\xCE\x03\x02\x02\x02\xCF\xD0\x03\x02\x02\x02\xD0\xD1" + - "\x03\x02\x02\x02\xD1\xD2\b\v\x04\x02\xD2\x18\x03\x02\x02\x02\xD3\xD4\x07" + - "1\x02\x02\xD4\xD5\x07,\x02\x02\xD5\xDA\x03\x02\x02\x02\xD6\xD9\x05\x19" + - "\f\x02\xD7\xD9\v\x02\x02\x02\xD8\xD6\x03\x02\x02\x02\xD8\xD7\x03\x02\x02" + - "\x02\xD9\xDC\x03\x02\x02\x02\xDA\xDB\x03\x02\x02\x02\xDA\xD8\x03\x02\x02" + - "\x02\xDB\xDD\x03\x02\x02\x02\xDC\xDA\x03\x02\x02\x02\xDD\xDE\x07,\x02" + - "\x02\xDE\xDF\x071\x02\x02\xDF\xE0\x03\x02\x02\x02\xE0\xE1\b\f\x04\x02" + - "\xE1\x1A\x03\x02\x02\x02\xE2\xE4\t\x03\x02\x02\xE3\xE2\x03\x02\x02\x02" + - "\xE4\xE5\x03\x02\x02\x02\xE5\xE3\x03\x02\x02\x02\xE5\xE6\x03\x02\x02\x02" + - "\xE6\xE7\x03\x02\x02\x02\xE7\xE8\b\r\x04\x02\xE8\x1C\x03\x02\x02\x02\xE9" + - "\xEA\x07~\x02\x02\xEA\xEB\x03\x02\x02\x02\xEB\xEC\b\x0E\x05\x02\xEC\x1E" + - "\x03\x02\x02\x02\xED\xEE\t\x04\x02\x02\xEE \x03\x02\x02\x02\xEF\xF0\t" + - "\x05\x02\x02\xF0\"\x03\x02\x02\x02\xF1\xF2\x07^\x02\x02\xF2\xF3\t\x06" + - "\x02\x02\xF3$\x03\x02\x02\x02\xF4\xF5\n\x07\x02\x02\xF5&\x03\x02\x02\x02" + - "\xF6\xF8\t\b\x02\x02\xF7\xF9\t\t\x02\x02\xF8\xF7\x03\x02\x02\x02\xF8\xF9" + - "\x03\x02\x02\x02\xF9\xFB\x03\x02\x02\x02\xFA\xFC\x05\x1F\x0F\x02\xFB\xFA" + - "\x03\x02\x02\x02\xFC\xFD\x03\x02\x02\x02\xFD\xFB\x03\x02\x02\x02\xFD\xFE" + - "\x03\x02\x02\x02\xFE(\x03\x02\x02\x02\xFF\u0104\x07$\x02\x02\u0100\u0103" + - "\x05#\x11\x02\u0101\u0103\x05%\x12\x02\u0102\u0100\x03\x02\x02\x02\u0102" + - "\u0101\x03\x02\x02\x02\u0103\u0106\x03\x02\x02\x02\u0104\u0102\x03\x02" + - "\x02\x02\u0104\u0105\x03\x02\x02\x02\u0105\u0107\x03\x02\x02\x02\u0106" + - "\u0104\x03\x02\x02\x02\u0107\u011D\x07$\x02\x02\u0108\u0109\x07$\x02\x02" + - "\u0109\u010A\x07$\x02\x02\u010A\u010B\x07$\x02\x02\u010B\u010F\x03\x02" + - "\x02\x02\u010C\u010E\n\x02\x02\x02\u010D\u010C\x03\x02\x02\x02\u010E\u0111" + - "\x03\x02\x02\x02\u010F\u0110\x03\x02\x02\x02\u010F\u010D\x03\x02\x02\x02" + - "\u0110\u0112\x03\x02\x02\x02\u0111\u010F\x03\x02\x02\x02\u0112\u0113\x07" + - "$\x02\x02\u0113\u0114\x07$\x02\x02\u0114\u0115\x07$\x02\x02\u0115\u0117" + - "\x03\x02\x02\x02\u0116\u0118\x07$\x02\x02\u0117\u0116\x03\x02\x02\x02" + - "\u0117\u0118\x03\x02\x02\x02\u0118\u011A\x03\x02\x02\x02\u0119\u011B\x07" + - "$\x02\x02\u011A\u0119\x03\x02\x02\x02\u011A\u011B\x03\x02\x02\x02\u011B" + - "\u011D\x03\x02\x02\x02\u011C\xFF\x03\x02\x02\x02\u011C\u0108\x03\x02\x02" + - "\x02\u011D*\x03\x02\x02\x02\u011E\u0120\x05\x1F\x0F\x02\u011F\u011E\x03" + - "\x02\x02\x02\u0120\u0121\x03\x02\x02\x02\u0121\u011F\x03\x02\x02\x02\u0121" + - "\u0122\x03\x02\x02\x02\u0122,\x03\x02\x02\x02\u0123\u0125\x05\x1F\x0F" + - "\x02\u0124\u0123\x03\x02\x02\x02\u0125\u0126\x03\x02\x02\x02\u0126\u0124" + - "\x03\x02\x02\x02\u0126\u0127\x03\x02\x02\x02\u0127\u0128\x03\x02\x02\x02" + - "\u0128\u012C\x057\x1B\x02\u0129\u012B\x05\x1F\x0F\x02\u012A\u0129\x03" + - "\x02\x02\x02\u012B\u012E\x03\x02\x02\x02\u012C\u012A\x03\x02\x02\x02\u012C" + - "\u012D\x03\x02\x02\x02\u012D\u014E\x03\x02\x02\x02\u012E\u012C\x03\x02" + - "\x02\x02\u012F\u0131\x057\x1B\x02\u0130\u0132\x05\x1F\x0F\x02\u0131\u0130" + - "\x03\x02\x02\x02\u0132\u0133\x03\x02\x02\x02\u0133\u0131\x03\x02\x02\x02" + - "\u0133\u0134\x03\x02\x02\x02\u0134\u014E\x03\x02\x02\x02\u0135\u0137\x05" + - "\x1F\x0F\x02\u0136\u0135\x03\x02\x02\x02\u0137\u0138\x03\x02\x02\x02\u0138" + - "\u0136\x03\x02\x02\x02\u0138\u0139\x03\x02\x02\x02\u0139\u0141\x03\x02" + - "\x02\x02\u013A\u013E\x057\x1B\x02\u013B\u013D\x05\x1F\x0F\x02\u013C\u013B" + - "\x03\x02\x02\x02\u013D\u0140\x03\x02\x02\x02\u013E\u013C\x03\x02\x02\x02" + - "\u013E\u013F\x03\x02\x02\x02\u013F\u0142\x03\x02\x02\x02\u0140\u013E\x03" + - "\x02\x02\x02\u0141\u013A\x03\x02\x02\x02\u0141\u0142\x03\x02\x02\x02\u0142" + - "\u0143\x03\x02\x02\x02\u0143\u0144\x05\'\x13\x02\u0144\u014E\x03\x02\x02" + - "\x02\u0145\u0147\x057\x1B\x02\u0146\u0148\x05\x1F\x0F\x02\u0147\u0146" + - "\x03\x02\x02\x02\u0148\u0149\x03\x02\x02\x02\u0149\u0147\x03\x02\x02\x02" + - "\u0149\u014A\x03\x02\x02\x02\u014A\u014B\x03\x02\x02\x02\u014B\u014C\x05" + - "\'\x13\x02\u014C\u014E\x03\x02\x02\x02\u014D\u0124\x03\x02\x02\x02\u014D" + - "\u012F\x03\x02\x02\x02\u014D\u0136\x03\x02\x02\x02\u014D\u0145\x03\x02" + - "\x02\x02\u014E.\x03\x02\x02\x02\u014F\u0150\x07d\x02\x02\u0150\u0151\x07" + - "{\x02\x02\u01510\x03\x02\x02\x02\u0152\u0153\x07c\x02\x02\u0153\u0154" + - "\x07p\x02\x02\u0154\u0155\x07f\x02\x02\u01552\x03\x02\x02\x02\u0156\u0157" + - "\x07?\x02\x02\u01574\x03\x02\x02\x02\u0158\u0159\x07.\x02\x02\u01596\x03" + - "\x02\x02\x02\u015A\u015B\x070\x02\x02\u015B8\x03\x02\x02\x02\u015C\u015D" + - "\x07*\x02\x02\u015D:\x03\x02\x02\x02\u015E\u015F\x07]\x02\x02\u015F\u0160" + - "\x03\x02\x02\x02\u0160\u0161\b\x1D\x06\x02\u0161<\x03\x02\x02\x02\u0162" + - "\u0163\x07_\x02\x02\u0163\u0164\x03\x02\x02\x02\u0164\u0165\b\x1E\x05" + - "\x02\u0165\u0166\b\x1E\x05\x02\u0166>\x03\x02\x02\x02\u0167\u0168\x07" + - "p\x02\x02\u0168\u0169\x07q\x02\x02\u0169\u016A\x07v\x02\x02\u016A@\x03" + - "\x02\x02\x02\u016B\u016C\x07p\x02\x02\u016C\u016D\x07w\x02\x02\u016D\u016E" + - "\x07n\x02\x02\u016E\u016F\x07n\x02\x02\u016FB\x03\x02\x02\x02\u0170\u0171" + - "\x07q\x02\x02\u0171\u0172\x07t\x02\x02\u0172D\x03\x02\x02\x02\u0173\u0174" + - "\x07+\x02\x02\u0174F\x03\x02\x02\x02\u0175\u0176\x07v\x02\x02\u0176\u0177" + - "\x07t\x02\x02\u0177\u0178\x07w\x02\x02\u0178\u017F\x07g\x02\x02\u0179" + - "\u017A\x07h\x02\x02\u017A\u017B\x07c\x02\x02\u017B\u017C\x07n\x02\x02" + - "\u017C\u017D\x07u\x02\x02\u017D\u017F\x07g\x02\x02\u017E\u0175\x03\x02" + - "\x02\x02\u017E\u0179\x03\x02\x02\x02\u017FH\x03\x02\x02\x02\u0180\u0181" + - "\x07?\x02\x02\u0181\u018B\x07?\x02\x02\u0182\u0183\x07#\x02\x02\u0183" + - "\u018B\x07?\x02\x02\u0184\u018B\x07>\x02\x02\u0185\u0186\x07>\x02\x02" + - "\u0186\u018B\x07?\x02\x02\u0187\u018B\x07@\x02\x02\u0188\u0189\x07@\x02" + - "\x02\u0189\u018B\x07?\x02\x02\u018A\u0180\x03\x02\x02\x02\u018A\u0182" + - "\x03\x02\x02\x02\u018A\u0184\x03\x02\x02\x02\u018A\u0185\x03\x02\x02\x02" + - "\u018A\u0187\x03\x02\x02\x02\u018A\u0188\x03\x02\x02\x02\u018BJ\x03\x02" + - "\x02\x02\u018C\u018D\x07-\x02\x02\u018DL\x03\x02\x02\x02\u018E\u018F\x07" + - "/\x02\x02\u018FN\x03\x02\x02\x02\u0190\u0191\x07,\x02\x02\u0191P\x03\x02" + - "\x02\x02\u0192\u0193\x071\x02\x02\u0193R\x03\x02\x02\x02\u0194\u0195\x07" + - "\'\x02\x02\u0195T\x03\x02\x02\x02\u0196\u0197\x07c\x02\x02\u0197\u0198" + - "\x07u\x02\x02\u0198\u019E\x07e\x02\x02\u0199\u019A\x07f\x02\x02\u019A" + - "\u019B\x07g\x02\x02\u019B\u019C\x07u\x02\x02\u019C\u019E\x07e\x02\x02" + - "\u019D\u0196\x03\x02\x02\x02\u019D\u0199\x03\x02\x02\x02\u019EV\x03\x02" + - "\x02\x02\u019F\u01A0\x07p\x02\x02\u01A0\u01A1\x07w\x02\x02\u01A1\u01A2" + - "\x07n\x02\x02\u01A2\u01A3\x07n\x02\x02\u01A3\u01A4\x07u\x02\x02\u01A4" + - "X\x03\x02\x02\x02\u01A5\u01A6\x07h\x02\x02\u01A6\u01A7\x07k\x02\x02\u01A7" + - "\u01A8\x07t\x02\x02\u01A8\u01A9\x07u\x02\x02\u01A9\u01AF\x07v\x02\x02" + - "\u01AA\u01AB\x07n\x02\x02\u01AB\u01AC\x07c\x02\x02\u01AC\u01AD\x07u\x02" + - "\x02\u01AD\u01AF\x07v\x02\x02\u01AE\u01A5\x03\x02\x02\x02\u01AE\u01AA" + - "\x03\x02\x02\x02\u01AFZ\x03\x02\x02\x02\u01B0\u01B1\x07t\x02\x02\u01B1" + - "\u01B2\x07q\x02\x02\u01B2\u01B3\x07w\x02\x02\u01B3\u01B4\x07p\x02\x02" + - "\u01B4\u01C2\x07f\x02\x02\u01B5\u01B6\x07c\x02\x02\u01B6\u01B7\x07x\x02" + - "\x02\u01B7\u01C2\x07i\x02\x02\u01B8\u01B9\x07o\x02\x02\u01B9\u01BA\x07" + - "k\x02\x02\u01BA\u01C2\x07p\x02\x02\u01BB\u01BC\x07o\x02\x02\u01BC\u01BD" + - "\x07c\x02\x02\u01BD\u01C2\x07z\x02\x02\u01BE\u01BF\x07u\x02\x02\u01BF" + - "\u01C0\x07w\x02\x02\u01C0\u01C2\x07o\x02\x02\u01C1\u01B0\x03\x02\x02\x02" + - "\u01C1\u01B5\x03\x02\x02\x02\u01C1\u01B8\x03\x02\x02\x02\u01C1\u01BB\x03" + - "\x02\x02\x02\u01C1\u01BE\x03\x02\x02\x02\u01C2\\\x03\x02\x02\x02\u01C3" + - "\u01C6\x05!\x10\x02\u01C4\u01C6\x07a\x02\x02\u01C5\u01C3\x03\x02\x02\x02" + - "\u01C5\u01C4\x03\x02\x02\x02\u01C6\u01CC\x03\x02\x02\x02\u01C7\u01CB\x05" + - "!\x10\x02\u01C8\u01CB\x05\x1F\x0F\x02\u01C9\u01CB\x07a\x02\x02\u01CA\u01C7" + - "\x03\x02\x02\x02\u01CA\u01C8\x03\x02\x02\x02\u01CA\u01C9\x03\x02\x02\x02" + - "\u01CB\u01CE\x03\x02\x02\x02\u01CC\u01CA\x03\x02\x02\x02\u01CC\u01CD\x03" + - "\x02\x02\x02\u01CD^\x03\x02\x02\x02\u01CE\u01CC\x03\x02\x02\x02\u01CF" + - "\u01D5\x07b\x02\x02\u01D0\u01D4\n\n\x02\x02\u01D1\u01D2\x07b\x02\x02\u01D2" + - "\u01D4\x07b\x02\x02\u01D3\u01D0\x03\x02\x02\x02\u01D3\u01D1\x03\x02\x02" + - "\x02\u01D4\u01D7\x03\x02\x02\x02\u01D5\u01D3\x03\x02\x02\x02\u01D5\u01D6" + - "\x03\x02\x02\x02\u01D6\u01D8\x03\x02\x02\x02\u01D7\u01D5\x03\x02\x02\x02" + - "\u01D8\u01D9\x07b\x02\x02\u01D9`\x03\x02\x02\x02\u01DA\u01DB\x05\x17\v" + - "\x02\u01DB\u01DC\x03\x02\x02\x02\u01DC\u01DD\b0\x04\x02\u01DDb\x03\x02" + - "\x02\x02\u01DE\u01DF\x05\x19\f\x02\u01DF\u01E0\x03\x02\x02\x02\u01E0\u01E1" + - "\b1\x04\x02\u01E1d\x03\x02\x02\x02\u01E2\u01E3\x05\x1B\r\x02\u01E3\u01E4" + - "\x03\x02\x02\x02\u01E4\u01E5\b2\x04\x02\u01E5f\x03\x02\x02\x02\u01E6\u01E7" + - "\x07~\x02\x02\u01E7\u01E8\x03\x02\x02\x02\u01E8\u01E9\b3\x07\x02\u01E9" + - "\u01EA\b3\x05\x02\u01EAh\x03\x02\x02\x02\u01EB\u01EC\x07_\x02\x02\u01EC" + - "\u01ED\x03\x02\x02\x02\u01ED\u01EE\b4\x05\x02\u01EE\u01EF\b4\x05\x02\u01EF" + - "\u01F0\b4\b\x02\u01F0j\x03\x02\x02\x02\u01F1\u01F2\x07.\x02\x02\u01F2" + - "\u01F3\x03\x02\x02\x02\u01F3\u01F4\b5\t\x02\u01F4l\x03\x02\x02\x02\u01F5" + - "\u01F6\x07?\x02\x02\u01F6\u01F7\x03\x02\x02\x02\u01F7\u01F8\b6\n\x02\u01F8" + - "n\x03\x02\x02\x02\u01F9\u01FB\x05q8\x02\u01FA\u01F9\x03\x02\x02\x02\u01FB" + - "\u01FC\x03\x02\x02\x02\u01FC\u01FA\x03\x02\x02\x02\u01FC\u01FD\x03\x02" + - "\x02\x02\u01FDp\x03\x02\x02\x02\u01FE\u0200\n\v\x02\x02\u01FF\u01FE\x03" + - "\x02\x02\x02\u0200\u0201\x03\x02\x02\x02\u0201\u01FF\x03\x02\x02\x02\u0201" + - "\u0202\x03\x02\x02\x02\u0202\u0206\x03\x02\x02\x02\u0203\u0204\x071\x02" + - "\x02\u0204\u0206\n\f\x02\x02\u0205\u01FF\x03\x02\x02\x02\u0205\u0203\x03" + - "\x02\x02\x02\u0206r\x03\x02\x02\x02\u0207\u0208\x05_/\x02\u0208t\x03\x02" + - "\x02\x02\u0209\u020A\x05\x17\v\x02\u020A\u020B\x03\x02\x02\x02\u020B\u020C" + - "\b:\x04\x02\u020Cv\x03\x02\x02\x02\u020D\u020E\x05\x19\f\x02\u020E\u020F" + - "\x03\x02\x02\x02\u020F\u0210\b;\x04\x02\u0210x\x03\x02\x02\x02\u0211\u0212" + - "\x05\x1B\r\x02\u0212\u0213\x03\x02\x02\x02\u0213\u0214\b<\x04\x02\u0214" + - "z\x03\x02\x02\x02)\x02\x03\x04\xC8\xCC\xCF\xD8\xDA\xE5\xF8\xFD\u0102\u0104" + - "\u010F\u0117\u011A\u011C\u0121\u0126\u012C\u0133\u0138\u013E\u0141\u0149" + - "\u014D\u017E\u018A\u019D\u01AE\u01C1\u01C5\u01CA\u01CC\u01D3\u01D5\u01FC" + - "\u0201\u0205\v\x07\x03\x02\x07\x04\x02\x02\x03\x02\x06\x02\x02\x07\x02" + - "\x02\t\x0F\x02\t\x1A\x02\t\x16\x02\t\x15\x02"; + private static readonly _serializedATNSegments: number = 3; + private static readonly _serializedATNSegment0: string = + "\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x02S\u0574\b\x01" + + "\b\x01\b\x01\b\x01\b\x01\x04\x02\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04" + + "\x05\t\x05\x04\x06\t\x06\x04\x07\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04" + + "\v\t\v\x04\f\t\f\x04\r\t\r\x04\x0E\t\x0E\x04\x0F\t\x0F\x04\x10\t\x10\x04" + + "\x11\t\x11\x04\x12\t\x12\x04\x13\t\x13\x04\x14\t\x14\x04\x15\t\x15\x04" + + "\x16\t\x16\x04\x17\t\x17\x04\x18\t\x18\x04\x19\t\x19\x04\x1A\t\x1A\x04" + + "\x1B\t\x1B\x04\x1C\t\x1C\x04\x1D\t\x1D\x04\x1E\t\x1E\x04\x1F\t\x1F\x04" + + " \t \x04!\t!\x04\"\t\"\x04#\t#\x04$\t$\x04%\t%\x04&\t&\x04\'\t\'\x04(" + + "\t(\x04)\t)\x04*\t*\x04+\t+\x04,\t,\x04-\t-\x04.\t.\x04/\t/\x040\t0\x04" + + "1\t1\x042\t2\x043\t3\x044\t4\x045\t5\x046\t6\x047\t7\x048\t8\x049\t9\x04" + + ":\t:\x04;\t;\x04<\t<\x04=\t=\x04>\t>\x04?\t?\x04@\t@\x04A\tA\x04B\tB\x04" + + "C\tC\x04D\tD\x04E\tE\x04F\tF\x04G\tG\x04H\tH\x04I\tI\x04J\tJ\x04K\tK\x04" + + "L\tL\x04M\tM\x04N\tN\x04O\tO\x04P\tP\x04Q\tQ\x04R\tR\x04S\tS\x04T\tT\x04" + + "U\tU\x04V\tV\x04W\tW\x04X\tX\x04Y\tY\x04Z\tZ\x04[\t[\x04\\\t\\\x04]\t" + + "]\x04^\t^\x04_\t_\x04`\t`\x04a\ta\x04b\tb\x04c\tc\x04d\td\x04e\te\x04" + + "f\tf\x04g\tg\x04h\th\x04i\ti\x04j\tj\x04k\tk\x04l\tl\x04m\tm\x04n\tn\x04" + + "o\to\x04p\tp\x04q\tq\x04r\tr\x04s\ts\x04t\tt\x04u\tu\x04v\tv\x04w\tw\x04" + + "x\tx\x04y\ty\x04z\tz\x04{\t{\x04|\t|\x04}\t}\x03\x02\x03\x02\x03\x02\x03" + + "\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03" + + "\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03" + + "\x04\x03\x04\x03\x04\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03" + + "\x05\x03\x05\x03\x05\x03\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03" + + "\x06\x03\x06\x03\x07\x03\x07\x03\x07\x03\x07\x03\x07\x03\x07\x03\b\x03" + + "\b\x03\b\x03\b\x03\b\x03\b\x03\b\x03\b\x03\t\x03\t\x03\t\x03\t\x03\t\x03" + + "\t\x03\t\x03\t\x03\n\x03\n\x03\n\x03\n\x03\n\x03\n\x03\n\x03\v\x03\v\x03" + + "\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\f\x03\f\x03" + + "\f\x03\f\x03\f\x03\f\x03\f\x03\f\x03\r\x03\r\x03\r\x03\r\x03\r\x03\r\x03" + + "\r\x03\r\x03\r\x03\r\x03\x0E\x03\x0E\x03\x0E\x03\x0E\x03\x0E\x03\x0E\x03" + + "\x0E\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03" + + "\x0F\x03\x10\x03\x10\x03\x10\x03\x10\x03\x10\x03\x10\x03\x10\x03\x11\x03" + + "\x11\x03\x11\x03\x11\x03\x11\x03\x11\x03\x11\x03\x11\x03\x11\x03\x12\x03" + + "\x12\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12\x03\x13\x03\x13\x03\x13\x03" + + "\x13\x07\x13\u018F\n\x13\f\x13\x0E\x13\u0192\v\x13\x03\x13\x05\x13\u0195" + + "\n\x13\x03\x13\x05\x13\u0198\n\x13\x03\x13\x03\x13\x03\x14\x03\x14\x03" + + "\x14\x03\x14\x03\x14\x07\x14\u01A1\n\x14\f\x14\x0E\x14\u01A4\v\x14\x03" + + "\x14\x03\x14\x03\x14\x03\x14\x03\x14\x03\x15\x06\x15\u01AC\n\x15\r\x15" + + "\x0E\x15\u01AD\x03\x15\x03\x15\x03\x16\x03\x16\x03\x16\x03\x16\x03\x16" + + "\x03\x17\x03\x17\x03\x17\x03\x17\x03\x17\x03\x18\x03\x18\x03\x18\x03\x18" + + "\x03\x19\x03\x19\x03\x19\x03\x19\x03\x1A\x03\x1A\x03\x1A\x03\x1A\x03\x1B" + + "\x03\x1B\x03\x1B\x03\x1B\x03\x1C\x03\x1C\x03\x1D\x03\x1D\x03\x1E\x03\x1E" + + "\x03\x1E\x03\x1F\x03\x1F\x03 \x03 \x05 \u01D7\n \x03 \x06 \u01DA\n \r" + + " \x0E \u01DB\x03!\x03!\x03!\x07!\u01E1\n!\f!\x0E!\u01E4\v!\x03!\x03!\x03" + + "!\x03!\x03!\x03!\x07!\u01EC\n!\f!\x0E!\u01EF\v!\x03!\x03!\x03!\x03!\x03" + + "!\x05!\u01F6\n!\x03!\x05!\u01F9\n!\x05!\u01FB\n!\x03\"\x06\"\u01FE\n\"" + + "\r\"\x0E\"\u01FF\x03#\x06#\u0203\n#\r#\x0E#\u0204\x03#\x03#\x07#\u0209" + + "\n#\f#\x0E#\u020C\v#\x03#\x03#\x06#\u0210\n#\r#\x0E#\u0211\x03#\x06#\u0215" + + "\n#\r#\x0E#\u0216\x03#\x03#\x07#\u021B\n#\f#\x0E#\u021E\v#\x05#\u0220" + + "\n#\x03#\x03#\x03#\x03#\x06#\u0226\n#\r#\x0E#\u0227\x03#\x03#\x05#\u022C" + + "\n#\x03$\x03$\x03$\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03" + + "%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03%\x03" + + "%\x03%\x03%\x03%\x05%\u024D\n%\x03&\x03&\x03&\x03&\x03\'\x03\'\x03(\x03" + + "(\x03)\x03)\x03*\x03*\x03+\x03+\x03+\x03+\x03+\x03,\x03,\x03,\x03,\x03" + + ",\x03-\x03-\x03-\x03-\x03.\x03.\x03.\x03.\x03.\x03/\x03/\x03/\x03/\x03" + + "/\x03/\x030\x030\x030\x031\x031\x031\x032\x032\x032\x033\x033\x033\x03" + + "3\x033\x034\x034\x034\x035\x035\x036\x036\x037\x037\x037\x037\x037\x03" + + "8\x038\x038\x038\x038\x038\x038\x038\x038\x038\x039\x039\x039\x039\x03" + + "9\x039\x039\x039\x039\x059\u02A1\n9\x03:\x03:\x03:\x03:\x03:\x03:\x03" + + ":\x03:\x03:\x03:\x05:\u02AD\n:\x03;\x03;\x03<\x03<\x03=\x03=\x03>\x03" + + ">\x03?\x03?\x03@\x03@\x03@\x03A\x03A\x03A\x03A\x03A\x03A\x03A\x05A\u02C3" + + "\nA\x03B\x03B\x03B\x03B\x03B\x03B\x03C\x03C\x03C\x03C\x03C\x03C\x03C\x03" + + "C\x03C\x05C\u02D4\nC\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03D\x03" + + "D\x03D\x03D\x05D\u0440\nD\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03" + + "E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03" + + "E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03" + + "E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03" + + "E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03" + + "E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03E\x03" + + "E\x03E\x03E\x05E\u0493\nE\x03F\x03F\x03F\x03F\x03F\x03F\x03F\x03F\x03" + + "F\x03F\x03F\x03G\x03G\x03G\x03G\x03G\x07G\u04A5\nG\fG\x0EG\u04A8\vG\x03" + + "G\x03G\x03G\x03G\x03G\x06G\u04AF\nG\rG\x0EG\u04B0\x05G\u04B3\nG\x03H\x03" + + "H\x03H\x03H\x07H\u04B9\nH\fH\x0EH\u04BC\vH\x03H\x03H\x03I\x03I\x03I\x03" + + "I\x03J\x03J\x03J\x03J\x03K\x03K\x03K\x03K\x03L\x03L\x03L\x03L\x03L\x03" + + "M\x03M\x03M\x03M\x03M\x03M\x03N\x03N\x03N\x03N\x03N\x03N\x03O\x03O\x03" + + "O\x03O\x03P\x03P\x03P\x03P\x03Q\x03Q\x03Q\x03Q\x03Q\x03Q\x03Q\x03Q\x03" + + "Q\x03R\x06R\u04EF\nR\rR\x0ER\u04F0\x03S\x06S\u04F4\nS\rS\x0ES\u04F5\x03" + + "S\x03S\x05S\u04FA\nS\x03T\x03T\x03U\x03U\x03U\x03U\x03V\x03V\x03V\x03" + + "V\x03W\x03W\x03W\x03W\x03X\x03X\x03X\x03Y\x03Y\x03Y\x03Y\x03Y\x03Z\x03" + + "Z\x03Z\x03Z\x03Z\x03[\x03[\x03[\x03[\x03[\x03[\x03\\\x03\\\x03\\\x03\\" + + "\x03]\x03]\x03]\x03]\x03^\x06^\u0526\n^\r^\x0E^\u0527\x03_\x06_\u052B" + + "\n_\r_\x0E_\u052C\x03_\x03_\x05_\u0531\n_\x03`\x03`\x03a\x03a\x03a\x03" + + "a\x03b\x03b\x03b\x03b\x03c\x03c\x03c\x03c\x03d\x03d\x03e\x03e\x03f\x03" + + "f\x03g\x03g\x03h\x03h\x03i\x03i\x03j\x03j\x03k\x03k\x03l\x03l\x03m\x03" + + "m\x03n\x03n\x03o\x03o\x03p\x03p\x03q\x03q\x03r\x03r\x03s\x03s\x03t\x03" + + "t\x03u\x03u\x03v\x03v\x03w\x03w\x03x\x03x\x03y\x03y\x03z\x03z\x03{\x03" + + "{\x03|\x03|\x03}\x03}\x04\u01A2\u01ED\x02\x02~\x07\x02\x03\t\x02\x04\v" + + "\x02\x05\r\x02\x06\x0F\x02\x07\x11\x02\b\x13\x02\t\x15\x02\n\x17\x02\v" + + "\x19\x02\f\x1B\x02\r\x1D\x02\x0E\x1F\x02\x0F!\x02\x10#\x02\x11%\x02\x12" + + "\'\x02\x13)\x02\x14+\x02\x15-\x02\x16/\x02\x021\x02S3\x02\x175\x02\x18" + + "7\x02\x199\x02\x1A;\x02\x02=\x02\x02?\x02\x02A\x02\x02C\x02\x02E\x02\x1B" + + "G\x02\x1CI\x02\x1DK\x02\x1EM\x02\x1FO\x02 Q\x02!S\x02\"U\x02#W\x02$Y\x02" + + "%[\x02&]\x02\'_\x02(a\x02)c\x02*e\x02+g\x02,i\x02-k\x02.m\x02/o\x020q" + + "\x021s\x022u\x023w\x024y\x025{\x026}\x027\x7F\x028\x81\x029\x83\x02:\x85" + + "\x02;\x87\x02<\x89\x02=\x8B\x02>\x8D\x02?\x8F\x02@\x91\x02A\x93\x02B\x95" + + "\x02C\x97\x02D\x99\x02E\x9B\x02\x02\x9D\x02\x02\x9F\x02\x02\xA1\x02\x02" + + "\xA3\x02\x02\xA5\x02F\xA7\x02G\xA9\x02\x02\xAB\x02H\xAD\x02I\xAF\x02J" + + "\xB1\x02K\xB3\x02L\xB5\x02M\xB7\x02\x02\xB9\x02\x02\xBB\x02\x02\xBD\x02" + + "\x02\xBF\x02N\xC1\x02\x02\xC3\x02O\xC5\x02P\xC7\x02Q\xC9\x02R\xCB\x02" + + "\x02\xCD\x02\x02\xCF\x02\x02\xD1\x02\x02\xD3\x02\x02\xD5\x02\x02\xD7\x02" + + "\x02\xD9\x02\x02\xDB\x02\x02\xDD\x02\x02\xDF\x02\x02\xE1\x02\x02\xE3\x02" + + "\x02\xE5\x02\x02\xE7\x02\x02\xE9\x02\x02\xEB\x02\x02\xED\x02\x02\xEF\x02" + + "\x02\xF1\x02\x02\xF3\x02\x02\xF5\x02\x02\xF7\x02\x02\xF9\x02\x02\xFB\x02" + + "\x02\xFD\x02\x02\x07\x02\x03\x04\x05\x06\'\x04\x02\f\f\x0F\x0F\x05\x02" + + "\v\f\x0F\x0F\"\"\x03\x022;\x04\x02C\\c|\x07\x02$$^^ppttvv\x06\x02\f\f" + + "\x0F\x0F$$^^\x04\x02GGgg\x04\x02--//\x04\x02BBaa\x03\x02bb\f\x02\v\f\x0F" + + "\x0F\"\"..11??]]__bb~~\x04\x02,,11\x04\x02CCcc\x04\x02DDdd\x04\x02EEe" + + "e\x04\x02FFff\x04\x02HHhh\x04\x02IIii\x04\x02JJjj\x04\x02KKkk\x04\x02" + + "LLll\x04\x02MMmm\x04\x02NNnn\x04\x02OOoo\x04\x02PPpp\x04\x02QQqq\x04\x02" + + "RRrr\x04\x02SSss\x04\x02TTtt\x04\x02UUuu\x04\x02VVvv\x04\x02WWww\x04\x02" + + "XXxx\x04\x02YYyy\x04\x02ZZzz\x04\x02[[{{\x04\x02\\\\||\x02\u05B8\x02\x07" + + "\x03\x02\x02\x02\x02\t\x03\x02\x02\x02\x02\v\x03\x02\x02\x02\x02\r\x03" + + "\x02\x02\x02\x02\x0F\x03\x02\x02\x02\x02\x11\x03\x02\x02\x02\x02\x13\x03" + + "\x02\x02\x02\x02\x15\x03\x02\x02\x02\x02\x17\x03\x02\x02\x02\x02\x19\x03" + + "\x02\x02\x02\x02\x1B\x03\x02\x02\x02\x02\x1D\x03\x02\x02\x02\x02\x1F\x03" + + "\x02\x02\x02\x02!\x03\x02\x02\x02\x02#\x03\x02\x02\x02\x02%\x03\x02\x02" + + "\x02\x02\'\x03\x02\x02\x02\x02)\x03\x02\x02\x02\x02+\x03\x02\x02\x02\x02" + + "-\x03\x02\x02\x02\x03/\x03\x02\x02\x02\x031\x03\x02\x02\x02\x033\x03\x02" + + "\x02\x02\x035\x03\x02\x02\x02\x037\x03\x02\x02\x02\x049\x03\x02\x02\x02" + + "\x04E\x03\x02\x02\x02\x04G\x03\x02\x02\x02\x04I\x03\x02\x02\x02\x04K\x03" + + "\x02\x02\x02\x04M\x03\x02\x02\x02\x04O\x03\x02\x02\x02\x04Q\x03\x02\x02" + + "\x02\x04S\x03\x02\x02\x02\x04U\x03\x02\x02\x02\x04W\x03\x02\x02\x02\x04" + + "Y\x03\x02\x02\x02\x04[\x03\x02\x02\x02\x04]\x03\x02\x02\x02\x04_\x03\x02" + + "\x02\x02\x04a\x03\x02\x02\x02\x04c\x03\x02\x02\x02\x04e\x03\x02\x02\x02" + + "\x04g\x03\x02\x02\x02\x04i\x03\x02\x02\x02\x04k\x03\x02\x02\x02\x04m\x03" + + "\x02\x02\x02\x04o\x03\x02\x02\x02\x04q\x03\x02\x02\x02\x04s\x03\x02\x02" + + "\x02\x04u\x03\x02\x02\x02\x04w\x03\x02\x02\x02\x04y\x03\x02\x02\x02\x04" + + "{\x03\x02\x02\x02\x04}\x03\x02\x02\x02\x04\x7F\x03\x02\x02\x02\x04\x81" + + "\x03\x02\x02\x02\x04\x83\x03\x02\x02\x02\x04\x85\x03\x02\x02\x02\x04\x87" + + "\x03\x02\x02\x02\x04\x89\x03\x02\x02\x02\x04\x8B\x03\x02\x02\x02\x04\x8D" + + "\x03\x02\x02\x02\x04\x8F\x03\x02\x02\x02\x04\x91\x03\x02\x02\x02\x04\x93" + + "\x03\x02\x02\x02\x04\x95\x03\x02\x02\x02\x04\x97\x03\x02\x02\x02\x04\x99" + + "\x03\x02\x02\x02\x05\x9B\x03\x02\x02\x02\x05\x9D\x03\x02\x02\x02\x05\x9F" + + "\x03\x02\x02\x02\x05\xA1\x03\x02\x02\x02\x05\xA3\x03\x02\x02\x02\x05\xA5" + + "\x03\x02\x02\x02\x05\xA7\x03\x02\x02\x02\x05\xAB\x03\x02\x02\x02\x05\xAD" + + "\x03\x02\x02\x02\x05\xAF\x03\x02\x02\x02\x05\xB1\x03\x02\x02\x02\x06\xB3" + + "\x03\x02\x02\x02\x06\xB5\x03\x02\x02\x02\x06\xB7\x03\x02\x02\x02\x06\xB9" + + "\x03\x02\x02\x02\x06\xBB\x03\x02\x02\x02\x06\xBD\x03\x02\x02\x02\x06\xBF" + + "\x03\x02\x02\x02\x06\xC3\x03\x02\x02\x02\x06\xC5\x03\x02\x02\x02\x06\xC7" + + "\x03\x02\x02\x02\x06\xC9\x03\x02\x02\x02\x07\xFF\x03\x02\x02\x02\t\u0109" + + "\x03\x02\x02\x02\v\u0110\x03\x02\x02\x02\r\u0117\x03\x02\x02\x02\x0F\u0121" + + "\x03\x02\x02\x02\x11\u0128\x03\x02\x02\x02\x13\u012E\x03\x02\x02\x02\x15" + + "\u0136\x03\x02\x02\x02\x17\u013E\x03\x02\x02\x02\x19\u0145\x03\x02\x02" + + "\x02\x1B\u0151\x03\x02\x02\x02\x1D\u0159\x03\x02\x02\x02\x1F\u0163\x03" + + "\x02\x02\x02!\u016A\x03\x02\x02\x02#\u0173\x03\x02\x02\x02%\u017A\x03" + + "\x02\x02\x02\'\u0183\x03\x02\x02\x02)\u018A\x03\x02\x02\x02+\u019B\x03" + + "\x02\x02\x02-\u01AB\x03\x02\x02\x02/\u01B1\x03\x02\x02\x021\u01B6\x03" + + "\x02\x02\x023\u01BB\x03\x02\x02\x025\u01BF\x03\x02\x02\x027\u01C3\x03" + + "\x02\x02\x029\u01C7\x03\x02\x02\x02;\u01CB\x03\x02\x02\x02=\u01CD\x03" + + "\x02\x02\x02?\u01CF\x03\x02\x02\x02A\u01D2\x03\x02\x02\x02C\u01D4\x03" + + "\x02\x02\x02E\u01FA\x03\x02\x02\x02G\u01FD\x03\x02\x02\x02I\u022B\x03" + + "\x02\x02\x02K\u022D\x03\x02\x02\x02M\u024C\x03\x02\x02\x02O\u024E\x03" + + "\x02\x02\x02Q\u0252\x03\x02\x02\x02S\u0254\x03\x02\x02\x02U\u0256\x03" + + "\x02\x02\x02W\u0258\x03\x02\x02\x02Y\u025A\x03\x02\x02\x02[\u025F\x03" + + "\x02\x02\x02]\u0264\x03\x02\x02\x02_\u0268\x03\x02\x02\x02a\u026D\x03" + + "\x02\x02\x02c\u0273\x03\x02\x02\x02e\u0276\x03\x02\x02\x02g\u0279\x03" + + "\x02\x02\x02i\u027C\x03\x02\x02\x02k\u0281\x03\x02\x02\x02m\u0284\x03" + + "\x02\x02\x02o\u0286\x03\x02\x02\x02q\u0288\x03\x02\x02\x02s\u028D\x03" + + "\x02\x02\x02u\u02A0\x03\x02\x02\x02w\u02AC\x03\x02\x02\x02y\u02AE\x03" + + "\x02\x02\x02{\u02B0\x03\x02\x02\x02}\u02B2\x03\x02\x02\x02\x7F\u02B4\x03" + + "\x02\x02\x02\x81\u02B6\x03\x02\x02\x02\x83\u02B8\x03\x02\x02\x02\x85\u02C2" + + "\x03\x02\x02\x02\x87\u02C4\x03\x02\x02\x02\x89\u02D3\x03\x02\x02\x02\x8B" + + "\u043F\x03\x02\x02\x02\x8D\u0492\x03\x02\x02\x02\x8F\u0494\x03\x02\x02" + + "\x02\x91\u04B2\x03\x02\x02\x02\x93\u04B4\x03\x02\x02\x02\x95\u04BF\x03" + + "\x02\x02\x02\x97\u04C3\x03\x02\x02\x02\x99\u04C7\x03\x02\x02\x02\x9B\u04CB" + + "\x03\x02\x02\x02\x9D\u04D0\x03\x02\x02\x02\x9F\u04D6\x03\x02\x02\x02\xA1" + + "\u04DC\x03\x02\x02\x02\xA3\u04E0\x03\x02\x02\x02\xA5\u04E4\x03\x02\x02" + + "\x02\xA7\u04EE\x03\x02\x02\x02\xA9\u04F9\x03\x02\x02\x02\xAB\u04FB\x03" + + "\x02\x02\x02\xAD\u04FD\x03\x02\x02\x02\xAF\u0501\x03\x02\x02\x02\xB1\u0505" + + "\x03\x02\x02\x02\xB3\u0509\x03\x02\x02\x02\xB5\u050C\x03\x02\x02\x02\xB7" + + "\u0511\x03\x02\x02\x02\xB9\u0516\x03\x02\x02\x02\xBB\u051C\x03\x02\x02" + + "\x02\xBD\u0520\x03\x02\x02\x02\xBF\u0525\x03\x02\x02\x02\xC1\u0530\x03" + + "\x02\x02\x02\xC3\u0532\x03\x02\x02\x02\xC5\u0534\x03\x02\x02\x02\xC7\u0538" + + "\x03\x02\x02\x02\xC9\u053C\x03\x02\x02\x02\xCB\u0540\x03\x02\x02\x02\xCD" + + "\u0542\x03\x02\x02\x02\xCF\u0544\x03\x02\x02\x02\xD1\u0546\x03\x02\x02" + + "\x02\xD3\u0548\x03\x02\x02\x02\xD5\u054A\x03\x02\x02\x02\xD7\u054C\x03" + + "\x02\x02\x02\xD9\u054E\x03\x02\x02\x02\xDB\u0550\x03\x02\x02\x02\xDD\u0552" + + "\x03\x02\x02\x02\xDF\u0554\x03\x02\x02\x02\xE1\u0556\x03\x02\x02\x02\xE3" + + "\u0558\x03\x02\x02\x02\xE5\u055A\x03\x02\x02\x02\xE7\u055C\x03\x02\x02" + + "\x02\xE9\u055E\x03\x02\x02\x02\xEB\u0560\x03\x02\x02\x02\xED\u0562\x03" + + "\x02\x02\x02\xEF\u0564\x03\x02\x02\x02\xF1\u0566\x03\x02\x02\x02\xF3\u0568" + + "\x03\x02\x02\x02\xF5\u056A\x03\x02\x02\x02\xF7\u056C\x03\x02\x02\x02\xF9" + + "\u056E\x03\x02\x02\x02\xFB\u0570\x03\x02\x02\x02\xFD\u0572\x03\x02\x02" + + "\x02\xFF\u0100\x05\xD1g\x02\u0100\u0101\x05\xDBl\x02\u0101\u0102\x05\xEF" + + "v\x02\u0102\u0103\x05\xEFv\x02\u0103\u0104\x05\xD3h\x02\u0104\u0105\x05" + + "\xCFf\x02\u0105\u0106\x05\xF1w\x02\u0106\u0107\x03\x02\x02\x02\u0107\u0108" + + "\b\x02\x02\x02\u0108\b\x03\x02\x02\x02\u0109\u010A\x05\xD7j\x02\u010A" + + "\u010B\x05\xEDu\x02\u010B\u010C\x05\xE7r\x02\u010C\u010D\x05\xDFn\x02" + + "\u010D\u010E\x03\x02\x02\x02\u010E\u010F\b\x03\x02\x02\u010F\n\x03\x02" + + "\x02\x02\u0110\u0111\x05\xD3h\x02\u0111\u0112\x05\xF5y\x02\u0112\u0113" + + "\x05\xCBd\x02\u0113\u0114\x05\xE1o\x02\u0114\u0115\x03\x02\x02\x02\u0115" + + "\u0116\b\x04\x02\x02\u0116\f\x03\x02\x02\x02\u0117\u0118\x05\xD3h\x02" + + "\u0118\u0119\x05\xF9{\x02\u0119\u011A\x05\xE9s\x02\u011A\u011B\x05\xE1" + + "o\x02\u011B\u011C\x05\xCBd\x02\u011C\u011D\x05\xDBl\x02\u011D\u011E\x05" + + "\xE5q\x02\u011E\u011F\x03\x02\x02\x02\u011F\u0120\b\x05\x03\x02\u0120" + + "\x0E\x03\x02\x02\x02\u0121\u0122\x05\xD5i\x02\u0122\u0123\x05\xEDu\x02" + + "\u0123\u0124\x05"; + private static readonly _serializedATNSegment1: string = + "\xE7r\x02\u0124\u0125\x05\xE3p\x02\u0125\u0126\x03\x02\x02\x02\u0126\u0127" + + "\b\x06\x04\x02\u0127\x10\x03\x02\x02\x02\u0128\u0129\x05\xEDu\x02\u0129" + + "\u012A\x05\xE7r\x02\u012A\u012B\x05\xF7z\x02\u012B\u012C\x03\x02\x02\x02" + + "\u012C\u012D\b\x07\x02\x02\u012D\x12\x03\x02\x02\x02\u012E\u012F\x05\xEF" + + "v\x02\u012F\u0130\x05\xF1w\x02\u0130\u0131\x05\xCBd\x02\u0131\u0132\x05" + + "\xF1w\x02\u0132\u0133\x05\xEFv\x02\u0133\u0134\x03\x02\x02\x02\u0134\u0135" + + "\b\b\x02\x02\u0135\x14\x03\x02\x02\x02\u0136\u0137\x05\xF7z\x02\u0137" + + "\u0138\x05\xD9k\x02\u0138\u0139\x05\xD3h\x02\u0139\u013A\x05\xEDu\x02" + + "\u013A\u013B\x05\xD3h\x02\u013B\u013C\x03\x02\x02\x02\u013C\u013D\b\t" + + "\x02\x02\u013D\x16\x03\x02\x02\x02\u013E\u013F\x05\xEFv\x02\u013F\u0140" + + "\x05\xE7r\x02\u0140\u0141\x05\xEDu\x02\u0141\u0142\x05\xF1w\x02\u0142" + + "\u0143\x03\x02\x02\x02\u0143\u0144\b\n\x02\x02\u0144\x18\x03\x02\x02\x02" + + "\u0145\u0146\x05\xE3p\x02\u0146\u0147\x05\xF5y\x02\u0147\u0148\x05o6\x02" + + "\u0148\u0149\x05\xD3h\x02\u0149\u014A\x05\xF9{\x02\u014A\u014B\x05\xE9" + + "s\x02\u014B\u014C\x05\xCBd\x02\u014C\u014D\x05\xE5q\x02\u014D\u014E\x05" + + "\xD1g\x02\u014E\u014F\x03\x02\x02\x02\u014F\u0150\b\v\x02\x02\u0150\x1A" + + "\x03\x02\x02\x02\u0151\u0152\x05\xE1o\x02\u0152\u0153\x05\xDBl\x02\u0153" + + "\u0154\x05\xE3p\x02\u0154\u0155\x05\xDBl\x02\u0155\u0156\x05\xF1w\x02" + + "\u0156\u0157\x03\x02\x02\x02\u0157\u0158\b\f\x02\x02\u0158\x1C\x03\x02" + + "\x02\x02\u0159\u015A\x05\xE9s\x02\u015A\u015B\x05\xEDu\x02\u015B\u015C" + + "\x05\xE7r\x02\u015C\u015D\x05\xDDm\x02\u015D\u015E\x05\xD3h\x02\u015E" + + "\u015F\x05\xCFf\x02\u015F\u0160\x05\xF1w\x02\u0160\u0161\x03\x02\x02\x02" + + "\u0161\u0162\b\r\x02\x02\u0162\x1E\x03\x02\x02\x02\u0163\u0164\x05\xD1" + + "g\x02\u0164\u0165\x05\xEDu\x02\u0165\u0166\x05\xE7r\x02\u0166\u0167\x05" + + "\xE9s\x02\u0167\u0168\x03\x02\x02\x02\u0168\u0169\b\x0E\x02\x02\u0169" + + " \x03\x02\x02\x02\u016A\u016B\x05\xEDu\x02\u016B\u016C\x05\xD3h\x02\u016C" + + "\u016D\x05\xE5q\x02\u016D\u016E\x05\xCBd\x02\u016E\u016F\x05\xE3p\x02" + + "\u016F\u0170\x05\xD3h\x02\u0170\u0171\x03\x02\x02\x02\u0171\u0172\b\x0F" + + "\x02\x02\u0172\"\x03\x02\x02\x02\u0173\u0174\x05\xEFv\x02\u0174\u0175" + + "\x05\xD9k\x02\u0175\u0176\x05\xE7r\x02\u0176\u0177\x05\xF7z\x02\u0177" + + "\u0178\x03\x02\x02\x02\u0178\u0179\b\x10\x02\x02\u0179$\x03\x02\x02\x02" + + "\u017A\u017B\x05\xD3h\x02\u017B\u017C\x05\xE5q\x02\u017C\u017D\x05\xED" + + "u\x02\u017D\u017E\x05\xDBl\x02\u017E\u017F\x05\xCFf\x02\u017F\u0180\x05" + + "\xD9k\x02\u0180\u0181\x03\x02\x02\x02\u0181\u0182\b\x11\x05\x02\u0182" + + "&\x03\x02\x02\x02\u0183\u0184\x05\xDFn\x02\u0184\u0185\x05\xD3h\x02\u0185" + + "\u0186\x05\xD3h\x02\u0186\u0187\x05\xE9s\x02\u0187\u0188\x03\x02\x02\x02" + + "\u0188\u0189\b\x12\x02\x02\u0189(\x03\x02\x02\x02\u018A\u018B\x071\x02" + + "\x02\u018B\u018C\x071\x02\x02\u018C\u0190\x03\x02\x02\x02\u018D\u018F" + + "\n\x02\x02\x02\u018E\u018D\x03\x02\x02\x02\u018F\u0192\x03\x02\x02\x02" + + "\u0190\u018E\x03\x02\x02\x02\u0190\u0191\x03\x02\x02\x02\u0191\u0194\x03" + + "\x02\x02\x02\u0192\u0190\x03\x02\x02\x02\u0193\u0195\x07\x0F\x02\x02\u0194" + + "\u0193\x03\x02\x02\x02\u0194\u0195\x03\x02\x02\x02\u0195\u0197\x03\x02" + + "\x02\x02\u0196\u0198\x07\f\x02\x02\u0197\u0196\x03\x02\x02\x02\u0197\u0198" + + "\x03\x02\x02\x02\u0198\u0199\x03\x02\x02\x02\u0199\u019A\b\x13\x06\x02" + + "\u019A*\x03\x02\x02\x02\u019B\u019C\x071\x02\x02\u019C\u019D\x07,\x02" + + "\x02\u019D\u01A2\x03\x02\x02\x02\u019E\u01A1\x05+\x14\x02\u019F\u01A1" + + "\v\x02\x02\x02\u01A0\u019E\x03\x02\x02\x02\u01A0\u019F\x03\x02\x02\x02" + + "\u01A1\u01A4\x03\x02\x02\x02\u01A2\u01A3\x03\x02\x02\x02\u01A2\u01A0\x03" + + "\x02\x02\x02\u01A3\u01A5\x03\x02\x02\x02\u01A4\u01A2\x03\x02\x02\x02\u01A5" + + "\u01A6\x07,\x02\x02\u01A6\u01A7\x071\x02\x02\u01A7\u01A8\x03\x02\x02\x02" + + "\u01A8\u01A9\b\x14\x06\x02\u01A9,\x03\x02\x02\x02\u01AA\u01AC\t\x03\x02" + + "\x02\u01AB\u01AA\x03\x02\x02\x02\u01AC\u01AD\x03\x02\x02\x02\u01AD\u01AB" + + "\x03\x02\x02\x02\u01AD\u01AE\x03\x02\x02\x02\u01AE\u01AF\x03\x02\x02\x02" + + "\u01AF\u01B0\b\x15\x06\x02\u01B0.\x03\x02\x02\x02\u01B1\u01B2\x07]\x02" + + "\x02\u01B2\u01B3\x03\x02\x02\x02\u01B3\u01B4\b\x16\x07\x02\u01B4\u01B5" + + "\b\x16\b\x02\u01B50\x03\x02\x02\x02\u01B6\u01B7\x07~\x02\x02\u01B7\u01B8" + + "\x03\x02\x02\x02\u01B8\u01B9\b\x17\t\x02\u01B9\u01BA\b\x17\n\x02\u01BA" + + "2\x03\x02\x02\x02\u01BB\u01BC\x05-\x15\x02\u01BC\u01BD\x03\x02\x02\x02" + + "\u01BD\u01BE\b\x18\x06\x02\u01BE4\x03\x02\x02\x02\u01BF\u01C0\x05)\x13" + + "\x02\u01C0\u01C1\x03\x02\x02\x02\u01C1\u01C2\b\x19\x06\x02\u01C26\x03" + + "\x02\x02\x02\u01C3\u01C4\x05+\x14\x02\u01C4\u01C5\x03\x02\x02\x02\u01C5" + + "\u01C6\b\x1A\x06\x02\u01C68\x03\x02\x02\x02\u01C7\u01C8\x07~\x02\x02\u01C8" + + "\u01C9\x03\x02\x02\x02\u01C9\u01CA\b\x1B\n\x02\u01CA:\x03\x02\x02\x02" + + "\u01CB\u01CC\t\x04\x02\x02\u01CC<\x03\x02\x02\x02\u01CD\u01CE\t\x05\x02" + + "\x02\u01CE>\x03\x02\x02\x02\u01CF\u01D0\x07^\x02\x02\u01D0\u01D1\t\x06" + + "\x02\x02\u01D1@\x03\x02\x02\x02\u01D2\u01D3\n\x07\x02\x02\u01D3B\x03\x02" + + "\x02\x02\u01D4\u01D6\t\b\x02\x02\u01D5\u01D7\t\t\x02\x02\u01D6\u01D5\x03" + + "\x02\x02\x02\u01D6\u01D7\x03\x02\x02\x02\u01D7\u01D9\x03\x02\x02\x02\u01D8" + + "\u01DA\x05;\x1C\x02\u01D9\u01D8\x03\x02\x02\x02\u01DA\u01DB\x03\x02\x02" + + "\x02\u01DB\u01D9\x03\x02\x02\x02\u01DB\u01DC\x03\x02\x02\x02\u01DCD\x03" + + "\x02\x02\x02\u01DD\u01E2\x07$\x02\x02\u01DE\u01E1\x05?\x1E\x02\u01DF\u01E1" + + "\x05A\x1F\x02\u01E0\u01DE\x03\x02\x02\x02\u01E0\u01DF\x03\x02\x02\x02" + + "\u01E1\u01E4\x03\x02\x02\x02\u01E2\u01E0\x03\x02\x02\x02\u01E2\u01E3\x03" + + "\x02\x02\x02\u01E3\u01E5\x03\x02\x02\x02\u01E4\u01E2\x03\x02\x02\x02\u01E5" + + "\u01FB\x07$\x02\x02\u01E6\u01E7\x07$\x02\x02\u01E7\u01E8\x07$\x02\x02" + + "\u01E8\u01E9\x07$\x02\x02\u01E9\u01ED\x03\x02\x02\x02\u01EA\u01EC\n\x02" + + "\x02\x02\u01EB\u01EA\x03\x02\x02\x02\u01EC\u01EF\x03\x02\x02\x02\u01ED" + + "\u01EE\x03\x02\x02\x02\u01ED\u01EB\x03\x02\x02\x02\u01EE\u01F0\x03\x02" + + "\x02\x02\u01EF\u01ED\x03\x02\x02\x02\u01F0\u01F1\x07$\x02\x02\u01F1\u01F2" + + "\x07$\x02\x02\u01F2\u01F3\x07$\x02\x02\u01F3\u01F5\x03\x02\x02\x02\u01F4" + + "\u01F6\x07$\x02\x02\u01F5\u01F4\x03\x02\x02\x02\u01F5\u01F6\x03\x02\x02" + + "\x02\u01F6\u01F8\x03\x02\x02\x02\u01F7\u01F9\x07$\x02\x02\u01F8\u01F7" + + "\x03\x02\x02\x02\u01F8\u01F9\x03\x02\x02\x02\u01F9\u01FB\x03\x02\x02\x02" + + "\u01FA\u01DD\x03\x02\x02\x02\u01FA\u01E6\x03\x02\x02\x02\u01FBF\x03\x02" + + "\x02\x02\u01FC\u01FE\x05;\x1C\x02\u01FD\u01FC\x03\x02\x02\x02\u01FE\u01FF" + + "\x03\x02\x02\x02\u01FF\u01FD\x03\x02\x02\x02\u01FF\u0200\x03\x02\x02\x02" + + "\u0200H\x03\x02\x02\x02\u0201\u0203\x05;\x1C\x02\u0202\u0201\x03\x02\x02" + + "\x02\u0203\u0204\x03\x02\x02\x02\u0204\u0202\x03\x02\x02\x02\u0204\u0205" + + "\x03\x02\x02\x02\u0205\u0206\x03\x02\x02\x02\u0206\u020A\x05U)\x02\u0207" + + "\u0209\x05;\x1C\x02\u0208\u0207\x03\x02\x02\x02\u0209\u020C\x03\x02\x02" + + "\x02\u020A\u0208\x03\x02\x02\x02\u020A\u020B\x03\x02\x02\x02\u020B\u022C" + + "\x03\x02\x02\x02\u020C\u020A\x03\x02\x02\x02\u020D\u020F\x05U)\x02\u020E" + + "\u0210\x05;\x1C\x02\u020F\u020E\x03\x02\x02\x02\u0210\u0211\x03\x02\x02" + + "\x02\u0211\u020F\x03\x02\x02\x02\u0211\u0212\x03\x02\x02\x02\u0212\u022C" + + "\x03\x02\x02\x02\u0213\u0215\x05;\x1C\x02\u0214\u0213\x03\x02\x02\x02" + + "\u0215\u0216\x03\x02\x02\x02\u0216\u0214\x03\x02\x02\x02\u0216\u0217\x03" + + "\x02\x02\x02\u0217\u021F\x03\x02\x02\x02\u0218\u021C\x05U)\x02\u0219\u021B" + + "\x05;\x1C\x02\u021A\u0219\x03\x02\x02\x02\u021B\u021E\x03\x02\x02\x02" + + "\u021C\u021A\x03\x02\x02\x02\u021C\u021D\x03\x02\x02\x02\u021D\u0220\x03" + + "\x02\x02\x02\u021E\u021C\x03\x02\x02\x02\u021F\u0218\x03\x02\x02\x02\u021F" + + "\u0220\x03\x02\x02\x02\u0220\u0221\x03\x02\x02\x02\u0221\u0222\x05C \x02" + + "\u0222\u022C\x03\x02\x02\x02\u0223\u0225\x05U)\x02\u0224\u0226\x05;\x1C" + + "\x02\u0225\u0224\x03\x02\x02\x02\u0226\u0227\x03\x02\x02\x02\u0227\u0225" + + "\x03\x02\x02\x02\u0227\u0228\x03\x02\x02\x02\u0228\u0229\x03\x02\x02\x02" + + "\u0229\u022A\x05C \x02\u022A\u022C\x03\x02\x02\x02\u022B\u0202\x03\x02" + + "\x02\x02\u022B\u020D\x03\x02\x02\x02\u022B\u0214\x03\x02\x02\x02\u022B" + + "\u0223\x03\x02\x02\x02\u022CJ\x03\x02\x02\x02\u022D\u022E\x07d\x02\x02" + + "\u022E\u022F\x07{\x02\x02\u022FL\x03\x02\x02\x02\u0230\u0231\x07{\x02" + + "\x02\u0231\u0232\x07g\x02\x02\u0232\u0233\x07c\x02\x02\u0233\u024D\x07" + + "t\x02\x02\u0234\u0235\x07o\x02\x02\u0235\u0236\x07q\x02\x02\u0236\u0237" + + "\x07p\x02\x02\u0237\u0238\x07v\x02\x02\u0238\u024D\x07j\x02\x02\u0239" + + "\u023A\x07f\x02\x02\u023A\u023B\x07c\x02\x02\u023B\u024D\x07{\x02\x02" + + "\u023C\u023D\x07u\x02\x02\u023D\u023E\x07g\x02\x02\u023E\u023F\x07e\x02" + + "\x02\u023F\u0240\x07q\x02\x02\u0240\u0241\x07p\x02\x02\u0241\u024D\x07" + + "f\x02\x02\u0242\u0243\x07o\x02\x02\u0243\u0244\x07k\x02\x02\u0244\u0245" + + "\x07p\x02\x02\u0245\u0246\x07w\x02\x02\u0246\u0247\x07v\x02\x02\u0247" + + "\u024D\x07g\x02\x02\u0248\u0249\x07j\x02\x02\u0249\u024A\x07q\x02\x02" + + "\u024A\u024B\x07w\x02\x02\u024B\u024D\x07t\x02\x02\u024C\u0230\x03\x02" + + "\x02\x02\u024C\u0234\x03\x02\x02\x02\u024C\u0239\x03\x02\x02\x02\u024C" + + "\u023C\x03\x02\x02\x02\u024C\u0242\x03\x02\x02\x02\u024C\u0248\x03\x02" + + "\x02\x02\u024DN\x03\x02\x02\x02\u024E\u024F\x07c\x02\x02\u024F\u0250\x07" + + "p\x02\x02\u0250\u0251\x07f\x02\x02\u0251P\x03\x02\x02\x02\u0252\u0253" + + "\x07?\x02\x02\u0253R\x03\x02\x02\x02\u0254\u0255\x07.\x02\x02\u0255T\x03" + + "\x02\x02\x02\u0256\u0257\x070\x02\x02\u0257V\x03\x02\x02\x02\u0258\u0259" + + "\x07*\x02\x02\u0259X\x03\x02\x02\x02\u025A\u025B\x07]\x02\x02\u025B\u025C" + + "\x03\x02\x02\x02\u025C\u025D\b+\x02\x02\u025D\u025E\b+\x02\x02\u025EZ" + + "\x03\x02\x02\x02\u025F\u0260\x07_\x02\x02\u0260\u0261\x03\x02\x02\x02" + + "\u0261\u0262\b,\n\x02\u0262\u0263\b,\n\x02\u0263\\\x03\x02\x02\x02\u0264" + + "\u0265\x05\xE5q\x02\u0265\u0266\x05\xE7r\x02\u0266\u0267\x05\xF1w\x02" + + "\u0267^\x03\x02\x02\x02\u0268\u0269\x05\xE1o\x02\u0269\u026A\x05\xDBl" + + "\x02\u026A\u026B\x05\xDFn\x02\u026B\u026C\x05\xD3h\x02\u026C`\x03\x02" + + "\x02\x02\u026D\u026E\x05\xEDu\x02\u026E\u026F\x05\xE1o\x02\u026F\u0270" + + "\x05\xDBl\x02\u0270\u0271\x05\xDFn\x02\u0271\u0272\x05\xD3h\x02\u0272" + + "b\x03\x02\x02\x02\u0273\u0274\x05\xDBl\x02\u0274\u0275\x05\xE5q\x02\u0275" + + "d\x03\x02\x02\x02\u0276\u0277\x05\xDBl\x02\u0277\u0278\x05\xEFv\x02\u0278" + + "f\x03\x02\x02\x02\u0279\u027A\x05\xCBd\x02\u027A\u027B\x05\xEFv\x02\u027B" + + "h\x03\x02\x02\x02\u027C\u027D\x05\xE5q\x02\u027D\u027E\x05\xF3x\x02\u027E" + + "\u027F\x05\xE1o\x02\u027F\u0280\x05\xE1o\x02\u0280j\x03\x02\x02\x02\u0281" + + "\u0282\x07q\x02\x02\u0282\u0283\x07t\x02\x02\u0283l\x03\x02\x02\x02\u0284" + + "\u0285\x07+\x02\x02\u0285n\x03\x02\x02\x02\u0286\u0287\x07a\x02\x02\u0287" + + "p\x03\x02\x02\x02\u0288\u0289\x07k\x02\x02\u0289\u028A\x07p\x02\x02\u028A" + + "\u028B\x07h\x02\x02\u028B\u028C\x07q\x02\x02\u028Cr\x03\x02\x02\x02\u028D" + + "\u028E\x07h\x02\x02\u028E\u028F\x07w\x02\x02\u028F\u0290\x07p\x02\x02" + + "\u0290\u0291\x07e\x02\x02\u0291\u0292\x07v\x02\x02\u0292\u0293\x07k\x02" + + "\x02\u0293\u0294\x07q\x02\x02\u0294\u0295\x07p\x02\x02\u0295\u0296\x07" + + "u\x02\x02\u0296t\x03\x02\x02\x02\u0297\u0298\x07v\x02\x02\u0298\u0299" + + "\x07t\x02\x02\u0299\u029A\x07w\x02\x02\u029A\u02A1\x07g\x02\x02\u029B" + + "\u029C\x07h\x02\x02\u029C\u029D\x07c\x02\x02\u029D\u029E\x07n\x02\x02" + + "\u029E\u029F\x07u\x02\x02\u029F\u02A1\x07g\x02\x02\u02A0\u0297\x03\x02" + + "\x02\x02\u02A0\u029B\x03\x02\x02\x02\u02A1v\x03\x02\x02\x02\u02A2\u02A3" + + "\x07?\x02\x02\u02A3\u02AD\x07?\x02\x02\u02A4\u02A5\x07#\x02\x02\u02A5" + + "\u02AD\x07?\x02\x02\u02A6\u02AD\x07>\x02\x02\u02A7\u02A8\x07>\x02\x02" + + "\u02A8\u02AD\x07?\x02\x02\u02A9\u02AD\x07@\x02\x02\u02AA\u02AB\x07@\x02" + + "\x02\u02AB\u02AD\x07?\x02\x02\u02AC\u02A2\x03\x02\x02\x02\u02AC\u02A4" + + "\x03\x02\x02\x02\u02AC\u02A6\x03\x02\x02\x02\u02AC\u02A7\x03\x02\x02\x02" + + "\u02AC\u02A9\x03\x02\x02\x02\u02AC\u02AA\x03\x02\x02\x02\u02ADx\x03\x02" + + "\x02\x02\u02AE\u02AF\x07-\x02\x02\u02AFz\x03\x02\x02\x02\u02B0\u02B1\x07" + + "/\x02\x02\u02B1|\x03\x02\x02\x02\u02B2\u02B3\x07,\x02\x02\u02B3~\x03\x02" + + "\x02\x02\u02B4\u02B5\x071\x02\x02\u02B5\x80\x03\x02\x02\x02\u02B6\u02B7" + + "\x07\'\x02\x02\u02B7\x82\x03\x02\x02\x02\u02B8\u02B9\x073\x02\x02\u02B9" + + "\u02BA\x072\x02\x02\u02BA\x84\x03\x02\x02\x02\u02BB\u02BC\x07c\x02\x02" + + "\u02BC\u02BD\x07u\x02\x02\u02BD\u02C3\x07e\x02\x02\u02BE\u02BF\x07f\x02" + + "\x02\u02BF\u02C0\x07g\x02\x02\u02C0\u02C1\x07u\x02\x02\u02C1\u02C3\x07" + + "e\x02\x02\u02C2\u02BB\x03\x02\x02\x02\u02C2\u02BE\x03\x02\x02\x02\u02C3" + + "\x86\x03\x02\x02\x02\u02C4\u02C5\x07p\x02\x02\u02C5\u02C6\x07w\x02\x02" + + "\u02C6\u02C7\x07n\x02\x02\u02C7\u02C8\x07n\x02\x02\u02C8\u02C9\x07u\x02" + + "\x02\u02C9\x88\x03\x02\x02\x02\u02CA\u02CB\x07h\x02\x02\u02CB\u02CC\x07" + + "k\x02\x02\u02CC\u02CD\x07t\x02\x02\u02CD\u02CE\x07u\x02\x02\u02CE\u02D4" + + "\x07v\x02\x02\u02CF\u02D0\x07n\x02\x02\u02D0\u02D1\x07c\x02\x02\u02D1" + + "\u02D2\x07u\x02\x02\u02D2\u02D4\x07v\x02\x02\u02D3\u02CA\x03\x02\x02\x02" + + "\u02D3\u02CF\x03\x02\x02\x02\u02D4\x8A\x03\x02\x02\x02\u02D5\u02D6\x05" + + "\xEDu\x02\u02D6\u02D7\x05\xE7r\x02\u02D7\u02D8\x05\xF3x\x02\u02D8\u02D9" + + "\x05\xE5q\x02\u02D9\u02DA\x05\xD1g\x02\u02DA\u0440\x03\x02\x02\x02\u02DB" + + "\u02DC\x05\xCBd\x02\u02DC\u02DD\x05\xCDe\x02\u02DD\u02DE\x05\xEFv\x02" + + "\u02DE\u0440\x03\x02\x02\x02\u02DF\u02E0\x05\xE9s\x02\u02E0\u02E1\x05" + + "\xE7r\x02\u02E1\u02E2\x05\xF7z\x02\u02E2\u0440\x03\x02\x02\x02\u02E3\u02E4" + + "\x05\xE1o\x02\u02E4\u02E5\x05\xE7r\x02\u02E5\u02E6\x05\xD7j\x02\u02E6" + + "\u02E7\x05\x83@\x02\u02E7\u0440\x03\x02\x02\x02\u02E8\u02E9\x05\xE9s\x02" + + "\u02E9\u02EA\x05\xDBl\x02\u02EA\u0440\x03\x02\x02\x02\u02EB\u02EC\x05" + + "\xF1w\x02\u02EC\u02ED\x05\xCBd\x02\u02ED\u02EE\x05\xF3x\x02\u02EE\u0440" + + "\x03\x02\x02\x02\u02EF\u0440\x05\xD3h\x02\u02F0\u02F1\x05\xEFv\x02\u02F1" + + "\u02F2\x05\xF3x\x02\u02F2\u02F3\x05\xCDe\x02\u02F3\u02F4\x05\xEFv\x02" + + "\u02F4\u02F5\x05\xF1w\x02\u02F5\u02F6\x05\xEDu\x02\u02F6\u02F7\x05\xDB" + + "l\x02\u02F7\u02F8\x05\xE5q\x02\u02F8\u02F9\x05\xD7j\x02\u02F9\u0440\x03" + + "\x02\x02\x02\u02FA\u02FB\x05\xF1w\x02\u02FB\u02FC\x05\xEDu\x02\u02FC\u02FD" + + "\x05\xDBl\x02\u02FD\u02FE\x05\xE3p\x02\u02FE\u0440\x03\x02\x02\x02\u02FF" + + "\u0300\x05\xCFf\x02\u0300\u0301\x05\xE7r\x02\u0301\u0302\x05\xE5q\x02" + + "\u0302\u0303\x05\xCFf\x02\u0303\u0304\x05\xCBd\x02\u0304\u0305\x05\xF1" + + "w\x02\u0305\u0440\x03\x02\x02\x02\u0306\u0307\x05\xEFv\x02\u0307\u0308" + + "\x05\xF1w\x02\u0308\u0309\x05\xCBd\x02\u0309\u030A\x05\xEDu\x02\u030A" + + "\u030B\x05\xF1w\x02\u030B\u030C\x05\xEFv\x02\u030C\u030D\x05o6\x02\u030D" + + "\u030E\x05\xF7z\x02\u030E\u030F\x05\xDBl\x02\u030F\u0310\x05\xF1w\x02" + + "\u0310\u0311\x05\xD9k\x02\u0311\u0440\x03\x02\x02\x02\u0312\u0313\x05" + + "\xD1g\x02\u0313\u0314\x05\xCBd\x02\u0314\u0315\x05\xF1w\x02\u0315\u0316" + + "\x05\xD3h\x02\u0316\u0317\x05o6\x02\u0317\u0318\x05\xD5i\x02\u0318\u0319" + + "\x05\xE7r\x02\u0319\u031A\x05\xEDu\x02\u031A\u031B\x05\xE3p\x02\u031B" + + "\u031C\x05\xCBd\x02\u031C\u031D\x05\xF1w\x02\u031D\u0440\x03\x02\x02\x02" + + "\u031E\u031F\x05\xD1g\x02\u031F\u0320\x05\xCBd\x02\u0320\u0321\x05\xF1" + + "w\x02\u0321\u0322\x05\xD3h\x02\u0322\u0323\x05o6\x02\u0323\u0324\x05\xF1" + + "w\x02\u0324\u0325\x05\xEDu\x02\u0325\u0326\x05\xF3x\x02\u0326\u0327\x05" + + "\xE5q\x02\u0327\u0328\x05\xCFf\x02\u0328\u0440\x03\x02\x02\x02\u0329\u032A" + + "\x05\xD1g\x02\u032A\u032B\x05\xCBd\x02\u032B\u032C\x05\xF1w\x02\u032C" + + "\u032D\x05\xD3h\x02\u032D\u032E\x05o6\x02\u032E\u032F\x05\xE9s\x02\u032F" + + "\u0330\x05\xCBd\x02\u0330\u0331\x05\xEDu\x02\u0331\u0332\x05\xEFv\x02" + + "\u0332\u0333\x05\xD3h\x02\u0333\u0440\x03\x02\x02\x02\u0334\u0335\x05" + + "\xCBd\x02\u0335\u0336\x05\xF3x\x02\u0336\u0337\x05\xF1w\x02\u0337\u0338" + + "\x05\xE7r\x02\u0338\u0339\x05o6\x02\u0339\u033A\x05\xCDe\x02\u033A\u033B" + + "\x05\xF3x\x02\u033B\u033C\x05\xCFf\x02\u033C\u033D\x05\xDFn\x02\u033D" + + "\u033E\x05\xD3h\x02\u033E\u033F\x05\xF1w\x02\u033F\u0440\x03\x02\x02\x02" + + "\u0340\u0341\x05\xDBl\x02\u0341\u0342\x05\xEFv\x02\u0342\u0343\x05o6\x02" + + "\u0343\u0344\x05\xD5i\x02\u0344\u0345\x05\xDBl\x02\u0345\u0346\x05\xE5" + + "q\x02\u0346\u0347\x05\xDBl\x02\u0347\u0348\x05\xF1w\x02\u0348\u0349\x05" + + "\xD3h\x02\u0349\u0440\x03\x02\x02\x02\u034A\u034B\x05\xDBl\x02\u034B\u034C" + + "\x05\xEFv\x02\u034C\u034D\x05o6\x02\u034D\u034E\x05\xDBl\x02\u034E\u034F" + + "\x05\xE5q\x02\u034F\u0350\x05\xD5i\x02\u0350\u0351\x05\xDBl\x02\u0351" + + "\u0352\x05\xE5q\x02\u0352\u0353\x05\xDBl\x02\u0353\u0354\x05\xF1w\x02" + + "\u0354\u0355\x05\xD3h\x02\u0355\u0440\x03\x02\x02\x02\u0356\u0357\x05" + + "\xCFf\x02\u0357\u0358\x05\xCBd\x02\u0358\u0359\x05\xEFv\x02\u0359\u035A" + + "\x05\xD3h\x02\u035A\u0440\x03\x02\x02\x02\u035B\u035C\x05\xE1o\x02\u035C" + + "\u035D\x05\xD3h\x02\u035D\u035E\x05\xE5q\x02\u035E\u035F\x05\xD7j\x02" + + "\u035F\u0360\x05\xF1w\x02\u0360\u0361\x05\xD9k\x02\u0361\u0440\x03\x02" + + "\x02\x02\u0362\u0363\x05\xE3p\x02\u0363\u0364\x05\xF5y\x02\u0364\u0365" + + "\x05o6\x02\u0365\u0366\x05\xE3p\x02\u0366\u0367\x05\xCBd\x02\u0367\u0368" + + "\x05\xF9{\x02\u0368\u0440\x03\x02\x02\x02\u0369\u036A\x05\xE3p\x02\u036A" + + "\u036B\x05\xF5y\x02\u036B\u036C\x05o6\x02\u036C\u036D\x05\xE3p\x02\u036D" + + "\u036E\x05\xDBl\x02\u036E\u036F\x05\xE5q\x02\u036F\u0440\x03\x02\x02\x02" + + "\u0370\u0371\x05\xE3p\x02\u0371\u0372\x05\xF5y\x02\u0372\u0373\x05o6\x02" + + "\u0373\u0374\x05\xCBd\x02\u0374\u0375\x05\xF5y\x02\u0375\u0376\x05\xD7" + + "j\x02\u0376\u0440\x03\x02\x02\x02\u0377\u0378\x05\xE3p\x02\u0378\u0379" + + "\x05\xF5y\x02\u0379\u037A\x05o6\x02\u037A\u037B\x05\xEFv\x02\u037B\u037C" + + "\x05\xF3x\x02\u037C\u037D\x05\xE3p\x02\u037D\u0440\x03\x02\x02\x02\u037E" + + "\u037F\x05\xE3p\x02\u037F\u0380\x05\xF5y\x02\u0380\u0381\x05o6\x02\u0381" + + "\u0382\x05\xCFf\x02\u0382\u0383\x05\xE7r\x02\u0383\u0384\x05\xF3x\x02" + + "\u0384\u0385\x05\xE5q\x02\u0385\u0386\x05\xF1w\x02\u0386\u0440\x03\x02" + + "\x02\x02\u0387\u0388\x05\xE3p\x02\u0388\u0389\x05\xF5y\x02\u0389\u038A" + + "\x05o6\x02\u038A\u038B\x05\xCFf\x02\u038B\u038C\x05\xE7r\x02\u038C\u038D" + + "\x05\xE5q\x02\u038D\u038E\x05\xCFf\x02\u038E\u038F\x05\xCBd\x02\u038F" + + "\u0390\x05\xF1w\x02\u0390\u0440\x03\x02\x02\x02\u0391\u0392\x05\xE3p\x02" + + "\u0392\u0393\x05\xF5y\x02\u0393\u0394\x05o6\x02\u0394\u0395\x05\xDDm\x02" + + "\u0395\u0396\x05\xE7r\x02\u0396\u0397\x05\xDBl\x02\u0397\u0398\x05\xE5" + + "q\x02\u0398\u0440\x03\x02\x02\x02\u0399\u039A\x05\xE3p\x02\u039A\u039B" + + "\x05\xF5y\x02\u039B\u039C\x05o6\x02\u039C\u039D\x05\xE3p\x02\u039D\u039E" + + "\x05\xD3h\x02\u039E\u039F\x05\xD1g\x02\u039F\u03A0\x05\xDBl\x02\u03A0" + + "\u03A1\x05\xCBd\x02\u03A1\u03A2\x05\xE5q\x02\u03A2\u0440\x03\x02\x02\x02" + + "\u03A3\u03A4\x05\xE3p\x02\u03A4\u03A5\x05\xF5y\x02\u03A5\u03A6\x05o6\x02" + + "\u03A6\u03A7\x05\xD1g\x02\u03A7\u03A8\x05\xD3h\x02\u03A8\u03A9\x05\xD1" + + "g\x02\u03A9\u03AA\x05\xF3x\x02\u03AA\u03AB\x05\xE9s\x02\u03AB\u03AC\x05" + + "\xD3h\x02\u03AC\u0440\x03\x02\x02\x02\u03AD\u03AE\x05\xE3p\x02\u03AE\u03AF" + + "\x05\xD3h\x02\u03AF\u03B0\x05\xF1w\x02\u03B0\u03B1\x05\xCBd\x02\u03B1" + + "\u03B2\x05\xD1g\x02\u03B2\u03B3\x05\xCBd\x02\u03B3\u03B4\x05\xF1w\x02" + + "\u03B4\u03B5\x05\xCBd\x02\u03B5\u0440\x03\x02\x02\x02\u03B6\u03B7\x05" + + "\xEFv\x02\u03B7\u03B8\x05\xE9s\x02\u03B8\u03B9\x05\xE1o\x02\u03B9\u03BA" + + "\x05\xDBl\x02\u03BA\u03BB\x05\xF1w\x02\u03BB\u0440\x03\x02\x02\x02\u03BC" + + "\u03BD\x05\xF1w\x02\u03BD\u03BE\x05\xE7r\x02\u03BE\u03BF\x05o6\x02\u03BF" + + "\u03C0\x05\xEFv\x02\u03C0\u03C1\x05\xF1w\x02\u03C1\u03C2\x05\xEDu\x02" + + "\u03C2\u03C3\x05\xDBl\x02\u03C3\u03C4\x05\xE5q\x02\u03C4\u03C5\x05\xD7" + + "j\x02\u03C5\u0440\x03\x02\x02\x02\u03C6\u03C7\x05\xF1w\x02\u03C7\u03C8" + + "\x05\xE7r\x02\u03C8\u03C9\x05o6\x02\u03C9\u03CA\x05\xEFv\x02\u03CA\u03CB" + + "\x05\xF1w\x02\u03CB\u03CC\x05\xEDu\x02\u03CC\u0440\x03\x02\x02\x02\u03CD" + + "\u03CE\x05\xF1w\x02\u03CE\u03CF\x05\xE7r\x02\u03CF\u03D0\x05o6\x02\u03D0" + + "\u03D1\x05\xCDe\x02\u03D1\u03D2\x05\xE7r\x02\u03D2\u03D3\x05\xE7r\x02" + + "\u03D3\u03D4\x05\xE1o\x02\u03D4\u0440\x03\x02\x02\x02\u03D5\u03D6\x05" + + "\xF1w\x02\u03D6\u03D7\x05\xE7r\x02\u03D7\u03D8\x05o6\x02\u03D8\u03D9\x05" + + "\xCDe\x02\u03D9\u03DA\x05\xE7r\x02\u03DA\u03DB\x05\xE7r\x02\u03DB\u03DC" + + "\x05\xE1o\x02\u03DC\u03DD\x05\xD3h\x02\u03DD\u03DE\x05\xCBd\x02\u03DE" + + "\u03DF\x05\xE5q\x02\u03DF\u0440\x03\x02\x02\x02\u03E0\u03E1\x05\xF1w\x02" + + "\u03E1\u03E2\x05\xE7r\x02\u03E2\u03E3\x05o6\x02\u03E3\u03E4\x05\xD1g\x02" + + "\u03E4\u03E5\x05\xCBd\x02\u03E5\u03E6\x05\xF1w\x02\u03E6\u03E7\x05\xD3" + + "h\x02\u03E7\u03E8\x05\xF1w\x02\u03E8\u03E9\x05\xDBl\x02\u03E9\u03EA\x05" + + "\xE3p\x02\u03EA\u03EB\x05\xD3h\x02\u03EB\u0440\x03\x02\x02\x02\u03EC\u03ED" + + "\x05\xF1w\x02\u03ED\u03EE\x05\xE7r\x02\u03EE\u03EF\x05o6\x02\u03EF\u03F0" + + "\x05\xD1g\x02\u03F0\u03F1\x05\xF1w\x02\u03F1\u0440\x03\x02\x02\x02\u03F2" + + "\u03F3\x05\xF1w\x02\u03F3\u03F4\x05\xE7r\x02\u03F4\u03F5\x05o6\x02\u03F5" + + "\u03F6\x05\xD1g\x02\u03F6\u03F7\x05\xCDe\x02\u03F7\u03F8\x05\xE1o\x02" + + "\u03F8\u0440\x03\x02\x02\x02\u03F9\u03FA\x05\xF1w\x02\u03FA\u03FB\x05" + + "\xE7r\x02\u03FB\u03FC\x05o6\x02\u03FC\u03FD\x05\xD1g\x02\u03FD\u03FE\x05" + + "\xE7r\x02\u03FE\u03FF\x05\xF3x\x02\u03FF\u0400\x05\xCDe\x02\u0400\u0401" + + "\x05\xE1o\x02\u0401\u0402\x05\xD3h\x02\u0402\u0440\x03\x02\x02\x02\u0403" + + "\u0404\x05\xF1w\x02\u0404\u0405\x05\xE7r\x02\u0405\u0406\x05o6\x02\u0406" + + "\u0407\x05\xDBl\x02\u0407\u0408\x05\xE5q\x02\u0408\u0409\x05\xF1w\x02" + + "\u0409\u0440\x03\x02\x02\x02\u040A\u040B\x05\xF1w\x02\u040B\u040C\x05" + + "\xE7r\x02\u040C\u040D\x05o6\x02\u040D\u040E\x05\xDBl\x02\u040E\u040F\x05" + + "\xE5q\x02\u040F\u0410\x05\xF1w\x02\u0410\u0411\x05\xD3h\x02\u0411\u0412" + + "\x05\xD7j\x02\u0412\u0413\x05\xD3h\x02\u0413\u0414\x05\xEDu\x02\u0414" + + "\u0440\x03\x02\x02\x02\u0415\u0416\x05\xF1w\x02\u0416\u0417\x05\xE7r\x02" + + "\u0417\u0418\x05o6\x02\u0418\u0419\x05\xE1o\x02\u0419\u041A\x05\xE7r\x02" + + "\u041A\u041B\x05\xE5q\x02\u041B\u041C\x05\xD7j\x02\u041C\u0440\x03\x02" + + "\x02\x02\u041D\u041E\x05\xF1w\x02\u041E\u041F\x05\xE7r\x02\u041F\u0420" + + "\x05o6\x02\u0420\u0421\x05\xDBl\x02\u0421\u0422\x05\xE9s\x02\u0422\u0440" + + "\x03\x02\x02\x02\u0423\u0424\x05\xF1w\x02\u0424\u0425\x05\xE7r\x02\u0425" + + "\u0426\x05o6\x02\u0426\u0427\x05\xF5y\x02\u0427\u0428\x05\xD3h\x02\u0428" + + "\u0429\x05\xEDu\x02\u0429\u042A\x05\xEFv\x02\u042A\u042B\x05\xDBl\x02" + + "\u042B\u042C\x05\xE7r\x02\u042C\u042D\x05\xE5q\x02\u042D\u0440\x03\x02" + + "\x02\x02\u042E\u042F\x05\xF1w\x02\u042F\u0430\x05\xE7r\x02\u0430\u0431" + + "\x05o6\x02\u0431\u0432\x05\xF3x\x02\u0432\u0433\x05\xE5q\x02\u0433\u0434" + + "\x05\xEFv\x02\u0434\u0435\x05\xDBl\x02\u0435\u0436\x05\xD7j\x02\u0436" + + "\u0437\x05\xE5q\x02\u0437\u0438\x05\xD3h\x02\u0438\u0439\x05\xD1g\x02" + + "\u0439\u043A\x05o6\x02\u043A\u043B\x05\xE1o\x02\u043B\u043C\x05\xE7r\x02" + + "\u043C\u043D\x05\xE5q\x02\u043D\u043E\x05\xD7j\x02\u043E\u0440\x03\x02" + + "\x02"; + private static readonly _serializedATNSegment2: string = + "\x02\u043F\u02D5\x03\x02\x02\x02\u043F\u02DB\x03\x02\x02\x02\u043F\u02DF" + + "\x03\x02\x02\x02\u043F\u02E3\x03\x02\x02\x02\u043F\u02E8\x03\x02\x02\x02" + + "\u043F\u02EB\x03\x02\x02\x02\u043F\u02EF\x03\x02\x02\x02\u043F\u02F0\x03" + + "\x02\x02\x02\u043F\u02FA\x03\x02\x02\x02\u043F\u02FF\x03\x02\x02\x02\u043F" + + "\u0306\x03\x02\x02\x02\u043F\u0312\x03\x02\x02\x02\u043F\u031E\x03\x02" + + "\x02\x02\u043F\u0329\x03\x02\x02\x02\u043F\u0334\x03\x02\x02\x02\u043F" + + "\u0340\x03\x02\x02\x02\u043F\u034A\x03\x02\x02\x02\u043F\u0356\x03\x02" + + "\x02\x02\u043F\u035B\x03\x02\x02\x02\u043F\u0362\x03\x02\x02\x02\u043F" + + "\u0369\x03\x02\x02\x02\u043F\u0370\x03\x02\x02\x02\u043F\u0377\x03\x02" + + "\x02\x02\u043F\u037E\x03\x02\x02\x02\u043F\u0387\x03\x02\x02\x02\u043F" + + "\u0391\x03\x02\x02\x02\u043F\u0399\x03\x02\x02\x02\u043F\u03A3\x03\x02" + + "\x02\x02\u043F\u03AD\x03\x02\x02\x02\u043F\u03B6\x03\x02\x02\x02\u043F" + + "\u03BC\x03\x02\x02\x02\u043F\u03C6\x03\x02\x02\x02\u043F\u03CD\x03\x02" + + "\x02\x02\u043F\u03D5\x03\x02\x02\x02\u043F\u03E0\x03\x02\x02\x02\u043F" + + "\u03EC\x03\x02\x02\x02\u043F\u03F2\x03\x02\x02\x02\u043F\u03F9\x03\x02" + + "\x02\x02\u043F\u0403\x03\x02\x02\x02\u043F\u040A\x03\x02\x02\x02\u043F" + + "\u0415\x03\x02\x02\x02\u043F\u041D\x03\x02\x02\x02\u043F\u0423\x03\x02" + + "\x02\x02\u043F\u042E\x03\x02\x02\x02\u0440\x8C\x03\x02\x02\x02\u0441\u0442" + + "\x05\xCBd\x02\u0442\u0443\x05\xF5y\x02\u0443\u0444\x05\xD7j\x02\u0444" + + "\u0493\x03\x02\x02\x02\u0445\u0446\x05\xE3p\x02\u0446\u0447\x05\xDBl\x02" + + "\u0447\u0448\x05\xE5q\x02\u0448\u0493\x03\x02\x02\x02\u0449\u044A\x05" + + "\xE3p\x02\u044A\u044B\x05\xCBd\x02\u044B\u044C\x05\xF9{\x02\u044C\u0493" + + "\x03\x02\x02\x02\u044D\u044E\x05\xEFv\x02\u044E\u044F\x05\xF3x\x02\u044F" + + "\u0450\x05\xE3p\x02\u0450\u0493\x03\x02\x02\x02\u0451\u0452\x05\xCFf\x02" + + "\u0452\u0453\x05\xE7r\x02\u0453\u0454\x05\xF3x\x02\u0454\u0455\x05\xE5" + + "q\x02\u0455\u0456\x05\xF1w\x02\u0456\u0493\x03\x02\x02\x02\u0457\u0458" + + "\x05\xCFf\x02\u0458\u0459\x05\xE7r\x02\u0459\u045A\x05\xF3x\x02\u045A" + + "\u045B\x05\xE5q\x02\u045B\u045C\x05\xF1w\x02\u045C\u045D\x05o6\x02\u045D" + + "\u045E\x05\xD1g\x02\u045E\u045F\x05\xDBl\x02\u045F\u0460\x05\xEFv\x02" + + "\u0460\u0461\x05\xF1w\x02\u0461\u0462\x05\xDBl\x02\u0462\u0463\x05\xE5" + + "q\x02\u0463\u0464\x05\xCFf\x02\u0464\u0465\x05\xF1w\x02\u0465\u0493\x03" + + "\x02\x02\x02\u0466\u0467\x05\xE9s\x02\u0467\u0468\x05\xD3h\x02\u0468\u0469" + + "\x05\xEDu\x02\u0469\u046A\x05\xCFf\x02\u046A\u046B\x05\xD3h\x02\u046B" + + "\u046C\x05\xE5q\x02\u046C\u046D\x05\xF1w\x02\u046D\u046E\x05\xDBl\x02" + + "\u046E\u046F\x05\xE1o\x02\u046F\u0470\x05\xD3h\x02\u0470\u0493\x03\x02" + + "\x02\x02\u0471\u0472\x05\xE3p\x02\u0472\u0473\x05\xD3h\x02\u0473\u0474" + + "\x05\xD1g\x02\u0474\u0475\x05\xDBl\x02\u0475\u0476\x05\xCBd\x02\u0476" + + "\u0477\x05\xE5q\x02\u0477\u0493\x03\x02\x02\x02\u0478\u0479\x05\xE3p\x02" + + "\u0479\u047A\x05\xD3h\x02\u047A\u047B\x05\xD1g\x02\u047B\u047C\x05\xDB" + + "l\x02\u047C\u047D\x05\xCBd\x02\u047D\u047E\x05\xE5q\x02\u047E\u047F\x05" + + "o6\x02\u047F\u0480\x05\xCBd\x02\u0480\u0481\x05\xCDe\x02\u0481\u0482\x05" + + "\xEFv\x02\u0482\u0483\x05\xE7r\x02\u0483\u0484\x05\xE1o\x02\u0484\u0485" + + "\x05\xF3x\x02\u0485\u0486\x05\xF1w\x02\u0486\u0487\x05\xD3h\x02\u0487" + + "\u0488\x05o6\x02\u0488\u0489\x05\xD1g\x02\u0489\u048A\x05\xD3h\x02\u048A" + + "\u048B\x05\xF5y\x02\u048B\u048C\x05\xDBl\x02\u048C\u048D\x05\xCBd\x02" + + "\u048D\u048E\x05\xF1w\x02\u048E\u048F\x05\xDBl\x02\u048F\u0490\x05\xE7" + + "r\x02\u0490\u0491\x05\xE5q\x02\u0491\u0493\x03\x02\x02\x02\u0492\u0441" + + "\x03\x02\x02\x02\u0492\u0445\x03\x02\x02\x02\u0492\u0449\x03\x02\x02\x02" + + "\u0492\u044D\x03\x02\x02\x02\u0492\u0451\x03\x02\x02\x02\u0492\u0457\x03" + + "\x02\x02\x02\u0492\u0466\x03\x02\x02\x02\u0492\u0471\x03\x02\x02\x02\u0492" + + "\u0478\x03\x02\x02\x02\u0493\x8E\x03\x02\x02\x02\u0494\u0495\x05\xCFf" + + "\x02\u0495\u0496\x05\xDBl\x02\u0496\u0497\x05\xD1g\x02\u0497\u0498\x05" + + "\xEDu\x02\u0498\u0499\x05o6\x02\u0499\u049A\x05\xE3p\x02\u049A\u049B\x05" + + "\xCBd\x02\u049B\u049C\x05\xF1w\x02\u049C\u049D\x05\xCFf\x02\u049D\u049E" + + "\x05\xD9k\x02\u049E\x90\x03\x02\x02\x02\u049F\u04A6\x05=\x1D\x02\u04A0" + + "\u04A5\x05=\x1D\x02\u04A1\u04A5\x05;\x1C\x02\u04A2\u04A5\x07a\x02\x02" + + "\u04A3\u04A5\x05}=\x02\u04A4\u04A0\x03\x02\x02\x02\u04A4\u04A1\x03\x02" + + "\x02\x02\u04A4\u04A2\x03\x02\x02\x02\u04A4\u04A3\x03\x02\x02\x02\u04A5" + + "\u04A8\x03\x02\x02\x02\u04A6\u04A4\x03\x02\x02\x02\u04A6\u04A7\x03\x02" + + "\x02\x02\u04A7\u04B3\x03\x02\x02\x02\u04A8\u04A6\x03\x02\x02\x02\u04A9" + + "\u04AE\t\n\x02\x02\u04AA\u04AF\x05=\x1D\x02\u04AB\u04AF\x05;\x1C\x02\u04AC" + + "\u04AF\x07a\x02\x02\u04AD\u04AF\x05}=\x02\u04AE\u04AA\x03\x02\x02\x02" + + "\u04AE\u04AB\x03\x02\x02\x02\u04AE\u04AC\x03\x02\x02\x02\u04AE\u04AD\x03" + + "\x02\x02\x02\u04AF\u04B0\x03\x02\x02\x02\u04B0\u04AE\x03\x02\x02\x02\u04B0" + + "\u04B1\x03\x02\x02\x02\u04B1\u04B3\x03\x02\x02\x02\u04B2\u049F\x03\x02" + + "\x02\x02\u04B2\u04A9\x03\x02\x02\x02\u04B3\x92\x03\x02\x02\x02\u04B4\u04BA" + + "\x07b\x02\x02\u04B5\u04B9\n\v\x02\x02\u04B6\u04B7\x07b\x02\x02\u04B7\u04B9" + + "\x07b\x02\x02\u04B8\u04B5\x03\x02\x02\x02\u04B8\u04B6\x03\x02\x02\x02" + + "\u04B9\u04BC\x03\x02\x02\x02\u04BA\u04B8\x03\x02\x02\x02\u04BA\u04BB\x03" + + "\x02\x02\x02\u04BB\u04BD\x03\x02\x02\x02\u04BC\u04BA\x03\x02\x02\x02\u04BD" + + "\u04BE\x07b\x02\x02\u04BE\x94\x03\x02\x02\x02\u04BF\u04C0\x05)\x13\x02" + + "\u04C0\u04C1\x03\x02\x02\x02\u04C1\u04C2\bI\x06\x02\u04C2\x96\x03\x02" + + "\x02\x02\u04C3\u04C4\x05+\x14\x02\u04C4\u04C5\x03\x02\x02\x02\u04C5\u04C6" + + "\bJ\x06\x02\u04C6\x98\x03\x02\x02\x02\u04C7\u04C8\x05-\x15\x02\u04C8\u04C9" + + "\x03\x02\x02\x02\u04C9\u04CA\bK\x06\x02\u04CA\x9A\x03\x02\x02\x02\u04CB" + + "\u04CC\x07~\x02\x02\u04CC\u04CD\x03\x02\x02\x02\u04CD\u04CE\bL\t\x02\u04CE" + + "\u04CF\bL\n\x02\u04CF\x9C\x03\x02\x02\x02\u04D0\u04D1\x07]\x02\x02\u04D1" + + "\u04D2\x03\x02\x02\x02\u04D2\u04D3\bM\x07\x02\u04D3\u04D4\bM\x04\x02\u04D4" + + "\u04D5\bM\x04\x02\u04D5\x9E\x03\x02\x02\x02\u04D6\u04D7\x07_\x02\x02\u04D7" + + "\u04D8\x03\x02\x02\x02\u04D8\u04D9\bN\n\x02\u04D9\u04DA\bN\n\x02\u04DA" + + "\u04DB\bN\v\x02\u04DB\xA0\x03\x02\x02\x02\u04DC\u04DD\x07.\x02\x02\u04DD" + + "\u04DE\x03\x02\x02\x02\u04DE\u04DF\bO\f\x02\u04DF\xA2\x03\x02\x02\x02" + + "\u04E0\u04E1\x07?\x02\x02\u04E1\u04E2\x03\x02\x02\x02\u04E2\u04E3\bP\r" + + "\x02\u04E3\xA4\x03\x02\x02\x02\u04E4\u04E5\x05\xE3p\x02\u04E5\u04E6\x05" + + "\xD3h\x02\u04E6\u04E7\x05\xF1w\x02\u04E7\u04E8\x05\xCBd\x02\u04E8\u04E9" + + "\x05\xD1g\x02\u04E9\u04EA\x05\xCBd\x02\u04EA\u04EB\x05\xF1w\x02\u04EB" + + "\u04EC\x05\xCBd\x02\u04EC\xA6\x03\x02\x02\x02\u04ED\u04EF\x05\xA9S\x02" + + "\u04EE\u04ED\x03\x02\x02\x02\u04EF\u04F0\x03\x02\x02\x02\u04F0\u04EE\x03" + + "\x02\x02\x02\u04F0\u04F1\x03\x02\x02\x02\u04F1\xA8\x03\x02\x02\x02\u04F2" + + "\u04F4\n\f\x02\x02\u04F3\u04F2\x03\x02\x02\x02\u04F4\u04F5\x03\x02\x02" + + "\x02\u04F5\u04F3\x03\x02\x02\x02\u04F5\u04F6\x03\x02\x02\x02\u04F6\u04FA" + + "\x03\x02\x02\x02\u04F7\u04F8\x071\x02\x02\u04F8\u04FA\n\r\x02\x02\u04F9" + + "\u04F3\x03\x02\x02\x02\u04F9\u04F7\x03\x02\x02\x02\u04FA\xAA\x03\x02\x02" + + "\x02\u04FB\u04FC\x05\x93H\x02\u04FC\xAC\x03\x02\x02\x02\u04FD\u04FE\x05" + + ")\x13\x02\u04FE\u04FF\x03\x02\x02\x02\u04FF\u0500\bU\x06\x02\u0500\xAE" + + "\x03\x02\x02\x02\u0501\u0502\x05+\x14\x02\u0502\u0503\x03\x02\x02\x02" + + "\u0503\u0504\bV\x06\x02\u0504\xB0\x03\x02\x02\x02\u0505\u0506\x05-\x15" + + "\x02\u0506\u0507\x03\x02\x02\x02\u0507\u0508\bW\x06\x02\u0508\xB2\x03" + + "\x02\x02\x02\u0509\u050A\x05\xE7r\x02\u050A\u050B\x05\xE5q\x02\u050B\xB4" + + "\x03\x02\x02\x02\u050C\u050D\x05\xF7z\x02\u050D\u050E\x05\xDBl\x02\u050E" + + "\u050F\x05\xF1w\x02\u050F\u0510\x05\xD9k\x02\u0510\xB6\x03\x02\x02\x02" + + "\u0511\u0512\x07~\x02\x02\u0512\u0513\x03\x02\x02\x02\u0513\u0514\bZ\t" + + "\x02\u0514\u0515\bZ\n\x02\u0515\xB8\x03\x02\x02\x02\u0516\u0517\x07_\x02" + + "\x02\u0517\u0518\x03\x02\x02\x02\u0518\u0519\b[\n\x02\u0519\u051A\b[\n" + + "\x02\u051A\u051B\b[\v\x02\u051B\xBA\x03\x02\x02\x02\u051C\u051D\x07.\x02" + + "\x02\u051D\u051E\x03\x02\x02\x02\u051E\u051F\b\\\f\x02\u051F\xBC\x03\x02" + + "\x02\x02\u0520\u0521\x07?\x02\x02\u0521\u0522\x03\x02\x02\x02\u0522\u0523" + + "\b]\r\x02\u0523\xBE\x03\x02\x02\x02\u0524\u0526\x05\xC1_\x02\u0525\u0524" + + "\x03\x02\x02\x02\u0526\u0527\x03\x02\x02\x02\u0527\u0525\x03\x02\x02\x02" + + "\u0527\u0528\x03\x02\x02\x02\u0528\xC0\x03\x02\x02\x02\u0529\u052B\n\f" + + "\x02\x02\u052A\u0529\x03\x02\x02\x02\u052B\u052C\x03\x02\x02\x02\u052C" + + "\u052A\x03\x02\x02\x02\u052C\u052D\x03\x02\x02\x02\u052D\u0531\x03\x02" + + "\x02\x02\u052E\u052F\x071\x02\x02\u052F\u0531\n\r\x02\x02\u0530\u052A" + + "\x03\x02\x02\x02\u0530\u052E\x03\x02\x02\x02\u0531\xC2\x03\x02\x02\x02" + + "\u0532\u0533\x05\x93H\x02\u0533\xC4\x03\x02\x02\x02\u0534\u0535\x05)\x13" + + "\x02\u0535\u0536\x03\x02\x02\x02\u0536\u0537\ba\x06\x02\u0537\xC6\x03" + + "\x02\x02\x02\u0538\u0539\x05+\x14\x02\u0539\u053A\x03\x02\x02\x02\u053A" + + "\u053B\bb\x06\x02\u053B\xC8\x03\x02\x02\x02\u053C\u053D\x05-\x15\x02\u053D" + + "\u053E\x03\x02\x02\x02\u053E\u053F\bc\x06\x02\u053F\xCA\x03\x02\x02\x02" + + "\u0540\u0541\t\x0E\x02\x02\u0541\xCC\x03\x02\x02\x02\u0542\u0543\t\x0F" + + "\x02\x02\u0543\xCE\x03\x02\x02\x02\u0544\u0545\t\x10\x02\x02\u0545\xD0" + + "\x03\x02\x02\x02\u0546\u0547\t\x11\x02\x02\u0547\xD2\x03\x02\x02\x02\u0548" + + "\u0549\t\b\x02\x02\u0549\xD4\x03\x02\x02\x02\u054A\u054B\t\x12\x02\x02" + + "\u054B\xD6\x03\x02\x02\x02\u054C\u054D\t\x13\x02\x02\u054D\xD8\x03\x02" + + "\x02\x02\u054E\u054F\t\x14\x02\x02\u054F\xDA\x03\x02\x02\x02\u0550\u0551" + + "\t\x15\x02\x02\u0551\xDC\x03\x02\x02\x02\u0552\u0553\t\x16\x02\x02\u0553" + + "\xDE\x03\x02\x02\x02\u0554\u0555\t\x17\x02\x02\u0555\xE0\x03\x02\x02\x02" + + "\u0556\u0557\t\x18\x02\x02\u0557\xE2\x03\x02\x02\x02\u0558\u0559\t\x19" + + "\x02\x02\u0559\xE4\x03\x02\x02\x02\u055A\u055B\t\x1A\x02\x02\u055B\xE6" + + "\x03\x02\x02\x02\u055C\u055D\t\x1B\x02\x02\u055D\xE8\x03\x02\x02\x02\u055E" + + "\u055F\t\x1C\x02\x02\u055F\xEA\x03\x02\x02\x02\u0560\u0561\t\x1D\x02\x02" + + "\u0561\xEC\x03\x02\x02\x02\u0562\u0563\t\x1E\x02\x02\u0563\xEE\x03\x02" + + "\x02\x02\u0564\u0565\t\x1F\x02\x02\u0565\xF0\x03\x02\x02\x02\u0566\u0567" + + "\t \x02\x02\u0567\xF2\x03\x02\x02\x02\u0568\u0569\t!\x02\x02\u0569\xF4" + + "\x03\x02\x02\x02\u056A\u056B\t\"\x02\x02\u056B\xF6\x03\x02\x02\x02\u056C" + + "\u056D\t#\x02\x02\u056D\xF8\x03\x02\x02\x02\u056E\u056F\t$\x02\x02\u056F" + + "\xFA\x03\x02\x02\x02\u0570\u0571\t%\x02\x02\u0571\xFC\x03\x02\x02\x02" + + "\u0572\u0573\t&\x02\x02\u0573\xFE\x03\x02\x02\x022\x02\x03\x04\x05\x06" + + "\u0190\u0194\u0197\u01A0\u01A2\u01AD\u01D6\u01DB\u01E0\u01E2\u01ED\u01F5" + + "\u01F8\u01FA\u01FF\u0204\u020A\u0211\u0216\u021C\u021F\u0227\u022B\u024C" + + "\u02A0\u02AC\u02C2\u02D3\u043F\u0492\u04A4\u04A6\u04AE\u04B0\u04B2\u04B8" + + "\u04BA\u04F0\u04F5\u04F9\u0527\u052C\u0530\x0E\x07\x04\x02\x07\x03\x02" + + "\x07\x05\x02\x07\x06\x02\x02\x03\x02\t%\x02\x07\x02\x02\t\x1A\x02\x06" + + "\x02\x02\t&\x02\t\"\x02\t!\x02"; + public static readonly _serializedATN: string = Utils.join( + [ + esql_lexer._serializedATNSegment0, + esql_lexer._serializedATNSegment1, + esql_lexer._serializedATNSegment2, + ], + "", + ); public static __ATN: ATN; public static get _ATN(): ATN { if (!esql_lexer.__ATN) { diff --git a/packages/kbn-monaco/src/esql/antlr/esql_parser.g4 b/packages/kbn-monaco/src/esql/antlr/esql_parser.g4 index 6196874af91bd..b062dc4f140e7 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_parser.g4 +++ b/packages/kbn-monaco/src/esql/antlr/esql_parser.g4 @@ -23,19 +23,50 @@ sourceCommand : explainCommand | fromCommand | rowCommand + | showCommand ; processingCommand : evalCommand | limitCommand | projectCommand + | keepCommand + | renameCommand + | dropCommand + | dissectCommand + | grokCommand | sortCommand | statsCommand | whereCommand + | mvExpandCommand + | enrichCommand + ; + +enrichCommand + : ENRICH policyName=enrichIdentifier (ON matchField=enrichFieldIdentifier)? (WITH enrichWithClause (COMMA enrichWithClause)*)? + ; + +enrichWithClause + : (newName=enrichFieldIdentifier ASSIGN)? enrichField=enrichFieldIdentifier + ; + +mvExpandCommand + : MV_EXPAND qualifiedNames ; whereCommand - : WHERE booleanExpression + : WHERE whereBooleanExpression + ; + +whereBooleanExpression + : NOT whereBooleanExpression + | valueExpression + | regexBooleanExpression + | left=whereBooleanExpression operator=AND right=whereBooleanExpression + | left=whereBooleanExpression operator=OR right=whereBooleanExpression + | valueExpression (NOT)? IN LP valueExpression (COMMA valueExpression)* RP + | (NOT)? WHERE_FUNCTIONS LP qualifiedName ((COMMA functionExpressionArgument)*)? RP + | valueExpression IS NOT? NULL ; booleanExpression @@ -45,6 +76,11 @@ booleanExpression | left=booleanExpression operator=OR right=booleanExpression ; +regexBooleanExpression + : valueExpression (NOT)? kind=LIKE pattern=string + | valueExpression (NOT)? kind=RLIKE pattern=string + ; + valueExpression : operatorExpression | comparison @@ -58,9 +94,14 @@ mathFn : functionIdentifier LP (functionExpressionArgument (COMMA functionExpressionArgument)*)? RP ; +mathEvalFn + : mathFunctionIdentifier LP (mathFunctionExpressionArgument (COMMA mathFunctionExpressionArgument)*)? RP + ; + operatorExpression : primaryExpression | mathFn + | mathEvalFn | operator=(MINUS | PLUS) operatorExpression | left=operatorExpression operator=(ASTERISK | SLASH | PERCENT) right=operatorExpression | left=operatorExpression operator=(PLUS | MINUS) right=operatorExpression @@ -86,12 +127,21 @@ field | userVariable ASSIGN booleanExpression ; +enrichFieldIdentifier + : ENR_UNQUOTED_IDENTIFIER + | ENR_QUOTED_IDENTIFIER + ; + userVariable : identifier ; fromCommand - : FROM sourceIdentifier (COMMA sourceIdentifier)* + : FROM sourceIdentifier (COMMA sourceIdentifier)* metadata? + ; + +metadata + : OPENING_BRACKET METADATA sourceIdentifier (COMMA sourceIdentifier)* CLOSING_BRACKET ; evalCommand @@ -99,7 +149,7 @@ evalCommand ; statsCommand - : STATS fields (BY qualifiedNames)? + : STATS fields? (BY qualifiedNames)? ; sourceIdentifier @@ -107,9 +157,24 @@ sourceIdentifier | SRC_QUOTED_IDENTIFIER ; +enrichIdentifier + : ENR_UNQUOTED_IDENTIFIER + | ENR_QUOTED_IDENTIFIER + ; + functionExpressionArgument : qualifiedName | string + | number + ; + +mathFunctionExpressionArgument + : qualifiedName + | string + | number + | operatorExpression + | number (DATE_LITERAL) + | comparison ; qualifiedName @@ -123,6 +188,11 @@ qualifiedNames identifier : UNQUOTED_IDENTIFIER | QUOTED_IDENTIFIER + | ASTERISK + ; + +mathFunctionIdentifier + : MATH_FUNCTION ; functionIdentifier @@ -130,10 +200,18 @@ functionIdentifier ; constant - : NULL #nullLiteral - | number #numericLiteral - | booleanValue #booleanLiteral - | string #stringLiteral + : NULL + | numericValue + | booleanValue + | string + | OPENING_BRACKET numericValue (COMMA numericValue)* CLOSING_BRACKET + | OPENING_BRACKET booleanValue (COMMA booleanValue)* CLOSING_BRACKET + | OPENING_BRACKET string (COMMA string)* CLOSING_BRACKET + ; + +numericValue + : decimalValue + | integerValue ; limitCommand @@ -149,12 +227,44 @@ orderExpression ; projectCommand - : PROJECT projectClause (COMMA projectClause)* + : PROJECT qualifiedNames + ; + +keepCommand + : KEEP qualifiedNames + ; + + +dropCommand + : DROP qualifiedNames + ; + +renameVariable + : identifier (DOT identifier)* + ; + +renameCommand + : RENAME renameClause (COMMA renameClause)* + ; + +renameClause + : qualifiedName AS renameVariable ; -projectClause - : sourceIdentifier - | newName=sourceIdentifier ASSIGN oldName=sourceIdentifier +dissectCommand + : DISSECT qualifiedNames string commandOptions? + ; + +grokCommand + : GROK qualifiedNames string + ; + +commandOptions + : commandOption (COMMA commandOption)* + ; + +commandOption + : identifier ASSIGN constant ; booleanValue @@ -166,6 +276,14 @@ number | INTEGER_LITERAL #integerLiteral ; +decimalValue + : DECIMAL_LITERAL + ; + +integerValue + : INTEGER_LITERAL + ; + string : STRING ; @@ -181,3 +299,8 @@ explainCommand subqueryExpression : OPENING_BRACKET query CLOSING_BRACKET ; + +showCommand + : SHOW INFO + | SHOW FUNCTIONS + ; diff --git a/packages/kbn-monaco/src/esql/antlr/esql_parser.interp b/packages/kbn-monaco/src/esql/antlr/esql_parser.interp index 39dc1a09fb8ba..8c0671e0d0a59 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_parser.interp +++ b/packages/kbn-monaco/src/esql/antlr/esql_parser.interp @@ -1,14 +1,25 @@ token literal names: null -'eval' -'explain' -'from' -'row' -'stats' -'where' -'sort' -'limit' -'project' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null null null null @@ -17,17 +28,26 @@ null null null 'by' +null 'and' null null '.' '(' -'[' +null ']' -'not' -'null' +null +null +null +null +null +null +null 'or' ')' +'_' +'info' +'functions' null null '+' @@ -35,6 +55,7 @@ null '*' '/' '%' +'10' null 'nulls' null @@ -49,9 +70,22 @@ null null null null +null +null +null +null +null +null +null +null +null +null +null token symbolic names: null +DISSECT +GROK EVAL EXPLAIN FROM @@ -59,16 +93,26 @@ ROW STATS WHERE SORT +MV_EXPAND LIMIT PROJECT +DROP +RENAME +SHOW +ENRICH +KEEP LINE_COMMENT MULTILINE_COMMENT WS +EXPLAIN_WS +EXPLAIN_LINE_COMMENT +EXPLAIN_MULTILINE_COMMENT PIPE STRING INTEGER_LITERAL DECIMAL_LITERAL BY +DATE_LITERAL AND ASSIGN COMMA @@ -77,9 +121,17 @@ LP OPENING_BRACKET CLOSING_BRACKET NOT +LIKE +RLIKE +IN +IS +AS NULL OR RP +UNDERSCORE +INFO +FUNCTIONS BOOLEAN_VALUE COMPARISON_OPERATOR PLUS @@ -87,59 +139,94 @@ MINUS ASTERISK SLASH PERCENT +TEN ORDERING NULLS_ORDERING NULLS_ORDERING_DIRECTION +MATH_FUNCTION UNARY_FUNCTION +WHERE_FUNCTIONS UNQUOTED_IDENTIFIER QUOTED_IDENTIFIER EXPR_LINE_COMMENT EXPR_MULTILINE_COMMENT EXPR_WS +METADATA SRC_UNQUOTED_IDENTIFIER SRC_QUOTED_IDENTIFIER SRC_LINE_COMMENT SRC_MULTILINE_COMMENT SRC_WS +ON +WITH +ENR_UNQUOTED_IDENTIFIER +ENR_QUOTED_IDENTIFIER +ENR_LINE_COMMENT +ENR_MULTILINE_COMMENT +ENR_WS +EXPLAIN_PIPE rule names: singleStatement query sourceCommand processingCommand +enrichCommand +enrichWithClause +mvExpandCommand whereCommand +whereBooleanExpression booleanExpression +regexBooleanExpression valueExpression comparison mathFn +mathEvalFn operatorExpression primaryExpression rowCommand fields field +enrichFieldIdentifier userVariable fromCommand +metadata evalCommand statsCommand sourceIdentifier +enrichIdentifier functionExpressionArgument +mathFunctionExpressionArgument qualifiedName qualifiedNames identifier +mathFunctionIdentifier functionIdentifier constant +numericValue limitCommand sortCommand orderExpression projectCommand -projectClause +keepCommand +dropCommand +renameVariable +renameCommand +renameClause +dissectCommand +grokCommand +commandOptions +commandOption booleanValue number +decimalValue +integerValue string comparisonOperator explainCommand subqueryExpression +showCommand atn: -[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 3, 51, 307, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 84, 10, 3, 12, 3, 14, 3, 87, 11, 3, 3, 4, 3, 4, 3, 4, 5, 4, 92, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 100, 10, 5, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 109, 10, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 3, 7, 7, 7, 117, 10, 7, 12, 7, 14, 7, 120, 11, 7, 3, 8, 3, 8, 5, 8, 124, 10, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 7, 10, 135, 10, 10, 12, 10, 14, 10, 138, 11, 10, 5, 10, 140, 10, 10, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 149, 10, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 157, 10, 11, 12, 11, 14, 11, 160, 11, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 7, 12, 173, 10, 12, 12, 12, 14, 12, 176, 11, 12, 5, 12, 178, 10, 12, 3, 12, 3, 12, 5, 12, 182, 10, 12, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 7, 14, 190, 10, 14, 12, 14, 14, 14, 193, 11, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 5, 15, 200, 10, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 7, 17, 208, 10, 17, 12, 17, 14, 17, 211, 11, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 5, 19, 220, 10, 19, 3, 20, 3, 20, 3, 21, 3, 21, 5, 21, 226, 10, 21, 3, 22, 3, 22, 3, 22, 7, 22, 231, 10, 22, 12, 22, 14, 22, 234, 11, 22, 3, 23, 3, 23, 3, 23, 7, 23, 239, 10, 23, 12, 23, 14, 23, 242, 11, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 5, 26, 252, 10, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 7, 28, 261, 10, 28, 12, 28, 14, 28, 264, 11, 28, 3, 29, 3, 29, 5, 29, 268, 10, 29, 3, 29, 3, 29, 5, 29, 272, 10, 29, 3, 30, 3, 30, 3, 30, 3, 30, 7, 30, 278, 10, 30, 12, 30, 14, 30, 281, 11, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 5, 31, 288, 10, 31, 3, 32, 3, 32, 3, 33, 3, 33, 5, 33, 294, 10, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 2, 2, 5, 4, 12, 20, 38, 2, 2, 4, 2, 6, 2, 8, 2, 10, 2, 12, 2, 14, 2, 16, 2, 18, 2, 20, 2, 22, 2, 24, 2, 26, 2, 28, 2, 30, 2, 32, 2, 34, 2, 36, 2, 38, 2, 40, 2, 42, 2, 44, 2, 46, 2, 48, 2, 50, 2, 52, 2, 54, 2, 56, 2, 58, 2, 60, 2, 62, 2, 64, 2, 66, 2, 68, 2, 70, 2, 72, 2, 2, 6, 3, 2, 33, 34, 3, 2, 35, 37, 3, 2, 47, 48, 3, 2, 42, 43, 2, 309, 2, 74, 3, 2, 2, 2, 4, 77, 3, 2, 2, 2, 6, 91, 3, 2, 2, 2, 8, 99, 3, 2, 2, 2, 10, 101, 3, 2, 2, 2, 12, 108, 3, 2, 2, 2, 14, 123, 3, 2, 2, 2, 16, 125, 3, 2, 2, 2, 18, 129, 3, 2, 2, 2, 20, 148, 3, 2, 2, 2, 22, 181, 3, 2, 2, 2, 24, 183, 3, 2, 2, 2, 26, 186, 3, 2, 2, 2, 28, 199, 3, 2, 2, 2, 30, 201, 3, 2, 2, 2, 32, 203, 3, 2, 2, 2, 34, 212, 3, 2, 2, 2, 36, 215, 3, 2, 2, 2, 38, 221, 3, 2, 2, 2, 40, 225, 3, 2, 2, 2, 42, 227, 3, 2, 2, 2, 44, 235, 3, 2, 2, 2, 46, 243, 3, 2, 2, 2, 48, 245, 3, 2, 2, 2, 50, 251, 3, 2, 2, 2, 52, 253, 3, 2, 2, 2, 54, 256, 3, 2, 2, 2, 56, 265, 3, 2, 2, 2, 58, 273, 3, 2, 2, 2, 60, 287, 3, 2, 2, 2, 62, 289, 3, 2, 2, 2, 64, 293, 3, 2, 2, 2, 66, 295, 3, 2, 2, 2, 68, 297, 3, 2, 2, 2, 70, 299, 3, 2, 2, 2, 72, 302, 3, 2, 2, 2, 74, 75, 5, 4, 3, 2, 75, 76, 7, 2, 2, 3, 76, 3, 3, 2, 2, 2, 77, 78, 8, 3, 1, 2, 78, 79, 5, 6, 4, 2, 79, 85, 3, 2, 2, 2, 80, 81, 12, 3, 2, 2, 81, 82, 7, 15, 2, 2, 82, 84, 5, 8, 5, 2, 83, 80, 3, 2, 2, 2, 84, 87, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 5, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 88, 92, 5, 70, 36, 2, 89, 92, 5, 32, 17, 2, 90, 92, 5, 24, 13, 2, 91, 88, 3, 2, 2, 2, 91, 89, 3, 2, 2, 2, 91, 90, 3, 2, 2, 2, 92, 7, 3, 2, 2, 2, 93, 100, 5, 34, 18, 2, 94, 100, 5, 52, 27, 2, 95, 100, 5, 58, 30, 2, 96, 100, 5, 54, 28, 2, 97, 100, 5, 36, 19, 2, 98, 100, 5, 10, 6, 2, 99, 93, 3, 2, 2, 2, 99, 94, 3, 2, 2, 2, 99, 95, 3, 2, 2, 2, 99, 96, 3, 2, 2, 2, 99, 97, 3, 2, 2, 2, 99, 98, 3, 2, 2, 2, 100, 9, 3, 2, 2, 2, 101, 102, 7, 8, 2, 2, 102, 103, 5, 12, 7, 2, 103, 11, 3, 2, 2, 2, 104, 105, 8, 7, 1, 2, 105, 106, 7, 27, 2, 2, 106, 109, 5, 12, 7, 6, 107, 109, 5, 14, 8, 2, 108, 104, 3, 2, 2, 2, 108, 107, 3, 2, 2, 2, 109, 118, 3, 2, 2, 2, 110, 111, 12, 4, 2, 2, 111, 112, 7, 20, 2, 2, 112, 117, 5, 12, 7, 5, 113, 114, 12, 3, 2, 2, 114, 115, 7, 29, 2, 2, 115, 117, 5, 12, 7, 4, 116, 110, 3, 2, 2, 2, 116, 113, 3, 2, 2, 2, 117, 120, 3, 2, 2, 2, 118, 116, 3, 2, 2, 2, 118, 119, 3, 2, 2, 2, 119, 13, 3, 2, 2, 2, 120, 118, 3, 2, 2, 2, 121, 124, 5, 20, 11, 2, 122, 124, 5, 16, 9, 2, 123, 121, 3, 2, 2, 2, 123, 122, 3, 2, 2, 2, 124, 15, 3, 2, 2, 2, 125, 126, 5, 20, 11, 2, 126, 127, 5, 68, 35, 2, 127, 128, 5, 20, 11, 2, 128, 17, 3, 2, 2, 2, 129, 130, 5, 48, 25, 2, 130, 139, 7, 24, 2, 2, 131, 136, 5, 40, 21, 2, 132, 133, 7, 22, 2, 2, 133, 135, 5, 40, 21, 2, 134, 132, 3, 2, 2, 2, 135, 138, 3, 2, 2, 2, 136, 134, 3, 2, 2, 2, 136, 137, 3, 2, 2, 2, 137, 140, 3, 2, 2, 2, 138, 136, 3, 2, 2, 2, 139, 131, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 141, 3, 2, 2, 2, 141, 142, 7, 30, 2, 2, 142, 19, 3, 2, 2, 2, 143, 144, 8, 11, 1, 2, 144, 149, 5, 22, 12, 2, 145, 149, 5, 18, 10, 2, 146, 147, 9, 2, 2, 2, 147, 149, 5, 20, 11, 5, 148, 143, 3, 2, 2, 2, 148, 145, 3, 2, 2, 2, 148, 146, 3, 2, 2, 2, 149, 158, 3, 2, 2, 2, 150, 151, 12, 4, 2, 2, 151, 152, 9, 3, 2, 2, 152, 157, 5, 20, 11, 5, 153, 154, 12, 3, 2, 2, 154, 155, 9, 2, 2, 2, 155, 157, 5, 20, 11, 4, 156, 150, 3, 2, 2, 2, 156, 153, 3, 2, 2, 2, 157, 160, 3, 2, 2, 2, 158, 156, 3, 2, 2, 2, 158, 159, 3, 2, 2, 2, 159, 21, 3, 2, 2, 2, 160, 158, 3, 2, 2, 2, 161, 182, 5, 50, 26, 2, 162, 182, 5, 42, 22, 2, 163, 164, 7, 24, 2, 2, 164, 165, 5, 12, 7, 2, 165, 166, 7, 30, 2, 2, 166, 182, 3, 2, 2, 2, 167, 168, 5, 46, 24, 2, 168, 177, 7, 24, 2, 2, 169, 174, 5, 12, 7, 2, 170, 171, 7, 22, 2, 2, 171, 173, 5, 12, 7, 2, 172, 170, 3, 2, 2, 2, 173, 176, 3, 2, 2, 2, 174, 172, 3, 2, 2, 2, 174, 175, 3, 2, 2, 2, 175, 178, 3, 2, 2, 2, 176, 174, 3, 2, 2, 2, 177, 169, 3, 2, 2, 2, 177, 178, 3, 2, 2, 2, 178, 179, 3, 2, 2, 2, 179, 180, 7, 30, 2, 2, 180, 182, 3, 2, 2, 2, 181, 161, 3, 2, 2, 2, 181, 162, 3, 2, 2, 2, 181, 163, 3, 2, 2, 2, 181, 167, 3, 2, 2, 2, 182, 23, 3, 2, 2, 2, 183, 184, 7, 6, 2, 2, 184, 185, 5, 26, 14, 2, 185, 25, 3, 2, 2, 2, 186, 191, 5, 28, 15, 2, 187, 188, 7, 22, 2, 2, 188, 190, 5, 28, 15, 2, 189, 187, 3, 2, 2, 2, 190, 193, 3, 2, 2, 2, 191, 189, 3, 2, 2, 2, 191, 192, 3, 2, 2, 2, 192, 27, 3, 2, 2, 2, 193, 191, 3, 2, 2, 2, 194, 200, 5, 12, 7, 2, 195, 196, 5, 30, 16, 2, 196, 197, 7, 21, 2, 2, 197, 198, 5, 12, 7, 2, 198, 200, 3, 2, 2, 2, 199, 194, 3, 2, 2, 2, 199, 195, 3, 2, 2, 2, 200, 29, 3, 2, 2, 2, 201, 202, 5, 46, 24, 2, 202, 31, 3, 2, 2, 2, 203, 204, 7, 5, 2, 2, 204, 209, 5, 38, 20, 2, 205, 206, 7, 22, 2, 2, 206, 208, 5, 38, 20, 2, 207, 205, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 209, 210, 3, 2, 2, 2, 210, 33, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 212, 213, 7, 3, 2, 2, 213, 214, 5, 26, 14, 2, 214, 35, 3, 2, 2, 2, 215, 216, 7, 7, 2, 2, 216, 219, 5, 26, 14, 2, 217, 218, 7, 19, 2, 2, 218, 220, 5, 44, 23, 2, 219, 217, 3, 2, 2, 2, 219, 220, 3, 2, 2, 2, 220, 37, 3, 2, 2, 2, 221, 222, 9, 4, 2, 2, 222, 39, 3, 2, 2, 2, 223, 226, 5, 42, 22, 2, 224, 226, 5, 66, 34, 2, 225, 223, 3, 2, 2, 2, 225, 224, 3, 2, 2, 2, 226, 41, 3, 2, 2, 2, 227, 232, 5, 46, 24, 2, 228, 229, 7, 23, 2, 2, 229, 231, 5, 46, 24, 2, 230, 228, 3, 2, 2, 2, 231, 234, 3, 2, 2, 2, 232, 230, 3, 2, 2, 2, 232, 233, 3, 2, 2, 2, 233, 43, 3, 2, 2, 2, 234, 232, 3, 2, 2, 2, 235, 240, 5, 42, 22, 2, 236, 237, 7, 22, 2, 2, 237, 239, 5, 42, 22, 2, 238, 236, 3, 2, 2, 2, 239, 242, 3, 2, 2, 2, 240, 238, 3, 2, 2, 2, 240, 241, 3, 2, 2, 2, 241, 45, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 244, 9, 5, 2, 2, 244, 47, 3, 2, 2, 2, 245, 246, 7, 41, 2, 2, 246, 49, 3, 2, 2, 2, 247, 252, 7, 28, 2, 2, 248, 252, 5, 64, 33, 2, 249, 252, 5, 62, 32, 2, 250, 252, 5, 66, 34, 2, 251, 247, 3, 2, 2, 2, 251, 248, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 251, 250, 3, 2, 2, 2, 252, 51, 3, 2, 2, 2, 253, 254, 7, 10, 2, 2, 254, 255, 7, 17, 2, 2, 255, 53, 3, 2, 2, 2, 256, 257, 7, 9, 2, 2, 257, 262, 5, 56, 29, 2, 258, 259, 7, 22, 2, 2, 259, 261, 5, 56, 29, 2, 260, 258, 3, 2, 2, 2, 261, 264, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 263, 55, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 267, 5, 12, 7, 2, 266, 268, 7, 38, 2, 2, 267, 266, 3, 2, 2, 2, 267, 268, 3, 2, 2, 2, 268, 271, 3, 2, 2, 2, 269, 270, 7, 39, 2, 2, 270, 272, 7, 40, 2, 2, 271, 269, 3, 2, 2, 2, 271, 272, 3, 2, 2, 2, 272, 57, 3, 2, 2, 2, 273, 274, 7, 11, 2, 2, 274, 279, 5, 60, 31, 2, 275, 276, 7, 22, 2, 2, 276, 278, 5, 60, 31, 2, 277, 275, 3, 2, 2, 2, 278, 281, 3, 2, 2, 2, 279, 277, 3, 2, 2, 2, 279, 280, 3, 2, 2, 2, 280, 59, 3, 2, 2, 2, 281, 279, 3, 2, 2, 2, 282, 288, 5, 38, 20, 2, 283, 284, 5, 38, 20, 2, 284, 285, 7, 21, 2, 2, 285, 286, 5, 38, 20, 2, 286, 288, 3, 2, 2, 2, 287, 282, 3, 2, 2, 2, 287, 283, 3, 2, 2, 2, 288, 61, 3, 2, 2, 2, 289, 290, 7, 31, 2, 2, 290, 63, 3, 2, 2, 2, 291, 294, 7, 18, 2, 2, 292, 294, 7, 17, 2, 2, 293, 291, 3, 2, 2, 2, 293, 292, 3, 2, 2, 2, 294, 65, 3, 2, 2, 2, 295, 296, 7, 16, 2, 2, 296, 67, 3, 2, 2, 2, 297, 298, 7, 32, 2, 2, 298, 69, 3, 2, 2, 2, 299, 300, 7, 4, 2, 2, 300, 301, 5, 72, 37, 2, 301, 71, 3, 2, 2, 2, 302, 303, 7, 25, 2, 2, 303, 304, 5, 4, 3, 2, 304, 305, 7, 26, 2, 2, 305, 73, 3, 2, 2, 2, 31, 85, 91, 99, 108, 116, 118, 123, 136, 139, 148, 156, 158, 174, 177, 181, 191, 199, 209, 219, 225, 232, 240, 251, 262, 267, 271, 279, 287, 293] \ No newline at end of file +[3, 51485, 51898, 1421, 44986, 20307, 1543, 60043, 49729, 3, 83, 594, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 130, 10, 3, 12, 3, 14, 3, 133, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 139, 10, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 154, 10, 5, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 160, 10, 6, 3, 6, 3, 6, 3, 6, 3, 6, 7, 6, 166, 10, 6, 12, 6, 14, 6, 169, 11, 6, 5, 6, 171, 10, 6, 3, 7, 3, 7, 3, 7, 5, 7, 176, 10, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 5, 10, 193, 10, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 7, 10, 200, 10, 10, 12, 10, 14, 10, 203, 11, 10, 3, 10, 3, 10, 3, 10, 5, 10, 208, 10, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 7, 10, 215, 10, 10, 12, 10, 14, 10, 218, 11, 10, 5, 10, 220, 10, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 5, 10, 227, 10, 10, 3, 10, 3, 10, 5, 10, 231, 10, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 7, 10, 239, 10, 10, 12, 10, 14, 10, 242, 11, 10, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 248, 10, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 256, 10, 11, 12, 11, 14, 11, 259, 11, 11, 3, 12, 3, 12, 5, 12, 263, 10, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 5, 12, 270, 10, 12, 3, 12, 3, 12, 3, 12, 5, 12, 275, 10, 12, 3, 13, 3, 13, 5, 13, 279, 10, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 7, 15, 290, 10, 15, 12, 15, 14, 15, 293, 11, 15, 5, 15, 295, 10, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 7, 16, 304, 10, 16, 12, 16, 14, 16, 307, 11, 16, 5, 16, 309, 10, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 5, 17, 319, 10, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 7, 17, 327, 10, 17, 12, 17, 14, 17, 330, 11, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 343, 10, 18, 12, 18, 14, 18, 346, 11, 18, 5, 18, 348, 10, 18, 3, 18, 3, 18, 5, 18, 352, 10, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 7, 20, 360, 10, 20, 12, 20, 14, 20, 363, 11, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 5, 21, 370, 10, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 24, 7, 24, 380, 10, 24, 12, 24, 14, 24, 383, 11, 24, 3, 24, 5, 24, 386, 10, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 7, 25, 393, 10, 25, 12, 25, 14, 25, 396, 11, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 5, 27, 405, 10, 27, 3, 27, 3, 27, 5, 27, 409, 10, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 5, 30, 418, 10, 30, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 3, 31, 5, 31, 428, 10, 31, 3, 32, 3, 32, 3, 32, 7, 32, 433, 10, 32, 12, 32, 14, 32, 436, 11, 32, 3, 33, 3, 33, 3, 33, 7, 33, 441, 10, 33, 12, 33, 14, 33, 444, 11, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 7, 37, 460, 10, 37, 12, 37, 14, 37, 463, 11, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 7, 37, 471, 10, 37, 12, 37, 14, 37, 474, 11, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 7, 37, 482, 10, 37, 12, 37, 14, 37, 485, 11, 37, 3, 37, 3, 37, 5, 37, 489, 10, 37, 3, 38, 3, 38, 5, 38, 493, 10, 38, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 502, 10, 40, 12, 40, 14, 40, 505, 11, 40, 3, 41, 3, 41, 5, 41, 509, 10, 41, 3, 41, 3, 41, 5, 41, 513, 10, 41, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 7, 45, 527, 10, 45, 12, 45, 14, 45, 530, 11, 45, 3, 46, 3, 46, 3, 46, 3, 46, 7, 46, 536, 10, 46, 12, 46, 14, 46, 539, 11, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 549, 10, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 7, 50, 558, 10, 50, 12, 50, 14, 50, 561, 11, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 5, 53, 571, 10, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 60, 3, 60, 3, 60, 3, 60, 5, 60, 592, 10, 60, 3, 60, 2, 2, 6, 4, 18, 20, 32, 61, 2, 2, 4, 2, 6, 2, 8, 2, 10, 2, 12, 2, 14, 2, 16, 2, 18, 2, 20, 2, 22, 2, 24, 2, 26, 2, 28, 2, 30, 2, 32, 2, 34, 2, 36, 2, 38, 2, 40, 2, 42, 2, 44, 2, 46, 2, 48, 2, 50, 2, 52, 2, 54, 2, 56, 2, 58, 2, 60, 2, 62, 2, 64, 2, 66, 2, 68, 2, 70, 2, 72, 2, 74, 2, 76, 2, 78, 2, 80, 2, 82, 2, 84, 2, 86, 2, 88, 2, 90, 2, 92, 2, 94, 2, 96, 2, 98, 2, 100, 2, 102, 2, 104, 2, 106, 2, 108, 2, 110, 2, 112, 2, 114, 2, 116, 2, 118, 2, 2, 7, 3, 2, 53, 54, 3, 2, 55, 57, 3, 2, 78, 79, 3, 2, 71, 72, 4, 2, 55, 55, 65, 66, 2, 623, 2, 120, 3, 2, 2, 2, 4, 123, 3, 2, 2, 2, 6, 138, 3, 2, 2, 2, 8, 153, 3, 2, 2, 2, 10, 155, 3, 2, 2, 2, 12, 175, 3, 2, 2, 2, 14, 179, 3, 2, 2, 2, 16, 182, 3, 2, 2, 2, 18, 230, 3, 2, 2, 2, 20, 247, 3, 2, 2, 2, 22, 274, 3, 2, 2, 2, 24, 278, 3, 2, 2, 2, 26, 280, 3, 2, 2, 2, 28, 284, 3, 2, 2, 2, 30, 298, 3, 2, 2, 2, 32, 318, 3, 2, 2, 2, 34, 351, 3, 2, 2, 2, 36, 353, 3, 2, 2, 2, 38, 356, 3, 2, 2, 2, 40, 369, 3, 2, 2, 2, 42, 371, 3, 2, 2, 2, 44, 373, 3, 2, 2, 2, 46, 375, 3, 2, 2, 2, 48, 387, 3, 2, 2, 2, 50, 399, 3, 2, 2, 2, 52, 402, 3, 2, 2, 2, 54, 410, 3, 2, 2, 2, 56, 412, 3, 2, 2, 2, 58, 417, 3, 2, 2, 2, 60, 427, 3, 2, 2, 2, 62, 429, 3, 2, 2, 2, 64, 437, 3, 2, 2, 2, 66, 445, 3, 2, 2, 2, 68, 447, 3, 2, 2, 2, 70, 449, 3, 2, 2, 2, 72, 488, 3, 2, 2, 2, 74, 492, 3, 2, 2, 2, 76, 494, 3, 2, 2, 2, 78, 497, 3, 2, 2, 2, 80, 506, 3, 2, 2, 2, 82, 514, 3, 2, 2, 2, 84, 517, 3, 2, 2, 2, 86, 520, 3, 2, 2, 2, 88, 523, 3, 2, 2, 2, 90, 531, 3, 2, 2, 2, 92, 540, 3, 2, 2, 2, 94, 544, 3, 2, 2, 2, 96, 550, 3, 2, 2, 2, 98, 554, 3, 2, 2, 2, 100, 562, 3, 2, 2, 2, 102, 566, 3, 2, 2, 2, 104, 570, 3, 2, 2, 2, 106, 572, 3, 2, 2, 2, 108, 574, 3, 2, 2, 2, 110, 576, 3, 2, 2, 2, 112, 578, 3, 2, 2, 2, 114, 580, 3, 2, 2, 2, 116, 583, 3, 2, 2, 2, 118, 591, 3, 2, 2, 2, 120, 121, 5, 4, 3, 2, 121, 122, 7, 2, 2, 3, 122, 3, 3, 2, 2, 2, 123, 124, 8, 3, 1, 2, 124, 125, 5, 6, 4, 2, 125, 131, 3, 2, 2, 2, 126, 127, 12, 3, 2, 2, 127, 128, 7, 26, 2, 2, 128, 130, 5, 8, 5, 2, 129, 126, 3, 2, 2, 2, 130, 133, 3, 2, 2, 2, 131, 129, 3, 2, 2, 2, 131, 132, 3, 2, 2, 2, 132, 5, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 134, 139, 5, 114, 58, 2, 135, 139, 5, 46, 24, 2, 136, 139, 5, 36, 19, 2, 137, 139, 5, 118, 60, 2, 138, 134, 3, 2, 2, 2, 138, 135, 3, 2, 2, 2, 138, 136, 3, 2, 2, 2, 138, 137, 3, 2, 2, 2, 139, 7, 3, 2, 2, 2, 140, 154, 5, 50, 26, 2, 141, 154, 5, 76, 39, 2, 142, 154, 5, 82, 42, 2, 143, 154, 5, 84, 43, 2, 144, 154, 5, 90, 46, 2, 145, 154, 5, 86, 44, 2, 146, 154, 5, 94, 48, 2, 147, 154, 5, 96, 49, 2, 148, 154, 5, 78, 40, 2, 149, 154, 5, 52, 27, 2, 150, 154, 5, 16, 9, 2, 151, 154, 5, 14, 8, 2, 152, 154, 5, 10, 6, 2, 153, 140, 3, 2, 2, 2, 153, 141, 3, 2, 2, 2, 153, 142, 3, 2, 2, 2, 153, 143, 3, 2, 2, 2, 153, 144, 3, 2, 2, 2, 153, 145, 3, 2, 2, 2, 153, 146, 3, 2, 2, 2, 153, 147, 3, 2, 2, 2, 153, 148, 3, 2, 2, 2, 153, 149, 3, 2, 2, 2, 153, 150, 3, 2, 2, 2, 153, 151, 3, 2, 2, 2, 153, 152, 3, 2, 2, 2, 154, 9, 3, 2, 2, 2, 155, 156, 7, 18, 2, 2, 156, 159, 5, 56, 29, 2, 157, 158, 7, 76, 2, 2, 158, 160, 5, 42, 22, 2, 159, 157, 3, 2, 2, 2, 159, 160, 3, 2, 2, 2, 160, 170, 3, 2, 2, 2, 161, 162, 7, 77, 2, 2, 162, 167, 5, 12, 7, 2, 163, 164, 7, 34, 2, 2, 164, 166, 5, 12, 7, 2, 165, 163, 3, 2, 2, 2, 166, 169, 3, 2, 2, 2, 167, 165, 3, 2, 2, 2, 167, 168, 3, 2, 2, 2, 168, 171, 3, 2, 2, 2, 169, 167, 3, 2, 2, 2, 170, 161, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171, 11, 3, 2, 2, 2, 172, 173, 5, 42, 22, 2, 173, 174, 7, 33, 2, 2, 174, 176, 3, 2, 2, 2, 175, 172, 3, 2, 2, 2, 175, 176, 3, 2, 2, 2, 176, 177, 3, 2, 2, 2, 177, 178, 5, 42, 22, 2, 178, 13, 3, 2, 2, 2, 179, 180, 7, 12, 2, 2, 180, 181, 5, 64, 33, 2, 181, 15, 3, 2, 2, 2, 182, 183, 7, 10, 2, 2, 183, 184, 5, 18, 10, 2, 184, 17, 3, 2, 2, 2, 185, 186, 8, 10, 1, 2, 186, 187, 7, 39, 2, 2, 187, 231, 5, 18, 10, 10, 188, 231, 5, 24, 13, 2, 189, 231, 5, 22, 12, 2, 190, 192, 5, 24, 13, 2, 191, 193, 7, 39, 2, 2, 192, 191, 3, 2, 2, 2, 192, 193, 3, 2, 2, 2, 193, 194, 3, 2, 2, 2, 194, 195, 7, 42, 2, 2, 195, 196, 7, 36, 2, 2, 196, 201, 5, 24, 13, 2, 197, 198, 7, 34, 2, 2, 198, 200, 5, 24, 13, 2, 199, 197, 3, 2, 2, 2, 200, 203, 3, 2, 2, 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 204, 3, 2, 2, 2, 203, 201, 3, 2, 2, 2, 204, 205, 7, 47, 2, 2, 205, 231, 3, 2, 2, 2, 206, 208, 7, 39, 2, 2, 207, 206, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 209, 3, 2, 2, 2, 209, 210, 7, 64, 2, 2, 210, 211, 7, 36, 2, 2, 211, 219, 5, 62, 32, 2, 212, 213, 7, 34, 2, 2, 213, 215, 5, 58, 30, 2, 214, 212, 3, 2, 2, 2, 215, 218, 3, 2, 2, 2, 216, 214, 3, 2, 2, 2, 216, 217, 3, 2, 2, 2, 217, 220, 3, 2, 2, 2, 218, 216, 3, 2, 2, 2, 219, 216, 3, 2, 2, 2, 219, 220, 3, 2, 2, 2, 220, 221, 3, 2, 2, 2, 221, 222, 7, 47, 2, 2, 222, 231, 3, 2, 2, 2, 223, 224, 5, 24, 13, 2, 224, 226, 7, 43, 2, 2, 225, 227, 7, 39, 2, 2, 226, 225, 3, 2, 2, 2, 226, 227, 3, 2, 2, 2, 227, 228, 3, 2, 2, 2, 228, 229, 7, 45, 2, 2, 229, 231, 3, 2, 2, 2, 230, 185, 3, 2, 2, 2, 230, 188, 3, 2, 2, 2, 230, 189, 3, 2, 2, 2, 230, 190, 3, 2, 2, 2, 230, 207, 3, 2, 2, 2, 230, 223, 3, 2, 2, 2, 231, 240, 3, 2, 2, 2, 232, 233, 12, 7, 2, 2, 233, 234, 7, 32, 2, 2, 234, 239, 5, 18, 10, 8, 235, 236, 12, 6, 2, 2, 236, 237, 7, 46, 2, 2, 237, 239, 5, 18, 10, 7, 238, 232, 3, 2, 2, 2, 238, 235, 3, 2, 2, 2, 239, 242, 3, 2, 2, 2, 240, 238, 3, 2, 2, 2, 240, 241, 3, 2, 2, 2, 241, 19, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 244, 8, 11, 1, 2, 244, 245, 7, 39, 2, 2, 245, 248, 5, 20, 11, 6, 246, 248, 5, 24, 13, 2, 247, 243, 3, 2, 2, 2, 247, 246, 3, 2, 2, 2, 248, 257, 3, 2, 2, 2, 249, 250, 12, 4, 2, 2, 250, 251, 7, 32, 2, 2, 251, 256, 5, 20, 11, 5, 252, 253, 12, 3, 2, 2, 253, 254, 7, 46, 2, 2, 254, 256, 5, 20, 11, 4, 255, 249, 3, 2, 2, 2, 255, 252, 3, 2, 2, 2, 256, 259, 3, 2, 2, 2, 257, 255, 3, 2, 2, 2, 257, 258, 3, 2, 2, 2, 258, 21, 3, 2, 2, 2, 259, 257, 3, 2, 2, 2, 260, 262, 5, 24, 13, 2, 261, 263, 7, 39, 2, 2, 262, 261, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 263, 264, 3, 2, 2, 2, 264, 265, 7, 40, 2, 2, 265, 266, 5, 110, 56, 2, 266, 275, 3, 2, 2, 2, 267, 269, 5, 24, 13, 2, 268, 270, 7, 39, 2, 2, 269, 268, 3, 2, 2, 2, 269, 270, 3, 2, 2, 2, 270, 271, 3, 2, 2, 2, 271, 272, 7, 41, 2, 2, 272, 273, 5, 110, 56, 2, 273, 275, 3, 2, 2, 2, 274, 260, 3, 2, 2, 2, 274, 267, 3, 2, 2, 2, 275, 23, 3, 2, 2, 2, 276, 279, 5, 32, 17, 2, 277, 279, 5, 26, 14, 2, 278, 276, 3, 2, 2, 2, 278, 277, 3, 2, 2, 2, 279, 25, 3, 2, 2, 2, 280, 281, 5, 32, 17, 2, 281, 282, 5, 112, 57, 2, 282, 283, 5, 32, 17, 2, 283, 27, 3, 2, 2, 2, 284, 285, 5, 70, 36, 2, 285, 294, 7, 36, 2, 2, 286, 291, 5, 58, 30, 2, 287, 288, 7, 34, 2, 2, 288, 290, 5, 58, 30, 2, 289, 287, 3, 2, 2, 2, 290, 293, 3, 2, 2, 2, 291, 289, 3, 2, 2, 2, 291, 292, 3, 2, 2, 2, 292, 295, 3, 2, 2, 2, 293, 291, 3, 2, 2, 2, 294, 286, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 296, 3, 2, 2, 2, 296, 297, 7, 47, 2, 2, 297, 29, 3, 2, 2, 2, 298, 299, 5, 68, 35, 2, 299, 308, 7, 36, 2, 2, 300, 305, 5, 60, 31, 2, 301, 302, 7, 34, 2, 2, 302, 304, 5, 60, 31, 2, 303, 301, 3, 2, 2, 2, 304, 307, 3, 2, 2, 2, 305, 303, 3, 2, 2, 2, 305, 306, 3, 2, 2, 2, 306, 309, 3, 2, 2, 2, 307, 305, 3, 2, 2, 2, 308, 300, 3, 2, 2, 2, 308, 309, 3, 2, 2, 2, 309, 310, 3, 2, 2, 2, 310, 311, 7, 47, 2, 2, 311, 31, 3, 2, 2, 2, 312, 313, 8, 17, 1, 2, 313, 319, 5, 34, 18, 2, 314, 319, 5, 28, 15, 2, 315, 319, 5, 30, 16, 2, 316, 317, 9, 2, 2, 2, 317, 319, 5, 32, 17, 5, 318, 312, 3, 2, 2, 2, 318, 314, 3, 2, 2, 2, 318, 315, 3, 2, 2, 2, 318, 316, 3, 2, 2, 2, 319, 328, 3, 2, 2, 2, 320, 321, 12, 4, 2, 2, 321, 322, 9, 3, 2, 2, 322, 327, 5, 32, 17, 5, 323, 324, 12, 3, 2, 2, 324, 325, 9, 2, 2, 2, 325, 327, 5, 32, 17, 4, 326, 320, 3, 2, 2, 2, 326, 323, 3, 2, 2, 2, 327, 330, 3, 2, 2, 2, 328, 326, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 33, 3, 2, 2, 2, 330, 328, 3, 2, 2, 2, 331, 352, 5, 72, 37, 2, 332, 352, 5, 62, 32, 2, 333, 334, 7, 36, 2, 2, 334, 335, 5, 20, 11, 2, 335, 336, 7, 47, 2, 2, 336, 352, 3, 2, 2, 2, 337, 338, 5, 66, 34, 2, 338, 347, 7, 36, 2, 2, 339, 344, 5, 20, 11, 2, 340, 341, 7, 34, 2, 2, 341, 343, 5, 20, 11, 2, 342, 340, 3, 2, 2, 2, 343, 346, 3, 2, 2, 2, 344, 342, 3, 2, 2, 2, 344, 345, 3, 2, 2, 2, 345, 348, 3, 2, 2, 2, 346, 344, 3, 2, 2, 2, 347, 339, 3, 2, 2, 2, 347, 348, 3, 2, 2, 2, 348, 349, 3, 2, 2, 2, 349, 350, 7, 47, 2, 2, 350, 352, 3, 2, 2, 2, 351, 331, 3, 2, 2, 2, 351, 332, 3, 2, 2, 2, 351, 333, 3, 2, 2, 2, 351, 337, 3, 2, 2, 2, 352, 35, 3, 2, 2, 2, 353, 354, 7, 8, 2, 2, 354, 355, 5, 38, 20, 2, 355, 37, 3, 2, 2, 2, 356, 361, 5, 40, 21, 2, 357, 358, 7, 34, 2, 2, 358, 360, 5, 40, 21, 2, 359, 357, 3, 2, 2, 2, 360, 363, 3, 2, 2, 2, 361, 359, 3, 2, 2, 2, 361, 362, 3, 2, 2, 2, 362, 39, 3, 2, 2, 2, 363, 361, 3, 2, 2, 2, 364, 370, 5, 20, 11, 2, 365, 366, 5, 44, 23, 2, 366, 367, 7, 33, 2, 2, 367, 368, 5, 20, 11, 2, 368, 370, 3, 2, 2, 2, 369, 364, 3, 2, 2, 2, 369, 365, 3, 2, 2, 2, 370, 41, 3, 2, 2, 2, 371, 372, 9, 4, 2, 2, 372, 43, 3, 2, 2, 2, 373, 374, 5, 66, 34, 2, 374, 45, 3, 2, 2, 2, 375, 376, 7, 7, 2, 2, 376, 381, 5, 54, 28, 2, 377, 378, 7, 34, 2, 2, 378, 380, 5, 54, 28, 2, 379, 377, 3, 2, 2, 2, 380, 383, 3, 2, 2, 2, 381, 379, 3, 2, 2, 2, 381, 382, 3, 2, 2, 2, 382, 385, 3, 2, 2, 2, 383, 381, 3, 2, 2, 2, 384, 386, 5, 48, 25, 2, 385, 384, 3, 2, 2, 2, 385, 386, 3, 2, 2, 2, 386, 47, 3, 2, 2, 2, 387, 388, 7, 37, 2, 2, 388, 389, 7, 70, 2, 2, 389, 394, 5, 54, 28, 2, 390, 391, 7, 34, 2, 2, 391, 393, 5, 54, 28, 2, 392, 390, 3, 2, 2, 2, 393, 396, 3, 2, 2, 2, 394, 392, 3, 2, 2, 2, 394, 395, 3, 2, 2, 2, 395, 397, 3, 2, 2, 2, 396, 394, 3, 2, 2, 2, 397, 398, 7, 38, 2, 2, 398, 49, 3, 2, 2, 2, 399, 400, 7, 5, 2, 2, 400, 401, 5, 38, 20, 2, 401, 51, 3, 2, 2, 2, 402, 404, 7, 9, 2, 2, 403, 405, 5, 38, 20, 2, 404, 403, 3, 2, 2, 2, 404, 405, 3, 2, 2, 2, 405, 408, 3, 2, 2, 2, 406, 407, 7, 30, 2, 2, 407, 409, 5, 64, 33, 2, 408, 406, 3, 2, 2, 2, 408, 409, 3, 2, 2, 2, 409, 53, 3, 2, 2, 2, 410, 411, 9, 5, 2, 2, 411, 55, 3, 2, 2, 2, 412, 413, 9, 4, 2, 2, 413, 57, 3, 2, 2, 2, 414, 418, 5, 62, 32, 2, 415, 418, 5, 110, 56, 2, 416, 418, 5, 104, 53, 2, 417, 414, 3, 2, 2, 2, 417, 415, 3, 2, 2, 2, 417, 416, 3, 2, 2, 2, 418, 59, 3, 2, 2, 2, 419, 428, 5, 62, 32, 2, 420, 428, 5, 110, 56, 2, 421, 428, 5, 104, 53, 2, 422, 428, 5, 32, 17, 2, 423, 424, 5, 104, 53, 2, 424, 425, 7, 31, 2, 2, 425, 428, 3, 2, 2, 2, 426, 428, 5, 26, 14, 2, 427, 419, 3, 2, 2, 2, 427, 420, 3, 2, 2, 2, 427, 421, 3, 2, 2, 2, 427, 422, 3, 2, 2, 2, 427, 423, 3, 2, 2, 2, 427, 426, 3, 2, 2, 2, 428, 61, 3, 2, 2, 2, 429, 434, 5, 66, 34, 2, 430, 431, 7, 35, 2, 2, 431, 433, 5, 66, 34, 2, 432, 430, 3, 2, 2, 2, 433, 436, 3, 2, 2, 2, 434, 432, 3, 2, 2, 2, 434, 435, 3, 2, 2, 2, 435, 63, 3, 2, 2, 2, 436, 434, 3, 2, 2, 2, 437, 442, 5, 62, 32, 2, 438, 439, 7, 34, 2, 2, 439, 441, 5, 62, 32, 2, 440, 438, 3, 2, 2, 2, 441, 444, 3, 2, 2, 2, 442, 440, 3, 2, 2, 2, 442, 443, 3, 2, 2, 2, 443, 65, 3, 2, 2, 2, 444, 442, 3, 2, 2, 2, 445, 446, 9, 6, 2, 2, 446, 67, 3, 2, 2, 2, 447, 448, 7, 62, 2, 2, 448, 69, 3, 2, 2, 2, 449, 450, 7, 63, 2, 2, 450, 71, 3, 2, 2, 2, 451, 489, 7, 45, 2, 2, 452, 489, 5, 74, 38, 2, 453, 489, 5, 102, 52, 2, 454, 489, 5, 110, 56, 2, 455, 456, 7, 37, 2, 2, 456, 461, 5, 74, 38, 2, 457, 458, 7, 34, 2, 2, 458, 460, 5, 74, 38, 2, 459, 457, 3, 2, 2, 2, 460, 463, 3, 2, 2, 2, 461, 459, 3, 2, 2, 2, 461, 462, 3, 2, 2, 2, 462, 464, 3, 2, 2, 2, 463, 461, 3, 2, 2, 2, 464, 465, 7, 38, 2, 2, 465, 489, 3, 2, 2, 2, 466, 467, 7, 37, 2, 2, 467, 472, 5, 102, 52, 2, 468, 469, 7, 34, 2, 2, 469, 471, 5, 102, 52, 2, 470, 468, 3, 2, 2, 2, 471, 474, 3, 2, 2, 2, 472, 470, 3, 2, 2, 2, 472, 473, 3, 2, 2, 2, 473, 475, 3, 2, 2, 2, 474, 472, 3, 2, 2, 2, 475, 476, 7, 38, 2, 2, 476, 489, 3, 2, 2, 2, 477, 478, 7, 37, 2, 2, 478, 483, 5, 110, 56, 2, 479, 480, 7, 34, 2, 2, 480, 482, 5, 110, 56, 2, 481, 479, 3, 2, 2, 2, 482, 485, 3, 2, 2, 2, 483, 481, 3, 2, 2, 2, 483, 484, 3, 2, 2, 2, 484, 486, 3, 2, 2, 2, 485, 483, 3, 2, 2, 2, 486, 487, 7, 38, 2, 2, 487, 489, 3, 2, 2, 2, 488, 451, 3, 2, 2, 2, 488, 452, 3, 2, 2, 2, 488, 453, 3, 2, 2, 2, 488, 454, 3, 2, 2, 2, 488, 455, 3, 2, 2, 2, 488, 466, 3, 2, 2, 2, 488, 477, 3, 2, 2, 2, 489, 73, 3, 2, 2, 2, 490, 493, 5, 106, 54, 2, 491, 493, 5, 108, 55, 2, 492, 490, 3, 2, 2, 2, 492, 491, 3, 2, 2, 2, 493, 75, 3, 2, 2, 2, 494, 495, 7, 13, 2, 2, 495, 496, 7, 28, 2, 2, 496, 77, 3, 2, 2, 2, 497, 498, 7, 11, 2, 2, 498, 503, 5, 80, 41, 2, 499, 500, 7, 34, 2, 2, 500, 502, 5, 80, 41, 2, 501, 499, 3, 2, 2, 2, 502, 505, 3, 2, 2, 2, 503, 501, 3, 2, 2, 2, 503, 504, 3, 2, 2, 2, 504, 79, 3, 2, 2, 2, 505, 503, 3, 2, 2, 2, 506, 508, 5, 20, 11, 2, 507, 509, 7, 59, 2, 2, 508, 507, 3, 2, 2, 2, 508, 509, 3, 2, 2, 2, 509, 512, 3, 2, 2, 2, 510, 511, 7, 60, 2, 2, 511, 513, 7, 61, 2, 2, 512, 510, 3, 2, 2, 2, 512, 513, 3, 2, 2, 2, 513, 81, 3, 2, 2, 2, 514, 515, 7, 14, 2, 2, 515, 516, 5, 64, 33, 2, 516, 83, 3, 2, 2, 2, 517, 518, 7, 19, 2, 2, 518, 519, 5, 64, 33, 2, 519, 85, 3, 2, 2, 2, 520, 521, 7, 15, 2, 2, 521, 522, 5, 64, 33, 2, 522, 87, 3, 2, 2, 2, 523, 528, 5, 66, 34, 2, 524, 525, 7, 35, 2, 2, 525, 527, 5, 66, 34, 2, 526, 524, 3, 2, 2, 2, 527, 530, 3, 2, 2, 2, 528, 526, 3, 2, 2, 2, 528, 529, 3, 2, 2, 2, 529, 89, 3, 2, 2, 2, 530, 528, 3, 2, 2, 2, 531, 532, 7, 16, 2, 2, 532, 537, 5, 92, 47, 2, 533, 534, 7, 34, 2, 2, 534, 536, 5, 92, 47, 2, 535, 533, 3, 2, 2, 2, 536, 539, 3, 2, 2, 2, 537, 535, 3, 2, 2, 2, 537, 538, 3, 2, 2, 2, 538, 91, 3, 2, 2, 2, 539, 537, 3, 2, 2, 2, 540, 541, 5, 62, 32, 2, 541, 542, 7, 44, 2, 2, 542, 543, 5, 88, 45, 2, 543, 93, 3, 2, 2, 2, 544, 545, 7, 3, 2, 2, 545, 546, 5, 64, 33, 2, 546, 548, 5, 110, 56, 2, 547, 549, 5, 98, 50, 2, 548, 547, 3, 2, 2, 2, 548, 549, 3, 2, 2, 2, 549, 95, 3, 2, 2, 2, 550, 551, 7, 4, 2, 2, 551, 552, 5, 64, 33, 2, 552, 553, 5, 110, 56, 2, 553, 97, 3, 2, 2, 2, 554, 559, 5, 100, 51, 2, 555, 556, 7, 34, 2, 2, 556, 558, 5, 100, 51, 2, 557, 555, 3, 2, 2, 2, 558, 561, 3, 2, 2, 2, 559, 557, 3, 2, 2, 2, 559, 560, 3, 2, 2, 2, 560, 99, 3, 2, 2, 2, 561, 559, 3, 2, 2, 2, 562, 563, 5, 66, 34, 2, 563, 564, 7, 33, 2, 2, 564, 565, 5, 72, 37, 2, 565, 101, 3, 2, 2, 2, 566, 567, 7, 51, 2, 2, 567, 103, 3, 2, 2, 2, 568, 571, 7, 29, 2, 2, 569, 571, 7, 28, 2, 2, 570, 568, 3, 2, 2, 2, 570, 569, 3, 2, 2, 2, 571, 105, 3, 2, 2, 2, 572, 573, 7, 29, 2, 2, 573, 107, 3, 2, 2, 2, 574, 575, 7, 28, 2, 2, 575, 109, 3, 2, 2, 2, 576, 577, 7, 27, 2, 2, 577, 111, 3, 2, 2, 2, 578, 579, 7, 52, 2, 2, 579, 113, 3, 2, 2, 2, 580, 581, 7, 6, 2, 2, 581, 582, 5, 116, 59, 2, 582, 115, 3, 2, 2, 2, 583, 584, 7, 37, 2, 2, 584, 585, 5, 4, 3, 2, 585, 586, 7, 38, 2, 2, 586, 117, 3, 2, 2, 2, 587, 588, 7, 17, 2, 2, 588, 592, 7, 49, 2, 2, 589, 590, 7, 17, 2, 2, 590, 592, 7, 50, 2, 2, 591, 587, 3, 2, 2, 2, 591, 589, 3, 2, 2, 2, 592, 119, 3, 2, 2, 2, 60, 131, 138, 153, 159, 167, 170, 175, 192, 201, 207, 216, 219, 226, 230, 238, 240, 247, 255, 257, 262, 269, 274, 278, 291, 294, 305, 308, 318, 326, 328, 344, 347, 351, 361, 369, 381, 385, 394, 404, 408, 417, 427, 434, 442, 461, 472, 483, 488, 492, 503, 508, 512, 528, 537, 548, 559, 570, 591] \ No newline at end of file diff --git a/packages/kbn-monaco/src/esql/antlr/esql_parser.tokens b/packages/kbn-monaco/src/esql/antlr/esql_parser.tokens index c2dafff2f222c..b72e97b9a2961 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_parser.tokens +++ b/packages/kbn-monaco/src/esql/antlr/esql_parser.tokens @@ -1,74 +1,98 @@ -EVAL=1 -EXPLAIN=2 -FROM=3 -ROW=4 -STATS=5 -WHERE=6 -SORT=7 -LIMIT=8 -PROJECT=9 -LINE_COMMENT=10 -MULTILINE_COMMENT=11 -WS=12 -PIPE=13 -STRING=14 -INTEGER_LITERAL=15 -DECIMAL_LITERAL=16 -BY=17 -AND=18 -ASSIGN=19 -COMMA=20 -DOT=21 -LP=22 -OPENING_BRACKET=23 -CLOSING_BRACKET=24 -NOT=25 -NULL=26 -OR=27 -RP=28 -BOOLEAN_VALUE=29 -COMPARISON_OPERATOR=30 -PLUS=31 -MINUS=32 -ASTERISK=33 -SLASH=34 -PERCENT=35 -ORDERING=36 -NULLS_ORDERING=37 -NULLS_ORDERING_DIRECTION=38 -UNARY_FUNCTION=39 -UNQUOTED_IDENTIFIER=40 -QUOTED_IDENTIFIER=41 -EXPR_LINE_COMMENT=42 -EXPR_MULTILINE_COMMENT=43 -EXPR_WS=44 -SRC_UNQUOTED_IDENTIFIER=45 -SRC_QUOTED_IDENTIFIER=46 -SRC_LINE_COMMENT=47 -SRC_MULTILINE_COMMENT=48 -SRC_WS=49 -'eval'=1 -'explain'=2 -'from'=3 -'row'=4 -'stats'=5 -'where'=6 -'sort'=7 -'limit'=8 -'project'=9 -'by'=17 -'and'=18 -'.'=21 -'('=22 -'['=23 -']'=24 -'not'=25 -'null'=26 -'or'=27 -')'=28 -'+'=31 -'-'=32 -'*'=33 -'/'=34 -'%'=35 -'nulls'=37 +DISSECT=1 +GROK=2 +EVAL=3 +EXPLAIN=4 +FROM=5 +ROW=6 +STATS=7 +WHERE=8 +SORT=9 +MV_EXPAND=10 +LIMIT=11 +PROJECT=12 +DROP=13 +RENAME=14 +SHOW=15 +ENRICH=16 +KEEP=17 +LINE_COMMENT=18 +MULTILINE_COMMENT=19 +WS=20 +EXPLAIN_WS=21 +EXPLAIN_LINE_COMMENT=22 +EXPLAIN_MULTILINE_COMMENT=23 +PIPE=24 +STRING=25 +INTEGER_LITERAL=26 +DECIMAL_LITERAL=27 +BY=28 +DATE_LITERAL=29 +AND=30 +ASSIGN=31 +COMMA=32 +DOT=33 +LP=34 +OPENING_BRACKET=35 +CLOSING_BRACKET=36 +NOT=37 +LIKE=38 +RLIKE=39 +IN=40 +IS=41 +AS=42 +NULL=43 +OR=44 +RP=45 +UNDERSCORE=46 +INFO=47 +FUNCTIONS=48 +BOOLEAN_VALUE=49 +COMPARISON_OPERATOR=50 +PLUS=51 +MINUS=52 +ASTERISK=53 +SLASH=54 +PERCENT=55 +TEN=56 +ORDERING=57 +NULLS_ORDERING=58 +NULLS_ORDERING_DIRECTION=59 +MATH_FUNCTION=60 +UNARY_FUNCTION=61 +WHERE_FUNCTIONS=62 +UNQUOTED_IDENTIFIER=63 +QUOTED_IDENTIFIER=64 +EXPR_LINE_COMMENT=65 +EXPR_MULTILINE_COMMENT=66 +EXPR_WS=67 +METADATA=68 +SRC_UNQUOTED_IDENTIFIER=69 +SRC_QUOTED_IDENTIFIER=70 +SRC_LINE_COMMENT=71 +SRC_MULTILINE_COMMENT=72 +SRC_WS=73 +ON=74 +WITH=75 +ENR_UNQUOTED_IDENTIFIER=76 +ENR_QUOTED_IDENTIFIER=77 +ENR_LINE_COMMENT=78 +ENR_MULTILINE_COMMENT=79 +ENR_WS=80 +EXPLAIN_PIPE=81 +'by'=28 +'and'=30 +'.'=33 +'('=34 +']'=36 +'or'=44 +')'=45 +'_'=46 +'info'=47 +'functions'=48 +'+'=51 +'-'=52 +'*'=53 +'/'=54 +'%'=55 +'10'=56 +'nulls'=58 diff --git a/packages/kbn-monaco/src/esql/antlr/esql_parser.ts b/packages/kbn-monaco/src/esql/antlr/esql_parser.ts index de825a0b3698e..e70ad71c58ba1 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_parser.ts +++ b/packages/kbn-monaco/src/esql/antlr/esql_parser.ts @@ -24,123 +24,192 @@ import { VocabularyImpl } from "antlr4ts/VocabularyImpl"; import * as Utils from "antlr4ts/misc/Utils"; -import { esql_parserListener } from "./esql_parser_listener"; +import { esql_parserListener } from "./esql_parserListener"; export class esql_parser extends Parser { - public static readonly EVAL = 1; - public static readonly EXPLAIN = 2; - public static readonly FROM = 3; - public static readonly ROW = 4; - public static readonly STATS = 5; - public static readonly WHERE = 6; - public static readonly SORT = 7; - public static readonly LIMIT = 8; - public static readonly PROJECT = 9; - public static readonly LINE_COMMENT = 10; - public static readonly MULTILINE_COMMENT = 11; - public static readonly WS = 12; - public static readonly PIPE = 13; - public static readonly STRING = 14; - public static readonly INTEGER_LITERAL = 15; - public static readonly DECIMAL_LITERAL = 16; - public static readonly BY = 17; - public static readonly AND = 18; - public static readonly ASSIGN = 19; - public static readonly COMMA = 20; - public static readonly DOT = 21; - public static readonly LP = 22; - public static readonly OPENING_BRACKET = 23; - public static readonly CLOSING_BRACKET = 24; - public static readonly NOT = 25; - public static readonly NULL = 26; - public static readonly OR = 27; - public static readonly RP = 28; - public static readonly BOOLEAN_VALUE = 29; - public static readonly COMPARISON_OPERATOR = 30; - public static readonly PLUS = 31; - public static readonly MINUS = 32; - public static readonly ASTERISK = 33; - public static readonly SLASH = 34; - public static readonly PERCENT = 35; - public static readonly ORDERING = 36; - public static readonly NULLS_ORDERING = 37; - public static readonly NULLS_ORDERING_DIRECTION = 38; - public static readonly UNARY_FUNCTION = 39; - public static readonly UNQUOTED_IDENTIFIER = 40; - public static readonly QUOTED_IDENTIFIER = 41; - public static readonly EXPR_LINE_COMMENT = 42; - public static readonly EXPR_MULTILINE_COMMENT = 43; - public static readonly EXPR_WS = 44; - public static readonly SRC_UNQUOTED_IDENTIFIER = 45; - public static readonly SRC_QUOTED_IDENTIFIER = 46; - public static readonly SRC_LINE_COMMENT = 47; - public static readonly SRC_MULTILINE_COMMENT = 48; - public static readonly SRC_WS = 49; + public static readonly DISSECT = 1; + public static readonly GROK = 2; + public static readonly EVAL = 3; + public static readonly EXPLAIN = 4; + public static readonly FROM = 5; + public static readonly ROW = 6; + public static readonly STATS = 7; + public static readonly WHERE = 8; + public static readonly SORT = 9; + public static readonly MV_EXPAND = 10; + public static readonly LIMIT = 11; + public static readonly PROJECT = 12; + public static readonly DROP = 13; + public static readonly RENAME = 14; + public static readonly SHOW = 15; + public static readonly ENRICH = 16; + public static readonly KEEP = 17; + public static readonly LINE_COMMENT = 18; + public static readonly MULTILINE_COMMENT = 19; + public static readonly WS = 20; + public static readonly EXPLAIN_WS = 21; + public static readonly EXPLAIN_LINE_COMMENT = 22; + public static readonly EXPLAIN_MULTILINE_COMMENT = 23; + public static readonly PIPE = 24; + public static readonly STRING = 25; + public static readonly INTEGER_LITERAL = 26; + public static readonly DECIMAL_LITERAL = 27; + public static readonly BY = 28; + public static readonly DATE_LITERAL = 29; + public static readonly AND = 30; + public static readonly ASSIGN = 31; + public static readonly COMMA = 32; + public static readonly DOT = 33; + public static readonly LP = 34; + public static readonly OPENING_BRACKET = 35; + public static readonly CLOSING_BRACKET = 36; + public static readonly NOT = 37; + public static readonly LIKE = 38; + public static readonly RLIKE = 39; + public static readonly IN = 40; + public static readonly IS = 41; + public static readonly AS = 42; + public static readonly NULL = 43; + public static readonly OR = 44; + public static readonly RP = 45; + public static readonly UNDERSCORE = 46; + public static readonly INFO = 47; + public static readonly FUNCTIONS = 48; + public static readonly BOOLEAN_VALUE = 49; + public static readonly COMPARISON_OPERATOR = 50; + public static readonly PLUS = 51; + public static readonly MINUS = 52; + public static readonly ASTERISK = 53; + public static readonly SLASH = 54; + public static readonly PERCENT = 55; + public static readonly TEN = 56; + public static readonly ORDERING = 57; + public static readonly NULLS_ORDERING = 58; + public static readonly NULLS_ORDERING_DIRECTION = 59; + public static readonly MATH_FUNCTION = 60; + public static readonly UNARY_FUNCTION = 61; + public static readonly WHERE_FUNCTIONS = 62; + public static readonly UNQUOTED_IDENTIFIER = 63; + public static readonly QUOTED_IDENTIFIER = 64; + public static readonly EXPR_LINE_COMMENT = 65; + public static readonly EXPR_MULTILINE_COMMENT = 66; + public static readonly EXPR_WS = 67; + public static readonly METADATA = 68; + public static readonly SRC_UNQUOTED_IDENTIFIER = 69; + public static readonly SRC_QUOTED_IDENTIFIER = 70; + public static readonly SRC_LINE_COMMENT = 71; + public static readonly SRC_MULTILINE_COMMENT = 72; + public static readonly SRC_WS = 73; + public static readonly ON = 74; + public static readonly WITH = 75; + public static readonly ENR_UNQUOTED_IDENTIFIER = 76; + public static readonly ENR_QUOTED_IDENTIFIER = 77; + public static readonly ENR_LINE_COMMENT = 78; + public static readonly ENR_MULTILINE_COMMENT = 79; + public static readonly ENR_WS = 80; + public static readonly EXPLAIN_PIPE = 81; public static readonly RULE_singleStatement = 0; public static readonly RULE_query = 1; public static readonly RULE_sourceCommand = 2; public static readonly RULE_processingCommand = 3; - public static readonly RULE_whereCommand = 4; - public static readonly RULE_booleanExpression = 5; - public static readonly RULE_valueExpression = 6; - public static readonly RULE_comparison = 7; - public static readonly RULE_mathFn = 8; - public static readonly RULE_operatorExpression = 9; - public static readonly RULE_primaryExpression = 10; - public static readonly RULE_rowCommand = 11; - public static readonly RULE_fields = 12; - public static readonly RULE_field = 13; - public static readonly RULE_userVariable = 14; - public static readonly RULE_fromCommand = 15; - public static readonly RULE_evalCommand = 16; - public static readonly RULE_statsCommand = 17; - public static readonly RULE_sourceIdentifier = 18; - public static readonly RULE_functionExpressionArgument = 19; - public static readonly RULE_qualifiedName = 20; - public static readonly RULE_qualifiedNames = 21; - public static readonly RULE_identifier = 22; - public static readonly RULE_functionIdentifier = 23; - public static readonly RULE_constant = 24; - public static readonly RULE_limitCommand = 25; - public static readonly RULE_sortCommand = 26; - public static readonly RULE_orderExpression = 27; - public static readonly RULE_projectCommand = 28; - public static readonly RULE_projectClause = 29; - public static readonly RULE_booleanValue = 30; - public static readonly RULE_number = 31; - public static readonly RULE_string = 32; - public static readonly RULE_comparisonOperator = 33; - public static readonly RULE_explainCommand = 34; - public static readonly RULE_subqueryExpression = 35; + public static readonly RULE_enrichCommand = 4; + public static readonly RULE_enrichWithClause = 5; + public static readonly RULE_mvExpandCommand = 6; + public static readonly RULE_whereCommand = 7; + public static readonly RULE_whereBooleanExpression = 8; + public static readonly RULE_booleanExpression = 9; + public static readonly RULE_regexBooleanExpression = 10; + public static readonly RULE_valueExpression = 11; + public static readonly RULE_comparison = 12; + public static readonly RULE_mathFn = 13; + public static readonly RULE_mathEvalFn = 14; + public static readonly RULE_operatorExpression = 15; + public static readonly RULE_primaryExpression = 16; + public static readonly RULE_rowCommand = 17; + public static readonly RULE_fields = 18; + public static readonly RULE_field = 19; + public static readonly RULE_enrichFieldIdentifier = 20; + public static readonly RULE_userVariable = 21; + public static readonly RULE_fromCommand = 22; + public static readonly RULE_metadata = 23; + public static readonly RULE_evalCommand = 24; + public static readonly RULE_statsCommand = 25; + public static readonly RULE_sourceIdentifier = 26; + public static readonly RULE_enrichIdentifier = 27; + public static readonly RULE_functionExpressionArgument = 28; + public static readonly RULE_mathFunctionExpressionArgument = 29; + public static readonly RULE_qualifiedName = 30; + public static readonly RULE_qualifiedNames = 31; + public static readonly RULE_identifier = 32; + public static readonly RULE_mathFunctionIdentifier = 33; + public static readonly RULE_functionIdentifier = 34; + public static readonly RULE_constant = 35; + public static readonly RULE_numericValue = 36; + public static readonly RULE_limitCommand = 37; + public static readonly RULE_sortCommand = 38; + public static readonly RULE_orderExpression = 39; + public static readonly RULE_projectCommand = 40; + public static readonly RULE_keepCommand = 41; + public static readonly RULE_dropCommand = 42; + public static readonly RULE_renameVariable = 43; + public static readonly RULE_renameCommand = 44; + public static readonly RULE_renameClause = 45; + public static readonly RULE_dissectCommand = 46; + public static readonly RULE_grokCommand = 47; + public static readonly RULE_commandOptions = 48; + public static readonly RULE_commandOption = 49; + public static readonly RULE_booleanValue = 50; + public static readonly RULE_number = 51; + public static readonly RULE_decimalValue = 52; + public static readonly RULE_integerValue = 53; + public static readonly RULE_string = 54; + public static readonly RULE_comparisonOperator = 55; + public static readonly RULE_explainCommand = 56; + public static readonly RULE_subqueryExpression = 57; + public static readonly RULE_showCommand = 58; // tslint:disable:no-trailing-whitespace public static readonly ruleNames: string[] = [ - "singleStatement", "query", "sourceCommand", "processingCommand", "whereCommand", - "booleanExpression", "valueExpression", "comparison", "mathFn", "operatorExpression", - "primaryExpression", "rowCommand", "fields", "field", "userVariable", - "fromCommand", "evalCommand", "statsCommand", "sourceIdentifier", "functionExpressionArgument", - "qualifiedName", "qualifiedNames", "identifier", "functionIdentifier", - "constant", "limitCommand", "sortCommand", "orderExpression", "projectCommand", - "projectClause", "booleanValue", "number", "string", "comparisonOperator", - "explainCommand", "subqueryExpression", + "singleStatement", "query", "sourceCommand", "processingCommand", "enrichCommand", + "enrichWithClause", "mvExpandCommand", "whereCommand", "whereBooleanExpression", + "booleanExpression", "regexBooleanExpression", "valueExpression", "comparison", + "mathFn", "mathEvalFn", "operatorExpression", "primaryExpression", "rowCommand", + "fields", "field", "enrichFieldIdentifier", "userVariable", "fromCommand", + "metadata", "evalCommand", "statsCommand", "sourceIdentifier", "enrichIdentifier", + "functionExpressionArgument", "mathFunctionExpressionArgument", "qualifiedName", + "qualifiedNames", "identifier", "mathFunctionIdentifier", "functionIdentifier", + "constant", "numericValue", "limitCommand", "sortCommand", "orderExpression", + "projectCommand", "keepCommand", "dropCommand", "renameVariable", "renameCommand", + "renameClause", "dissectCommand", "grokCommand", "commandOptions", "commandOption", + "booleanValue", "number", "decimalValue", "integerValue", "string", "comparisonOperator", + "explainCommand", "subqueryExpression", "showCommand", ]; private static readonly _LITERAL_NAMES: Array = [ - undefined, "'eval'", "'explain'", "'from'", "'row'", "'stats'", "'where'", - "'sort'", "'limit'", "'project'", undefined, undefined, undefined, undefined, - undefined, undefined, undefined, "'by'", "'and'", undefined, undefined, - "'.'", "'('", "'['", "']'", "'not'", "'null'", "'or'", "')'", undefined, - undefined, "'+'", "'-'", "'*'", "'/'", "'%'", undefined, "'nulls'", + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + undefined, undefined, undefined, undefined, undefined, undefined, undefined, + "'by'", undefined, "'and'", undefined, undefined, "'.'", "'('", undefined, + "']'", undefined, undefined, undefined, undefined, undefined, undefined, + undefined, "'or'", "')'", "'_'", "'info'", "'functions'", undefined, undefined, + "'+'", "'-'", "'*'", "'/'", "'%'", "'10'", undefined, "'nulls'", ]; private static readonly _SYMBOLIC_NAMES: Array = [ - undefined, "EVAL", "EXPLAIN", "FROM", "ROW", "STATS", "WHERE", "SORT", - "LIMIT", "PROJECT", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", - "STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASSIGN", - "COMMA", "DOT", "LP", "OPENING_BRACKET", "CLOSING_BRACKET", "NOT", "NULL", - "OR", "RP", "BOOLEAN_VALUE", "COMPARISON_OPERATOR", "PLUS", "MINUS", "ASTERISK", - "SLASH", "PERCENT", "ORDERING", "NULLS_ORDERING", "NULLS_ORDERING_DIRECTION", - "UNARY_FUNCTION", "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", - "EXPR_MULTILINE_COMMENT", "EXPR_WS", "SRC_UNQUOTED_IDENTIFIER", "SRC_QUOTED_IDENTIFIER", - "SRC_LINE_COMMENT", "SRC_MULTILINE_COMMENT", "SRC_WS", + undefined, "DISSECT", "GROK", "EVAL", "EXPLAIN", "FROM", "ROW", "STATS", + "WHERE", "SORT", "MV_EXPAND", "LIMIT", "PROJECT", "DROP", "RENAME", "SHOW", + "ENRICH", "KEEP", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "EXPLAIN_WS", + "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "PIPE", "STRING", + "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "DATE_LITERAL", "AND", "ASSIGN", + "COMMA", "DOT", "LP", "OPENING_BRACKET", "CLOSING_BRACKET", "NOT", "LIKE", + "RLIKE", "IN", "IS", "AS", "NULL", "OR", "RP", "UNDERSCORE", "INFO", "FUNCTIONS", + "BOOLEAN_VALUE", "COMPARISON_OPERATOR", "PLUS", "MINUS", "ASTERISK", "SLASH", + "PERCENT", "TEN", "ORDERING", "NULLS_ORDERING", "NULLS_ORDERING_DIRECTION", + "MATH_FUNCTION", "UNARY_FUNCTION", "WHERE_FUNCTIONS", "UNQUOTED_IDENTIFIER", + "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", "EXPR_WS", + "METADATA", "SRC_UNQUOTED_IDENTIFIER", "SRC_QUOTED_IDENTIFIER", "SRC_LINE_COMMENT", + "SRC_MULTILINE_COMMENT", "SRC_WS", "ON", "WITH", "ENR_UNQUOTED_IDENTIFIER", + "ENR_QUOTED_IDENTIFIER", "ENR_LINE_COMMENT", "ENR_MULTILINE_COMMENT", + "ENR_WS", "EXPLAIN_PIPE", ]; public static readonly VOCABULARY: Vocabulary = new VocabularyImpl(esql_parser._LITERAL_NAMES, esql_parser._SYMBOLIC_NAMES, []); @@ -171,9 +240,9 @@ export class esql_parser extends Parser { try { this.enterOuterAlt(_localctx, 1); { - this.state = 72; + this.state = 118; this.query(0); - this.state = 73; + this.state = 119; this.match(esql_parser.EOF); } } @@ -215,11 +284,11 @@ export class esql_parser extends Parser { this._ctx = _localctx; _prevctx = _localctx; - this.state = 76; + this.state = 122; this.sourceCommand(); } this._ctx._stop = this._input.tryLT(-1); - this.state = 83; + this.state = 129; this._errHandler.sync(this); _alt = this.interpreter.adaptivePredict(this._input, 0, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { @@ -232,18 +301,18 @@ export class esql_parser extends Parser { { _localctx = new CompositeQueryContext(new QueryContext(_parentctx, _parentState)); this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_query); - this.state = 78; + this.state = 124; if (!(this.precpred(this._ctx, 1))) { throw new FailedPredicateException(this, "this.precpred(this._ctx, 1)"); } - this.state = 79; + this.state = 125; this.match(esql_parser.PIPE); - this.state = 80; + this.state = 126; this.processingCommand(); } } } - this.state = 85; + this.state = 131; this._errHandler.sync(this); _alt = this.interpreter.adaptivePredict(this._input, 0, this._ctx); } @@ -268,30 +337,37 @@ export class esql_parser extends Parser { let _localctx: SourceCommandContext = new SourceCommandContext(this._ctx, this.state); this.enterRule(_localctx, 4, esql_parser.RULE_sourceCommand); try { - this.state = 89; + this.state = 136; this._errHandler.sync(this); switch (this._input.LA(1)) { case esql_parser.EXPLAIN: this.enterOuterAlt(_localctx, 1); { - this.state = 86; + this.state = 132; this.explainCommand(); } break; case esql_parser.FROM: this.enterOuterAlt(_localctx, 2); { - this.state = 87; + this.state = 133; this.fromCommand(); } break; case esql_parser.ROW: this.enterOuterAlt(_localctx, 3); { - this.state = 88; + this.state = 134; this.rowCommand(); } break; + case esql_parser.SHOW: + this.enterOuterAlt(_localctx, 4); + { + this.state = 135; + this.showCommand(); + } + break; default: throw new NoViableAltException(this); } @@ -315,51 +391,100 @@ export class esql_parser extends Parser { let _localctx: ProcessingCommandContext = new ProcessingCommandContext(this._ctx, this.state); this.enterRule(_localctx, 6, esql_parser.RULE_processingCommand); try { - this.state = 97; + this.state = 151; this._errHandler.sync(this); switch (this._input.LA(1)) { case esql_parser.EVAL: this.enterOuterAlt(_localctx, 1); { - this.state = 91; + this.state = 138; this.evalCommand(); } break; case esql_parser.LIMIT: this.enterOuterAlt(_localctx, 2); { - this.state = 92; + this.state = 139; this.limitCommand(); } break; case esql_parser.PROJECT: this.enterOuterAlt(_localctx, 3); { - this.state = 93; + this.state = 140; this.projectCommand(); } break; - case esql_parser.SORT: + case esql_parser.KEEP: this.enterOuterAlt(_localctx, 4); { - this.state = 94; + this.state = 141; + this.keepCommand(); + } + break; + case esql_parser.RENAME: + this.enterOuterAlt(_localctx, 5); + { + this.state = 142; + this.renameCommand(); + } + break; + case esql_parser.DROP: + this.enterOuterAlt(_localctx, 6); + { + this.state = 143; + this.dropCommand(); + } + break; + case esql_parser.DISSECT: + this.enterOuterAlt(_localctx, 7); + { + this.state = 144; + this.dissectCommand(); + } + break; + case esql_parser.GROK: + this.enterOuterAlt(_localctx, 8); + { + this.state = 145; + this.grokCommand(); + } + break; + case esql_parser.SORT: + this.enterOuterAlt(_localctx, 9); + { + this.state = 146; this.sortCommand(); } break; case esql_parser.STATS: - this.enterOuterAlt(_localctx, 5); + this.enterOuterAlt(_localctx, 10); { - this.state = 95; + this.state = 147; this.statsCommand(); } break; case esql_parser.WHERE: - this.enterOuterAlt(_localctx, 6); + this.enterOuterAlt(_localctx, 11); { - this.state = 96; + this.state = 148; this.whereCommand(); } break; + case esql_parser.MV_EXPAND: + this.enterOuterAlt(_localctx, 12); + { + this.state = 149; + this.mvExpandCommand(); + } + break; + case esql_parser.ENRICH: + this.enterOuterAlt(_localctx, 13); + { + this.state = 150; + this.enrichCommand(); + } + break; default: throw new NoViableAltException(this); } @@ -379,132 +504,58 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public whereCommand(): WhereCommandContext { - let _localctx: WhereCommandContext = new WhereCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 8, esql_parser.RULE_whereCommand); - try { - this.enterOuterAlt(_localctx, 1); - { - this.state = 99; - this.match(esql_parser.WHERE); - this.state = 100; - this.booleanExpression(0); - } - } - catch (re) { - if (re instanceof RecognitionException) { - _localctx.exception = re; - this._errHandler.reportError(this, re); - this._errHandler.recover(this, re); - } else { - throw re; - } - } - finally { - this.exitRule(); - } - return _localctx; - } - - public booleanExpression(): BooleanExpressionContext; - public booleanExpression(_p: number): BooleanExpressionContext; - // @RuleVersion(0) - public booleanExpression(_p?: number): BooleanExpressionContext { - if (_p === undefined) { - _p = 0; - } - - let _parentctx: ParserRuleContext = this._ctx; - let _parentState: number = this.state; - let _localctx: BooleanExpressionContext = new BooleanExpressionContext(this._ctx, _parentState); - let _prevctx: BooleanExpressionContext = _localctx; - let _startState: number = 10; - this.enterRecursionRule(_localctx, 10, esql_parser.RULE_booleanExpression, _p); + public enrichCommand(): EnrichCommandContext { + let _localctx: EnrichCommandContext = new EnrichCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 8, esql_parser.RULE_enrichCommand); try { let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 106; + this.state = 153; + this.match(esql_parser.ENRICH); + this.state = 154; + _localctx._policyName = this.enrichIdentifier(); + this.state = 157; this._errHandler.sync(this); - switch (this._input.LA(1)) { - case esql_parser.NOT: - { - this.state = 103; - this.match(esql_parser.NOT); - this.state = 104; - this.booleanExpression(4); - } - break; - case esql_parser.STRING: - case esql_parser.INTEGER_LITERAL: - case esql_parser.DECIMAL_LITERAL: - case esql_parser.LP: - case esql_parser.NULL: - case esql_parser.BOOLEAN_VALUE: - case esql_parser.PLUS: - case esql_parser.MINUS: - case esql_parser.UNARY_FUNCTION: - case esql_parser.UNQUOTED_IDENTIFIER: - case esql_parser.QUOTED_IDENTIFIER: + switch ( this.interpreter.adaptivePredict(this._input, 3, this._ctx) ) { + case 1: { - this.state = 105; - this.valueExpression(); + this.state = 155; + this.match(esql_parser.ON); + this.state = 156; + _localctx._matchField = this.enrichFieldIdentifier(); } break; - default: - throw new NoViableAltException(this); } - this._ctx._stop = this._input.tryLT(-1); - this.state = 116; + this.state = 168; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 5, this._ctx); - while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { - if (_alt === 1) { - if (this._parseListeners != null) { - this.triggerExitRuleEvent(); - } - _prevctx = _localctx; - { - this.state = 114; - this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 4, this._ctx) ) { - case 1: + switch ( this.interpreter.adaptivePredict(this._input, 5, this._ctx) ) { + case 1: + { + this.state = 159; + this.match(esql_parser.WITH); + this.state = 160; + this.enrichWithClause(); + this.state = 165; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 4, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { { - _localctx = new BooleanExpressionContext(_parentctx, _parentState); - _localctx._left = _prevctx; - this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_booleanExpression); - this.state = 108; - if (!(this.precpred(this._ctx, 2))) { - throw new FailedPredicateException(this, "this.precpred(this._ctx, 2)"); - } - this.state = 109; - _localctx._operator = this.match(esql_parser.AND); - this.state = 110; - _localctx._right = this.booleanExpression(3); - } - break; - - case 2: { - _localctx = new BooleanExpressionContext(_parentctx, _parentState); - _localctx._left = _prevctx; - this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_booleanExpression); - this.state = 111; - if (!(this.precpred(this._ctx, 1))) { - throw new FailedPredicateException(this, "this.precpred(this._ctx, 1)"); + this.state = 161; + this.match(esql_parser.COMMA); + this.state = 162; + this.enrichWithClause(); } - this.state = 112; - _localctx._operator = this.match(esql_parser.OR); - this.state = 113; - _localctx._right = this.booleanExpression(2); } - break; - } } + this.state = 167; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 4, this._ctx); } - this.state = 118; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 5, this._ctx); + } + break; } } } @@ -518,34 +569,32 @@ export class esql_parser extends Parser { } } finally { - this.unrollRecursionContexts(_parentctx); + this.exitRule(); } return _localctx; } // @RuleVersion(0) - public valueExpression(): ValueExpressionContext { - let _localctx: ValueExpressionContext = new ValueExpressionContext(this._ctx, this.state); - this.enterRule(_localctx, 12, esql_parser.RULE_valueExpression); + public enrichWithClause(): EnrichWithClauseContext { + let _localctx: EnrichWithClauseContext = new EnrichWithClauseContext(this._ctx, this.state); + this.enterRule(_localctx, 10, esql_parser.RULE_enrichWithClause); try { - this.state = 121; + this.enterOuterAlt(_localctx, 1); + { + this.state = 173; this._errHandler.sync(this); switch ( this.interpreter.adaptivePredict(this._input, 6, this._ctx) ) { case 1: - this.enterOuterAlt(_localctx, 1); { - this.state = 119; - this.operatorExpression(0); - } - break; - - case 2: - this.enterOuterAlt(_localctx, 2); - { - this.state = 120; - this.comparison(); + this.state = 170; + _localctx._newName = this.enrichFieldIdentifier(); + this.state = 171; + this.match(esql_parser.ASSIGN); } break; } + this.state = 175; + _localctx._enrichField = this.enrichFieldIdentifier(); + } } catch (re) { if (re instanceof RecognitionException) { @@ -562,18 +611,16 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public comparison(): ComparisonContext { - let _localctx: ComparisonContext = new ComparisonContext(this._ctx, this.state); - this.enterRule(_localctx, 14, esql_parser.RULE_comparison); + public mvExpandCommand(): MvExpandCommandContext { + let _localctx: MvExpandCommandContext = new MvExpandCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 12, esql_parser.RULE_mvExpandCommand); try { this.enterOuterAlt(_localctx, 1); { - this.state = 123; - _localctx._left = this.operatorExpression(0); - this.state = 124; - this.comparisonOperator(); - this.state = 125; - _localctx._right = this.operatorExpression(0); + this.state = 177; + this.match(esql_parser.MV_EXPAND); + this.state = 178; + this.qualifiedNames(); } } catch (re) { @@ -591,45 +638,16 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public mathFn(): MathFnContext { - let _localctx: MathFnContext = new MathFnContext(this._ctx, this.state); - this.enterRule(_localctx, 16, esql_parser.RULE_mathFn); - let _la: number; + public whereCommand(): WhereCommandContext { + let _localctx: WhereCommandContext = new WhereCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 14, esql_parser.RULE_whereCommand); try { this.enterOuterAlt(_localctx, 1); { - this.state = 127; - this.functionIdentifier(); - this.state = 128; - this.match(esql_parser.LP); - this.state = 137; - this._errHandler.sync(this); - _la = this._input.LA(1); - if (((((_la - 14)) & ~0x1F) === 0 && ((1 << (_la - 14)) & ((1 << (esql_parser.STRING - 14)) | (1 << (esql_parser.UNQUOTED_IDENTIFIER - 14)) | (1 << (esql_parser.QUOTED_IDENTIFIER - 14)))) !== 0)) { - { - this.state = 129; - this.functionExpressionArgument(); - this.state = 134; - this._errHandler.sync(this); - _la = this._input.LA(1); - while (_la === esql_parser.COMMA) { - { - { - this.state = 130; - this.match(esql_parser.COMMA); - this.state = 131; - this.functionExpressionArgument(); - } - } - this.state = 136; - this._errHandler.sync(this); - _la = this._input.LA(1); - } - } - } - - this.state = 139; - this.match(esql_parser.RP); + this.state = 180; + this.match(esql_parser.WHERE); + this.state = 181; + this.whereBooleanExpression(0); } } catch (re) { @@ -647,74 +665,164 @@ export class esql_parser extends Parser { return _localctx; } - public operatorExpression(): OperatorExpressionContext; - public operatorExpression(_p: number): OperatorExpressionContext; + public whereBooleanExpression(): WhereBooleanExpressionContext; + public whereBooleanExpression(_p: number): WhereBooleanExpressionContext; // @RuleVersion(0) - public operatorExpression(_p?: number): OperatorExpressionContext { + public whereBooleanExpression(_p?: number): WhereBooleanExpressionContext { if (_p === undefined) { _p = 0; } let _parentctx: ParserRuleContext = this._ctx; let _parentState: number = this.state; - let _localctx: OperatorExpressionContext = new OperatorExpressionContext(this._ctx, _parentState); - let _prevctx: OperatorExpressionContext = _localctx; - let _startState: number = 18; - this.enterRecursionRule(_localctx, 18, esql_parser.RULE_operatorExpression, _p); + let _localctx: WhereBooleanExpressionContext = new WhereBooleanExpressionContext(this._ctx, _parentState); + let _prevctx: WhereBooleanExpressionContext = _localctx; + let _startState: number = 16; + this.enterRecursionRule(_localctx, 16, esql_parser.RULE_whereBooleanExpression, _p); let _la: number; try { let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 146; + this.state = 228; this._errHandler.sync(this); - switch (this._input.LA(1)) { - case esql_parser.STRING: - case esql_parser.INTEGER_LITERAL: - case esql_parser.DECIMAL_LITERAL: - case esql_parser.LP: - case esql_parser.NULL: - case esql_parser.BOOLEAN_VALUE: - case esql_parser.UNQUOTED_IDENTIFIER: - case esql_parser.QUOTED_IDENTIFIER: + switch ( this.interpreter.adaptivePredict(this._input, 13, this._ctx) ) { + case 1: { - this.state = 142; - this.primaryExpression(); + this.state = 184; + this.match(esql_parser.NOT); + this.state = 185; + this.whereBooleanExpression(8); } break; - case esql_parser.UNARY_FUNCTION: + + case 2: { - this.state = 143; - this.mathFn(); + this.state = 186; + this.valueExpression(); } break; - case esql_parser.PLUS: - case esql_parser.MINUS: + + case 3: { - this.state = 144; - _localctx._operator = this._input.LT(1); + this.state = 187; + this.regexBooleanExpression(); + } + break; + + case 4: + { + this.state = 188; + this.valueExpression(); + this.state = 190; + this._errHandler.sync(this); _la = this._input.LA(1); - if (!(_la === esql_parser.PLUS || _la === esql_parser.MINUS)) { - _localctx._operator = this._errHandler.recoverInline(this); - } else { - if (this._input.LA(1) === Token.EOF) { - this.matchedEOF = true; + if (_la === esql_parser.NOT) { + { + this.state = 189; + this.match(esql_parser.NOT); } + } - this._errHandler.reportMatch(this); - this.consume(); + this.state = 192; + this.match(esql_parser.IN); + this.state = 193; + this.match(esql_parser.LP); + this.state = 194; + this.valueExpression(); + this.state = 199; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 195; + this.match(esql_parser.COMMA); + this.state = 196; + this.valueExpression(); + } + } + this.state = 201; + this._errHandler.sync(this); + _la = this._input.LA(1); } - this.state = 145; - this.operatorExpression(3); + this.state = 202; + this.match(esql_parser.RP); + } + break; + + case 5: + { + this.state = 205; + this._errHandler.sync(this); + _la = this._input.LA(1); + if (_la === esql_parser.NOT) { + { + this.state = 204; + this.match(esql_parser.NOT); + } + } + + this.state = 207; + this.match(esql_parser.WHERE_FUNCTIONS); + this.state = 208; + this.match(esql_parser.LP); + this.state = 209; + this.qualifiedName(); + this.state = 217; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 11, this._ctx) ) { + case 1: + { + this.state = 214; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 210; + this.match(esql_parser.COMMA); + this.state = 211; + this.functionExpressionArgument(); + } + } + this.state = 216; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + } + break; + } + this.state = 219; + this.match(esql_parser.RP); + } + break; + + case 6: + { + this.state = 221; + this.valueExpression(); + this.state = 222; + this.match(esql_parser.IS); + this.state = 224; + this._errHandler.sync(this); + _la = this._input.LA(1); + if (_la === esql_parser.NOT) { + { + this.state = 223; + this.match(esql_parser.NOT); + } + } + + this.state = 226; + this.match(esql_parser.NULL); } break; - default: - throw new NoViableAltException(this); } this._ctx._stop = this._input.tryLT(-1); - this.state = 156; + this.state = 238; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 11, this._ctx); + _alt = this.interpreter.adaptivePredict(this._input, 15, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { if (this._parseListeners != null) { @@ -722,68 +830,166 @@ export class esql_parser extends Parser { } _prevctx = _localctx; { - this.state = 154; + this.state = 236; this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 10, this._ctx) ) { + switch ( this.interpreter.adaptivePredict(this._input, 14, this._ctx) ) { case 1: { - _localctx = new OperatorExpressionContext(_parentctx, _parentState); + _localctx = new WhereBooleanExpressionContext(_parentctx, _parentState); _localctx._left = _prevctx; - this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_operatorExpression); - this.state = 148; - if (!(this.precpred(this._ctx, 2))) { - throw new FailedPredicateException(this, "this.precpred(this._ctx, 2)"); + this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_whereBooleanExpression); + this.state = 230; + if (!(this.precpred(this._ctx, 5))) { + throw new FailedPredicateException(this, "this.precpred(this._ctx, 5)"); } - this.state = 149; - _localctx._operator = this._input.LT(1); - _la = this._input.LA(1); - if (!(((((_la - 33)) & ~0x1F) === 0 && ((1 << (_la - 33)) & ((1 << (esql_parser.ASTERISK - 33)) | (1 << (esql_parser.SLASH - 33)) | (1 << (esql_parser.PERCENT - 33)))) !== 0))) { - _localctx._operator = this._errHandler.recoverInline(this); - } else { - if (this._input.LA(1) === Token.EOF) { - this.matchedEOF = true; - } + this.state = 231; + _localctx._operator = this.match(esql_parser.AND); + this.state = 232; + _localctx._right = this.whereBooleanExpression(6); + } + break; - this._errHandler.reportMatch(this); - this.consume(); + case 2: + { + _localctx = new WhereBooleanExpressionContext(_parentctx, _parentState); + _localctx._left = _prevctx; + this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_whereBooleanExpression); + this.state = 233; + if (!(this.precpred(this._ctx, 4))) { + throw new FailedPredicateException(this, "this.precpred(this._ctx, 4)"); } - this.state = 150; - _localctx._right = this.operatorExpression(3); + this.state = 234; + _localctx._operator = this.match(esql_parser.OR); + this.state = 235; + _localctx._right = this.whereBooleanExpression(5); + } + break; + } + } + } + this.state = 240; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 15, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.unrollRecursionContexts(_parentctx); + } + return _localctx; + } + + public booleanExpression(): BooleanExpressionContext; + public booleanExpression(_p: number): BooleanExpressionContext; + // @RuleVersion(0) + public booleanExpression(_p?: number): BooleanExpressionContext { + if (_p === undefined) { + _p = 0; + } + + let _parentctx: ParserRuleContext = this._ctx; + let _parentState: number = this.state; + let _localctx: BooleanExpressionContext = new BooleanExpressionContext(this._ctx, _parentState); + let _prevctx: BooleanExpressionContext = _localctx; + let _startState: number = 18; + this.enterRecursionRule(_localctx, 18, esql_parser.RULE_booleanExpression, _p); + try { + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 245; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case esql_parser.NOT: + { + this.state = 242; + this.match(esql_parser.NOT); + this.state = 243; + this.booleanExpression(4); + } + break; + case esql_parser.STRING: + case esql_parser.INTEGER_LITERAL: + case esql_parser.DECIMAL_LITERAL: + case esql_parser.LP: + case esql_parser.OPENING_BRACKET: + case esql_parser.NULL: + case esql_parser.BOOLEAN_VALUE: + case esql_parser.PLUS: + case esql_parser.MINUS: + case esql_parser.ASTERISK: + case esql_parser.MATH_FUNCTION: + case esql_parser.UNARY_FUNCTION: + case esql_parser.UNQUOTED_IDENTIFIER: + case esql_parser.QUOTED_IDENTIFIER: + { + this.state = 244; + this.valueExpression(); + } + break; + default: + throw new NoViableAltException(this); + } + this._ctx._stop = this._input.tryLT(-1); + this.state = 255; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 18, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + if (this._parseListeners != null) { + this.triggerExitRuleEvent(); + } + _prevctx = _localctx; + { + this.state = 253; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 17, this._ctx) ) { + case 1: + { + _localctx = new BooleanExpressionContext(_parentctx, _parentState); + _localctx._left = _prevctx; + this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_booleanExpression); + this.state = 247; + if (!(this.precpred(this._ctx, 2))) { + throw new FailedPredicateException(this, "this.precpred(this._ctx, 2)"); + } + this.state = 248; + _localctx._operator = this.match(esql_parser.AND); + this.state = 249; + _localctx._right = this.booleanExpression(3); } break; case 2: { - _localctx = new OperatorExpressionContext(_parentctx, _parentState); + _localctx = new BooleanExpressionContext(_parentctx, _parentState); _localctx._left = _prevctx; - this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_operatorExpression); - this.state = 151; + this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_booleanExpression); + this.state = 250; if (!(this.precpred(this._ctx, 1))) { throw new FailedPredicateException(this, "this.precpred(this._ctx, 1)"); } - this.state = 152; - _localctx._operator = this._input.LT(1); - _la = this._input.LA(1); - if (!(_la === esql_parser.PLUS || _la === esql_parser.MINUS)) { - _localctx._operator = this._errHandler.recoverInline(this); - } else { - if (this._input.LA(1) === Token.EOF) { - this.matchedEOF = true; - } - - this._errHandler.reportMatch(this); - this.consume(); - } - this.state = 153; - _localctx._right = this.operatorExpression(2); + this.state = 251; + _localctx._operator = this.match(esql_parser.OR); + this.state = 252; + _localctx._right = this.booleanExpression(2); } break; } } } - this.state = 158; + this.state = 257; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 11, this._ctx); + _alt = this.interpreter.adaptivePredict(this._input, 18, this._ctx); } } } @@ -802,77 +1008,55 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public primaryExpression(): PrimaryExpressionContext { - let _localctx: PrimaryExpressionContext = new PrimaryExpressionContext(this._ctx, this.state); - this.enterRule(_localctx, 20, esql_parser.RULE_primaryExpression); + public regexBooleanExpression(): RegexBooleanExpressionContext { + let _localctx: RegexBooleanExpressionContext = new RegexBooleanExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 20, esql_parser.RULE_regexBooleanExpression); let _la: number; try { - this.state = 179; + this.state = 272; this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 14, this._ctx) ) { + switch ( this.interpreter.adaptivePredict(this._input, 21, this._ctx) ) { case 1: this.enterOuterAlt(_localctx, 1); { - this.state = 159; - this.constant(); - } - break; - - case 2: - this.enterOuterAlt(_localctx, 2); - { - this.state = 160; - this.qualifiedName(); + this.state = 258; + this.valueExpression(); + this.state = 260; + this._errHandler.sync(this); + _la = this._input.LA(1); + if (_la === esql_parser.NOT) { + { + this.state = 259; + this.match(esql_parser.NOT); + } } - break; - case 3: - this.enterOuterAlt(_localctx, 3); - { - this.state = 161; - this.match(esql_parser.LP); - this.state = 162; - this.booleanExpression(0); - this.state = 163; - this.match(esql_parser.RP); + this.state = 262; + _localctx._kind = this.match(esql_parser.LIKE); + this.state = 263; + _localctx._pattern = this.string(); } break; - case 4: - this.enterOuterAlt(_localctx, 4); + case 2: + this.enterOuterAlt(_localctx, 2); { - this.state = 165; - this.identifier(); - this.state = 166; - this.match(esql_parser.LP); - this.state = 175; + this.state = 265; + this.valueExpression(); + this.state = 267; this._errHandler.sync(this); _la = this._input.LA(1); - if (((((_la - 14)) & ~0x1F) === 0 && ((1 << (_la - 14)) & ((1 << (esql_parser.STRING - 14)) | (1 << (esql_parser.INTEGER_LITERAL - 14)) | (1 << (esql_parser.DECIMAL_LITERAL - 14)) | (1 << (esql_parser.LP - 14)) | (1 << (esql_parser.NOT - 14)) | (1 << (esql_parser.NULL - 14)) | (1 << (esql_parser.BOOLEAN_VALUE - 14)) | (1 << (esql_parser.PLUS - 14)) | (1 << (esql_parser.MINUS - 14)) | (1 << (esql_parser.UNARY_FUNCTION - 14)) | (1 << (esql_parser.UNQUOTED_IDENTIFIER - 14)) | (1 << (esql_parser.QUOTED_IDENTIFIER - 14)))) !== 0)) { + if (_la === esql_parser.NOT) { { - this.state = 167; - this.booleanExpression(0); - this.state = 172; - this._errHandler.sync(this); - _la = this._input.LA(1); - while (_la === esql_parser.COMMA) { - { - { - this.state = 168; - this.match(esql_parser.COMMA); - this.state = 169; - this.booleanExpression(0); - } - } - this.state = 174; - this._errHandler.sync(this); - _la = this._input.LA(1); - } + this.state = 266; + this.match(esql_parser.NOT); } } - this.state = 177; - this.match(esql_parser.RP); + this.state = 269; + _localctx._kind = this.match(esql_parser.RLIKE); + this.state = 270; + _localctx._pattern = this.string(); } break; } @@ -892,16 +1076,28 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public rowCommand(): RowCommandContext { - let _localctx: RowCommandContext = new RowCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 22, esql_parser.RULE_rowCommand); + public valueExpression(): ValueExpressionContext { + let _localctx: ValueExpressionContext = new ValueExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 22, esql_parser.RULE_valueExpression); try { - this.enterOuterAlt(_localctx, 1); - { - this.state = 181; - this.match(esql_parser.ROW); - this.state = 182; - this.fields(); + this.state = 276; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 22, this._ctx) ) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 274; + this.operatorExpression(0); + } + break; + + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 275; + this.comparison(); + } + break; } } catch (re) { @@ -919,33 +1115,18 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public fields(): FieldsContext { - let _localctx: FieldsContext = new FieldsContext(this._ctx, this.state); - this.enterRule(_localctx, 24, esql_parser.RULE_fields); + public comparison(): ComparisonContext { + let _localctx: ComparisonContext = new ComparisonContext(this._ctx, this.state); + this.enterRule(_localctx, 24, esql_parser.RULE_comparison); try { - let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 184; - this.field(); - this.state = 189; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 15, this._ctx); - while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { - if (_alt === 1) { - { - { - this.state = 185; - this.match(esql_parser.COMMA); - this.state = 186; - this.field(); - } - } - } - this.state = 191; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 15, this._ctx); - } + this.state = 278; + _localctx._left = this.operatorExpression(0); + this.state = 279; + this.comparisonOperator(); + this.state = 280; + _localctx._right = this.operatorExpression(0); } } catch (re) { @@ -963,57 +1144,45 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public field(): FieldContext { - let _localctx: FieldContext = new FieldContext(this._ctx, this.state); - this.enterRule(_localctx, 26, esql_parser.RULE_field); + public mathFn(): MathFnContext { + let _localctx: MathFnContext = new MathFnContext(this._ctx, this.state); + this.enterRule(_localctx, 26, esql_parser.RULE_mathFn); + let _la: number; try { - this.state = 197; + this.enterOuterAlt(_localctx, 1); + { + this.state = 282; + this.functionIdentifier(); + this.state = 283; + this.match(esql_parser.LP); + this.state = 292; this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 16, this._ctx) ) { - case 1: - this.enterOuterAlt(_localctx, 1); + _la = this._input.LA(1); + if ((((_la) & ~0x1F) === 0 && ((1 << _la) & ((1 << esql_parser.STRING) | (1 << esql_parser.INTEGER_LITERAL) | (1 << esql_parser.DECIMAL_LITERAL))) !== 0) || ((((_la - 53)) & ~0x1F) === 0 && ((1 << (_la - 53)) & ((1 << (esql_parser.ASTERISK - 53)) | (1 << (esql_parser.UNQUOTED_IDENTIFIER - 53)) | (1 << (esql_parser.QUOTED_IDENTIFIER - 53)))) !== 0)) { { - this.state = 192; - this.booleanExpression(0); + this.state = 284; + this.functionExpressionArgument(); + this.state = 289; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 285; + this.match(esql_parser.COMMA); + this.state = 286; + this.functionExpressionArgument(); + } + } + this.state = 291; + this._errHandler.sync(this); + _la = this._input.LA(1); } - break; - - case 2: - this.enterOuterAlt(_localctx, 2); - { - this.state = 193; - this.userVariable(); - this.state = 194; - this.match(esql_parser.ASSIGN); - this.state = 195; - this.booleanExpression(0); } - break; - } - } - catch (re) { - if (re instanceof RecognitionException) { - _localctx.exception = re; - this._errHandler.reportError(this, re); - this._errHandler.recover(this, re); - } else { - throw re; } - } - finally { - this.exitRule(); - } - return _localctx; - } - // @RuleVersion(0) - public userVariable(): UserVariableContext { - let _localctx: UserVariableContext = new UserVariableContext(this._ctx, this.state); - this.enterRule(_localctx, 28, esql_parser.RULE_userVariable); - try { - this.enterOuterAlt(_localctx, 1); - { - this.state = 199; - this.identifier(); + + this.state = 294; + this.match(esql_parser.RP); } } catch (re) { @@ -1031,35 +1200,45 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public fromCommand(): FromCommandContext { - let _localctx: FromCommandContext = new FromCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 30, esql_parser.RULE_fromCommand); + public mathEvalFn(): MathEvalFnContext { + let _localctx: MathEvalFnContext = new MathEvalFnContext(this._ctx, this.state); + this.enterRule(_localctx, 28, esql_parser.RULE_mathEvalFn); + let _la: number; try { - let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 201; - this.match(esql_parser.FROM); - this.state = 202; - this.sourceIdentifier(); - this.state = 207; + this.state = 296; + this.mathFunctionIdentifier(); + this.state = 297; + this.match(esql_parser.LP); + this.state = 306; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 17, this._ctx); - while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { - if (_alt === 1) { + _la = this._input.LA(1); + if ((((_la) & ~0x1F) === 0 && ((1 << _la) & ((1 << esql_parser.STRING) | (1 << esql_parser.INTEGER_LITERAL) | (1 << esql_parser.DECIMAL_LITERAL))) !== 0) || ((((_la - 34)) & ~0x1F) === 0 && ((1 << (_la - 34)) & ((1 << (esql_parser.LP - 34)) | (1 << (esql_parser.OPENING_BRACKET - 34)) | (1 << (esql_parser.NULL - 34)) | (1 << (esql_parser.BOOLEAN_VALUE - 34)) | (1 << (esql_parser.PLUS - 34)) | (1 << (esql_parser.MINUS - 34)) | (1 << (esql_parser.ASTERISK - 34)) | (1 << (esql_parser.MATH_FUNCTION - 34)) | (1 << (esql_parser.UNARY_FUNCTION - 34)) | (1 << (esql_parser.UNQUOTED_IDENTIFIER - 34)) | (1 << (esql_parser.QUOTED_IDENTIFIER - 34)))) !== 0)) { + { + this.state = 298; + this.mathFunctionExpressionArgument(); + this.state = 303; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { { { - this.state = 203; + this.state = 299; this.match(esql_parser.COMMA); - this.state = 204; - this.sourceIdentifier(); + this.state = 300; + this.mathFunctionExpressionArgument(); } } + this.state = 305; + this._errHandler.sync(this); + _la = this._input.LA(1); + } } - this.state = 209; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 17, this._ctx); } + + this.state = 308; + this.match(esql_parser.RP); } } catch (re) { @@ -1076,55 +1255,152 @@ export class esql_parser extends Parser { } return _localctx; } + + public operatorExpression(): OperatorExpressionContext; + public operatorExpression(_p: number): OperatorExpressionContext; // @RuleVersion(0) - public evalCommand(): EvalCommandContext { - let _localctx: EvalCommandContext = new EvalCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 32, esql_parser.RULE_evalCommand); - try { - this.enterOuterAlt(_localctx, 1); - { - this.state = 210; - this.match(esql_parser.EVAL); - this.state = 211; - this.fields(); - } - } - catch (re) { - if (re instanceof RecognitionException) { - _localctx.exception = re; - this._errHandler.reportError(this, re); - this._errHandler.recover(this, re); - } else { - throw re; - } - } - finally { - this.exitRule(); + public operatorExpression(_p?: number): OperatorExpressionContext { + if (_p === undefined) { + _p = 0; } - return _localctx; - } - // @RuleVersion(0) - public statsCommand(): StatsCommandContext { - let _localctx: StatsCommandContext = new StatsCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 34, esql_parser.RULE_statsCommand); + + let _parentctx: ParserRuleContext = this._ctx; + let _parentState: number = this.state; + let _localctx: OperatorExpressionContext = new OperatorExpressionContext(this._ctx, _parentState); + let _prevctx: OperatorExpressionContext = _localctx; + let _startState: number = 30; + this.enterRecursionRule(_localctx, 30, esql_parser.RULE_operatorExpression, _p); + let _la: number; try { + let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 213; - this.match(esql_parser.STATS); - this.state = 214; - this.fields(); - this.state = 217; + this.state = 316; this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 18, this._ctx) ) { - case 1: + switch (this._input.LA(1)) { + case esql_parser.STRING: + case esql_parser.INTEGER_LITERAL: + case esql_parser.DECIMAL_LITERAL: + case esql_parser.LP: + case esql_parser.OPENING_BRACKET: + case esql_parser.NULL: + case esql_parser.BOOLEAN_VALUE: + case esql_parser.ASTERISK: + case esql_parser.UNQUOTED_IDENTIFIER: + case esql_parser.QUOTED_IDENTIFIER: { - this.state = 215; - this.match(esql_parser.BY); - this.state = 216; - this.qualifiedNames(); + this.state = 311; + this.primaryExpression(); + } + break; + case esql_parser.UNARY_FUNCTION: + { + this.state = 312; + this.mathFn(); } break; + case esql_parser.MATH_FUNCTION: + { + this.state = 313; + this.mathEvalFn(); + } + break; + case esql_parser.PLUS: + case esql_parser.MINUS: + { + this.state = 314; + _localctx._operator = this._input.LT(1); + _la = this._input.LA(1); + if (!(_la === esql_parser.PLUS || _la === esql_parser.MINUS)) { + _localctx._operator = this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; + } + + this._errHandler.reportMatch(this); + this.consume(); + } + this.state = 315; + this.operatorExpression(3); + } + break; + default: + throw new NoViableAltException(this); + } + this._ctx._stop = this._input.tryLT(-1); + this.state = 326; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 29, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + if (this._parseListeners != null) { + this.triggerExitRuleEvent(); + } + _prevctx = _localctx; + { + this.state = 324; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 28, this._ctx) ) { + case 1: + { + _localctx = new OperatorExpressionContext(_parentctx, _parentState); + _localctx._left = _prevctx; + this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_operatorExpression); + this.state = 318; + if (!(this.precpred(this._ctx, 2))) { + throw new FailedPredicateException(this, "this.precpred(this._ctx, 2)"); + } + this.state = 319; + _localctx._operator = this._input.LT(1); + _la = this._input.LA(1); + if (!(((((_la - 53)) & ~0x1F) === 0 && ((1 << (_la - 53)) & ((1 << (esql_parser.ASTERISK - 53)) | (1 << (esql_parser.SLASH - 53)) | (1 << (esql_parser.PERCENT - 53)))) !== 0))) { + _localctx._operator = this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; + } + + this._errHandler.reportMatch(this); + this.consume(); + } + this.state = 320; + _localctx._right = this.operatorExpression(3); + } + break; + + case 2: + { + _localctx = new OperatorExpressionContext(_parentctx, _parentState); + _localctx._left = _prevctx; + this.pushNewRecursionContext(_localctx, _startState, esql_parser.RULE_operatorExpression); + this.state = 321; + if (!(this.precpred(this._ctx, 1))) { + throw new FailedPredicateException(this, "this.precpred(this._ctx, 1)"); + } + this.state = 322; + _localctx._operator = this._input.LT(1); + _la = this._input.LA(1); + if (!(_la === esql_parser.PLUS || _la === esql_parser.MINUS)) { + _localctx._operator = this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; + } + + this._errHandler.reportMatch(this); + this.consume(); + } + this.state = 323; + _localctx._right = this.operatorExpression(2); + } + break; + } + } + } + this.state = 328; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 29, this._ctx); } } } @@ -1138,30 +1414,84 @@ export class esql_parser extends Parser { } } finally { - this.exitRule(); + this.unrollRecursionContexts(_parentctx); } return _localctx; } // @RuleVersion(0) - public sourceIdentifier(): SourceIdentifierContext { - let _localctx: SourceIdentifierContext = new SourceIdentifierContext(this._ctx, this.state); - this.enterRule(_localctx, 36, esql_parser.RULE_sourceIdentifier); + public primaryExpression(): PrimaryExpressionContext { + let _localctx: PrimaryExpressionContext = new PrimaryExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 32, esql_parser.RULE_primaryExpression); let _la: number; try { - this.enterOuterAlt(_localctx, 1); - { - this.state = 219; - _la = this._input.LA(1); - if (!(_la === esql_parser.SRC_UNQUOTED_IDENTIFIER || _la === esql_parser.SRC_QUOTED_IDENTIFIER)) { - this._errHandler.recoverInline(this); - } else { - if (this._input.LA(1) === Token.EOF) { - this.matchedEOF = true; + this.state = 349; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 32, this._ctx) ) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 329; + this.constant(); } + break; - this._errHandler.reportMatch(this); - this.consume(); - } + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 330; + this.qualifiedName(); + } + break; + + case 3: + this.enterOuterAlt(_localctx, 3); + { + this.state = 331; + this.match(esql_parser.LP); + this.state = 332; + this.booleanExpression(0); + this.state = 333; + this.match(esql_parser.RP); + } + break; + + case 4: + this.enterOuterAlt(_localctx, 4); + { + this.state = 335; + this.identifier(); + this.state = 336; + this.match(esql_parser.LP); + this.state = 345; + this._errHandler.sync(this); + _la = this._input.LA(1); + if ((((_la) & ~0x1F) === 0 && ((1 << _la) & ((1 << esql_parser.STRING) | (1 << esql_parser.INTEGER_LITERAL) | (1 << esql_parser.DECIMAL_LITERAL))) !== 0) || ((((_la - 34)) & ~0x1F) === 0 && ((1 << (_la - 34)) & ((1 << (esql_parser.LP - 34)) | (1 << (esql_parser.OPENING_BRACKET - 34)) | (1 << (esql_parser.NOT - 34)) | (1 << (esql_parser.NULL - 34)) | (1 << (esql_parser.BOOLEAN_VALUE - 34)) | (1 << (esql_parser.PLUS - 34)) | (1 << (esql_parser.MINUS - 34)) | (1 << (esql_parser.ASTERISK - 34)) | (1 << (esql_parser.MATH_FUNCTION - 34)) | (1 << (esql_parser.UNARY_FUNCTION - 34)) | (1 << (esql_parser.UNQUOTED_IDENTIFIER - 34)) | (1 << (esql_parser.QUOTED_IDENTIFIER - 34)))) !== 0)) { + { + this.state = 337; + this.booleanExpression(0); + this.state = 342; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 338; + this.match(esql_parser.COMMA); + this.state = 339; + this.booleanExpression(0); + } + } + this.state = 344; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + } + } + + this.state = 347; + this.match(esql_parser.RP); + } + break; } } catch (re) { @@ -1179,30 +1509,16 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public functionExpressionArgument(): FunctionExpressionArgumentContext { - let _localctx: FunctionExpressionArgumentContext = new FunctionExpressionArgumentContext(this._ctx, this.state); - this.enterRule(_localctx, 38, esql_parser.RULE_functionExpressionArgument); + public rowCommand(): RowCommandContext { + let _localctx: RowCommandContext = new RowCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 34, esql_parser.RULE_rowCommand); try { - this.state = 223; - this._errHandler.sync(this); - switch (this._input.LA(1)) { - case esql_parser.UNQUOTED_IDENTIFIER: - case esql_parser.QUOTED_IDENTIFIER: - this.enterOuterAlt(_localctx, 1); - { - this.state = 221; - this.qualifiedName(); - } - break; - case esql_parser.STRING: - this.enterOuterAlt(_localctx, 2); - { - this.state = 222; - this.string(); - } - break; - default: - throw new NoViableAltException(this); + this.enterOuterAlt(_localctx, 1); + { + this.state = 351; + this.match(esql_parser.ROW); + this.state = 352; + this.fields(); } } catch (re) { @@ -1220,32 +1536,32 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public qualifiedName(): QualifiedNameContext { - let _localctx: QualifiedNameContext = new QualifiedNameContext(this._ctx, this.state); - this.enterRule(_localctx, 40, esql_parser.RULE_qualifiedName); + public fields(): FieldsContext { + let _localctx: FieldsContext = new FieldsContext(this._ctx, this.state); + this.enterRule(_localctx, 36, esql_parser.RULE_fields); try { let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 225; - this.identifier(); - this.state = 230; + this.state = 354; + this.field(); + this.state = 359; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 20, this._ctx); + _alt = this.interpreter.adaptivePredict(this._input, 33, this._ctx); while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { if (_alt === 1) { { { - this.state = 226; - this.match(esql_parser.DOT); - this.state = 227; - this.identifier(); + this.state = 355; + this.match(esql_parser.COMMA); + this.state = 356; + this.field(); } } } - this.state = 232; + this.state = 361; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 20, this._ctx); + _alt = this.interpreter.adaptivePredict(this._input, 33, this._ctx); } } } @@ -1264,33 +1580,32 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public qualifiedNames(): QualifiedNamesContext { - let _localctx: QualifiedNamesContext = new QualifiedNamesContext(this._ctx, this.state); - this.enterRule(_localctx, 42, esql_parser.RULE_qualifiedNames); + public field(): FieldContext { + let _localctx: FieldContext = new FieldContext(this._ctx, this.state); + this.enterRule(_localctx, 38, esql_parser.RULE_field); try { - let _alt: number; - this.enterOuterAlt(_localctx, 1); - { - this.state = 233; - this.qualifiedName(); - this.state = 238; + this.state = 367; this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 21, this._ctx); - while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { - if (_alt === 1) { - { - { - this.state = 234; - this.match(esql_parser.COMMA); - this.state = 235; - this.qualifiedName(); - } - } + switch ( this.interpreter.adaptivePredict(this._input, 34, this._ctx) ) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 362; + this.booleanExpression(0); } - this.state = 240; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 21, this._ctx); - } + break; + + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 363; + this.userVariable(); + this.state = 364; + this.match(esql_parser.ASSIGN); + this.state = 365; + this.booleanExpression(0); + } + break; } } catch (re) { @@ -1308,16 +1623,16 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public identifier(): IdentifierContext { - let _localctx: IdentifierContext = new IdentifierContext(this._ctx, this.state); - this.enterRule(_localctx, 44, esql_parser.RULE_identifier); + public enrichFieldIdentifier(): EnrichFieldIdentifierContext { + let _localctx: EnrichFieldIdentifierContext = new EnrichFieldIdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 40, esql_parser.RULE_enrichFieldIdentifier); let _la: number; try { this.enterOuterAlt(_localctx, 1); { - this.state = 241; + this.state = 369; _la = this._input.LA(1); - if (!(_la === esql_parser.UNQUOTED_IDENTIFIER || _la === esql_parser.QUOTED_IDENTIFIER)) { + if (!(_la === esql_parser.ENR_UNQUOTED_IDENTIFIER || _la === esql_parser.ENR_QUOTED_IDENTIFIER)) { this._errHandler.recoverInline(this); } else { if (this._input.LA(1) === Token.EOF) { @@ -1344,14 +1659,14 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public functionIdentifier(): FunctionIdentifierContext { - let _localctx: FunctionIdentifierContext = new FunctionIdentifierContext(this._ctx, this.state); - this.enterRule(_localctx, 46, esql_parser.RULE_functionIdentifier); + public userVariable(): UserVariableContext { + let _localctx: UserVariableContext = new UserVariableContext(this._ctx, this.state); + this.enterRule(_localctx, 42, esql_parser.RULE_userVariable); try { this.enterOuterAlt(_localctx, 1); { - this.state = 243; - this.match(esql_parser.UNARY_FUNCTION); + this.state = 371; + this.identifier(); } } catch (re) { @@ -1369,48 +1684,45 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public constant(): ConstantContext { - let _localctx: ConstantContext = new ConstantContext(this._ctx, this.state); - this.enterRule(_localctx, 48, esql_parser.RULE_constant); + public fromCommand(): FromCommandContext { + let _localctx: FromCommandContext = new FromCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 44, esql_parser.RULE_fromCommand); try { - this.state = 249; + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 373; + this.match(esql_parser.FROM); + this.state = 374; + this.sourceIdentifier(); + this.state = 379; this._errHandler.sync(this); - switch (this._input.LA(1)) { - case esql_parser.NULL: - _localctx = new NullLiteralContext(_localctx); - this.enterOuterAlt(_localctx, 1); - { - this.state = 245; - this.match(esql_parser.NULL); - } - break; - case esql_parser.INTEGER_LITERAL: - case esql_parser.DECIMAL_LITERAL: - _localctx = new NumericLiteralContext(_localctx); - this.enterOuterAlt(_localctx, 2); - { - this.state = 246; - this.number(); - } - break; - case esql_parser.BOOLEAN_VALUE: - _localctx = new BooleanLiteralContext(_localctx); - this.enterOuterAlt(_localctx, 3); - { - this.state = 247; - this.booleanValue(); + _alt = this.interpreter.adaptivePredict(this._input, 35, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 375; + this.match(esql_parser.COMMA); + this.state = 376; + this.sourceIdentifier(); + } + } } - break; - case esql_parser.STRING: - _localctx = new StringLiteralContext(_localctx); - this.enterOuterAlt(_localctx, 4); + this.state = 381; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 35, this._ctx); + } + this.state = 383; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 36, this._ctx) ) { + case 1: { - this.state = 248; - this.string(); + this.state = 382; + this.metadata(); } break; - default: - throw new NoViableAltException(this); + } } } catch (re) { @@ -1428,16 +1740,37 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public limitCommand(): LimitCommandContext { - let _localctx: LimitCommandContext = new LimitCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 50, esql_parser.RULE_limitCommand); + public metadata(): MetadataContext { + let _localctx: MetadataContext = new MetadataContext(this._ctx, this.state); + this.enterRule(_localctx, 46, esql_parser.RULE_metadata); + let _la: number; try { this.enterOuterAlt(_localctx, 1); { - this.state = 251; - this.match(esql_parser.LIMIT); - this.state = 252; - this.match(esql_parser.INTEGER_LITERAL); + this.state = 385; + this.match(esql_parser.OPENING_BRACKET); + this.state = 386; + this.match(esql_parser.METADATA); + this.state = 387; + this.sourceIdentifier(); + this.state = 392; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 388; + this.match(esql_parser.COMMA); + this.state = 389; + this.sourceIdentifier(); + } + } + this.state = 394; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + this.state = 395; + this.match(esql_parser.CLOSING_BRACKET); } } catch (re) { @@ -1455,35 +1788,16 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public sortCommand(): SortCommandContext { - let _localctx: SortCommandContext = new SortCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 52, esql_parser.RULE_sortCommand); + public evalCommand(): EvalCommandContext { + let _localctx: EvalCommandContext = new EvalCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 48, esql_parser.RULE_evalCommand); try { - let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 254; - this.match(esql_parser.SORT); - this.state = 255; - this.orderExpression(); - this.state = 260; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 23, this._ctx); - while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { - if (_alt === 1) { - { - { - this.state = 256; - this.match(esql_parser.COMMA); - this.state = 257; - this.orderExpression(); - } - } - } - this.state = 262; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 23, this._ctx); - } + this.state = 397; + this.match(esql_parser.EVAL); + this.state = 398; + this.fields(); } } catch (re) { @@ -1501,35 +1815,33 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public orderExpression(): OrderExpressionContext { - let _localctx: OrderExpressionContext = new OrderExpressionContext(this._ctx, this.state); - this.enterRule(_localctx, 54, esql_parser.RULE_orderExpression); + public statsCommand(): StatsCommandContext { + let _localctx: StatsCommandContext = new StatsCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 50, esql_parser.RULE_statsCommand); try { this.enterOuterAlt(_localctx, 1); { - this.state = 263; - this.booleanExpression(0); - this.state = 265; + this.state = 400; + this.match(esql_parser.STATS); + this.state = 402; this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 24, this._ctx) ) { + switch ( this.interpreter.adaptivePredict(this._input, 38, this._ctx) ) { case 1: { - this.state = 264; - this.match(esql_parser.ORDERING); + this.state = 401; + this.fields(); } break; } - this.state = 269; + this.state = 406; this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 25, this._ctx) ) { + switch ( this.interpreter.adaptivePredict(this._input, 39, this._ctx) ) { case 1: { - this.state = 267; - this.match(esql_parser.NULLS_ORDERING); - { - this.state = 268; - this.match(esql_parser.NULLS_ORDERING_DIRECTION); - } + this.state = 404; + this.match(esql_parser.BY); + this.state = 405; + this.qualifiedNames(); } break; } @@ -1550,34 +1862,24 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public projectCommand(): ProjectCommandContext { - let _localctx: ProjectCommandContext = new ProjectCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 56, esql_parser.RULE_projectCommand); + public sourceIdentifier(): SourceIdentifierContext { + let _localctx: SourceIdentifierContext = new SourceIdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 52, esql_parser.RULE_sourceIdentifier); + let _la: number; try { - let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 271; - this.match(esql_parser.PROJECT); - this.state = 272; - this.projectClause(); - this.state = 277; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 26, this._ctx); - while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { - if (_alt === 1) { - { - { - this.state = 273; - this.match(esql_parser.COMMA); - this.state = 274; - this.projectClause(); - } - } + this.state = 408; + _la = this._input.LA(1); + if (!(_la === esql_parser.SRC_UNQUOTED_IDENTIFIER || _la === esql_parser.SRC_QUOTED_IDENTIFIER)) { + this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; } - this.state = 279; - this._errHandler.sync(this); - _alt = this.interpreter.adaptivePredict(this._input, 26, this._ctx); + + this._errHandler.reportMatch(this); + this.consume(); } } } @@ -1596,32 +1898,25 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public projectClause(): ProjectClauseContext { - let _localctx: ProjectClauseContext = new ProjectClauseContext(this._ctx, this.state); - this.enterRule(_localctx, 58, esql_parser.RULE_projectClause); + public enrichIdentifier(): EnrichIdentifierContext { + let _localctx: EnrichIdentifierContext = new EnrichIdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 54, esql_parser.RULE_enrichIdentifier); + let _la: number; try { - this.state = 285; - this._errHandler.sync(this); - switch ( this.interpreter.adaptivePredict(this._input, 27, this._ctx) ) { - case 1: - this.enterOuterAlt(_localctx, 1); - { - this.state = 280; - this.sourceIdentifier(); + this.enterOuterAlt(_localctx, 1); + { + this.state = 410; + _la = this._input.LA(1); + if (!(_la === esql_parser.ENR_UNQUOTED_IDENTIFIER || _la === esql_parser.ENR_QUOTED_IDENTIFIER)) { + this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; } - break; - case 2: - this.enterOuterAlt(_localctx, 2); - { - this.state = 281; - _localctx._newName = this.sourceIdentifier(); - this.state = 282; - this.match(esql_parser.ASSIGN); - this.state = 283; - _localctx._oldName = this.sourceIdentifier(); - } - break; + this._errHandler.reportMatch(this); + this.consume(); + } } } catch (re) { @@ -1639,14 +1934,39 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public booleanValue(): BooleanValueContext { - let _localctx: BooleanValueContext = new BooleanValueContext(this._ctx, this.state); - this.enterRule(_localctx, 60, esql_parser.RULE_booleanValue); + public functionExpressionArgument(): FunctionExpressionArgumentContext { + let _localctx: FunctionExpressionArgumentContext = new FunctionExpressionArgumentContext(this._ctx, this.state); + this.enterRule(_localctx, 56, esql_parser.RULE_functionExpressionArgument); try { - this.enterOuterAlt(_localctx, 1); - { - this.state = 287; - this.match(esql_parser.BOOLEAN_VALUE); + this.state = 415; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case esql_parser.ASTERISK: + case esql_parser.UNQUOTED_IDENTIFIER: + case esql_parser.QUOTED_IDENTIFIER: + this.enterOuterAlt(_localctx, 1); + { + this.state = 412; + this.qualifiedName(); + } + break; + case esql_parser.STRING: + this.enterOuterAlt(_localctx, 2); + { + this.state = 413; + this.string(); + } + break; + case esql_parser.INTEGER_LITERAL: + case esql_parser.DECIMAL_LITERAL: + this.enterOuterAlt(_localctx, 3); + { + this.state = 414; + this.number(); + } + break; + default: + throw new NoViableAltException(this); } } catch (re) { @@ -1664,31 +1984,64 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public number(): NumberContext { - let _localctx: NumberContext = new NumberContext(this._ctx, this.state); - this.enterRule(_localctx, 62, esql_parser.RULE_number); + public mathFunctionExpressionArgument(): MathFunctionExpressionArgumentContext { + let _localctx: MathFunctionExpressionArgumentContext = new MathFunctionExpressionArgumentContext(this._ctx, this.state); + this.enterRule(_localctx, 58, esql_parser.RULE_mathFunctionExpressionArgument); try { - this.state = 291; + this.state = 425; this._errHandler.sync(this); - switch (this._input.LA(1)) { - case esql_parser.DECIMAL_LITERAL: - _localctx = new DecimalLiteralContext(_localctx); + switch ( this.interpreter.adaptivePredict(this._input, 41, this._ctx) ) { + case 1: this.enterOuterAlt(_localctx, 1); { - this.state = 289; - this.match(esql_parser.DECIMAL_LITERAL); + this.state = 417; + this.qualifiedName(); } break; - case esql_parser.INTEGER_LITERAL: - _localctx = new IntegerLiteralContext(_localctx); + + case 2: this.enterOuterAlt(_localctx, 2); { - this.state = 290; - this.match(esql_parser.INTEGER_LITERAL); + this.state = 418; + this.string(); + } + break; + + case 3: + this.enterOuterAlt(_localctx, 3); + { + this.state = 419; + this.number(); + } + break; + + case 4: + this.enterOuterAlt(_localctx, 4); + { + this.state = 420; + this.operatorExpression(0); + } + break; + + case 5: + this.enterOuterAlt(_localctx, 5); + { + this.state = 421; + this.number(); + { + this.state = 422; + this.match(esql_parser.DATE_LITERAL); + } + } + break; + + case 6: + this.enterOuterAlt(_localctx, 6); + { + this.state = 424; + this.comparison(); } break; - default: - throw new NoViableAltException(this); } } catch (re) { @@ -1706,14 +2059,33 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public string(): StringContext { - let _localctx: StringContext = new StringContext(this._ctx, this.state); - this.enterRule(_localctx, 64, esql_parser.RULE_string); + public qualifiedName(): QualifiedNameContext { + let _localctx: QualifiedNameContext = new QualifiedNameContext(this._ctx, this.state); + this.enterRule(_localctx, 60, esql_parser.RULE_qualifiedName); try { + let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 293; - this.match(esql_parser.STRING); + this.state = 427; + this.identifier(); + this.state = 432; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 42, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 428; + this.match(esql_parser.DOT); + this.state = 429; + this.identifier(); + } + } + } + this.state = 434; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 42, this._ctx); + } } } catch (re) { @@ -1731,14 +2103,33 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public comparisonOperator(): ComparisonOperatorContext { - let _localctx: ComparisonOperatorContext = new ComparisonOperatorContext(this._ctx, this.state); - this.enterRule(_localctx, 66, esql_parser.RULE_comparisonOperator); + public qualifiedNames(): QualifiedNamesContext { + let _localctx: QualifiedNamesContext = new QualifiedNamesContext(this._ctx, this.state); + this.enterRule(_localctx, 62, esql_parser.RULE_qualifiedNames); try { + let _alt: number; this.enterOuterAlt(_localctx, 1); { - this.state = 295; - this.match(esql_parser.COMPARISON_OPERATOR); + this.state = 435; + this.qualifiedName(); + this.state = 440; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 43, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 436; + this.match(esql_parser.COMMA); + this.state = 437; + this.qualifiedName(); + } + } + } + this.state = 442; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 43, this._ctx); + } } } catch (re) { @@ -1756,16 +2147,25 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public explainCommand(): ExplainCommandContext { - let _localctx: ExplainCommandContext = new ExplainCommandContext(this._ctx, this.state); - this.enterRule(_localctx, 68, esql_parser.RULE_explainCommand); + public identifier(): IdentifierContext { + let _localctx: IdentifierContext = new IdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 64, esql_parser.RULE_identifier); + let _la: number; try { this.enterOuterAlt(_localctx, 1); { - this.state = 297; - this.match(esql_parser.EXPLAIN); - this.state = 298; - this.subqueryExpression(); + this.state = 443; + _la = this._input.LA(1); + if (!(((((_la - 53)) & ~0x1F) === 0 && ((1 << (_la - 53)) & ((1 << (esql_parser.ASTERISK - 53)) | (1 << (esql_parser.UNQUOTED_IDENTIFIER - 53)) | (1 << (esql_parser.QUOTED_IDENTIFIER - 53)))) !== 0))) { + this._errHandler.recoverInline(this); + } else { + if (this._input.LA(1) === Token.EOF) { + this.matchedEOF = true; + } + + this._errHandler.reportMatch(this); + this.consume(); + } } } catch (re) { @@ -1783,18 +2183,14 @@ export class esql_parser extends Parser { return _localctx; } // @RuleVersion(0) - public subqueryExpression(): SubqueryExpressionContext { - let _localctx: SubqueryExpressionContext = new SubqueryExpressionContext(this._ctx, this.state); - this.enterRule(_localctx, 70, esql_parser.RULE_subqueryExpression); + public mathFunctionIdentifier(): MathFunctionIdentifierContext { + let _localctx: MathFunctionIdentifierContext = new MathFunctionIdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 66, esql_parser.RULE_mathFunctionIdentifier); try { this.enterOuterAlt(_localctx, 1); { - this.state = 300; - this.match(esql_parser.OPENING_BRACKET); - this.state = 301; - this.query(0); - this.state = 302; - this.match(esql_parser.CLOSING_BRACKET); + this.state = 445; + this.match(esql_parser.MATH_FUNCTION); } } catch (re) { @@ -1811,488 +2207,2199 @@ export class esql_parser extends Parser { } return _localctx; } - - public sempred(_localctx: RuleContext, ruleIndex: number, predIndex: number): boolean { - switch (ruleIndex) { - case 1: - return this.query_sempred(_localctx as QueryContext, predIndex); - - case 5: - return this.booleanExpression_sempred(_localctx as BooleanExpressionContext, predIndex); - - case 9: - return this.operatorExpression_sempred(_localctx as OperatorExpressionContext, predIndex); - } - return true; - } - private query_sempred(_localctx: QueryContext, predIndex: number): boolean { - switch (predIndex) { - case 0: - return this.precpred(this._ctx, 1); + // @RuleVersion(0) + public functionIdentifier(): FunctionIdentifierContext { + let _localctx: FunctionIdentifierContext = new FunctionIdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 68, esql_parser.RULE_functionIdentifier); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 447; + this.match(esql_parser.UNARY_FUNCTION); + } } - return true; - } - private booleanExpression_sempred(_localctx: BooleanExpressionContext, predIndex: number): boolean { - switch (predIndex) { - case 1: - return this.precpred(this._ctx, 2); - - case 2: - return this.precpred(this._ctx, 1); + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } } - return true; - } - private operatorExpression_sempred(_localctx: OperatorExpressionContext, predIndex: number): boolean { - switch (predIndex) { - case 3: - return this.precpred(this._ctx, 2); - - case 4: - return this.precpred(this._ctx, 1); + finally { + this.exitRule(); } - return true; + return _localctx; } + // @RuleVersion(0) + public constant(): ConstantContext { + let _localctx: ConstantContext = new ConstantContext(this._ctx, this.state); + this.enterRule(_localctx, 70, esql_parser.RULE_constant); + let _la: number; + try { + this.state = 486; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 47, this._ctx) ) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 449; + this.match(esql_parser.NULL); + } + break; - public static readonly _serializedATN: string = - "\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x033\u0133\x04\x02" + - "\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04\x07" + - "\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f\t\f\x04\r\t\r\x04" + - "\x0E\t\x0E\x04\x0F\t\x0F\x04\x10\t\x10\x04\x11\t\x11\x04\x12\t\x12\x04" + - "\x13\t\x13\x04\x14\t\x14\x04\x15\t\x15\x04\x16\t\x16\x04\x17\t\x17\x04" + - "\x18\t\x18\x04\x19\t\x19\x04\x1A\t\x1A\x04\x1B\t\x1B\x04\x1C\t\x1C\x04" + - "\x1D\t\x1D\x04\x1E\t\x1E\x04\x1F\t\x1F\x04 \t \x04!\t!\x04\"\t\"\x04#" + - "\t#\x04$\t$\x04%\t%\x03\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03\x03\x03" + - "\x03\x03\x03\x03\x03\x07\x03T\n\x03\f\x03\x0E\x03W\v\x03\x03\x04\x03\x04" + - "\x03\x04\x05\x04\\\n\x04\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05" + - "\x05\x05d\n\x05\x03\x06\x03\x06\x03\x06\x03\x07\x03\x07\x03\x07\x03\x07" + - "\x05\x07m\n\x07\x03\x07\x03\x07\x03\x07\x03\x07\x03\x07\x03\x07\x07\x07" + - "u\n\x07\f\x07\x0E\x07x\v\x07\x03\b\x03\b\x05\b|\n\b\x03\t\x03\t\x03\t" + - "\x03\t\x03\n\x03\n\x03\n\x03\n\x03\n\x07\n\x87\n\n\f\n\x0E\n\x8A\v\n\x05" + - "\n\x8C\n\n\x03\n\x03\n\x03\v\x03\v\x03\v\x03\v\x03\v\x05\v\x95\n\v\x03" + - "\v\x03\v\x03\v\x03\v\x03\v\x03\v\x07\v\x9D\n\v\f\v\x0E\v\xA0\v\v\x03\f" + - "\x03\f\x03\f\x03\f\x03\f\x03\f\x03\f\x03\f\x03\f\x03\f\x03\f\x07\f\xAD" + - "\n\f\f\f\x0E\f\xB0\v\f\x05\f\xB2\n\f\x03\f\x03\f\x05\f\xB6\n\f\x03\r\x03" + - "\r\x03\r\x03\x0E\x03\x0E\x03\x0E\x07\x0E\xBE\n\x0E\f\x0E\x0E\x0E\xC1\v" + - "\x0E\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x05\x0F\xC8\n\x0F\x03\x10" + - "\x03\x10\x03\x11\x03\x11\x03\x11\x03\x11\x07\x11\xD0\n\x11\f\x11\x0E\x11" + - "\xD3\v\x11\x03\x12\x03\x12\x03\x12\x03\x13\x03\x13\x03\x13\x03\x13\x05" + - "\x13\xDC\n\x13\x03\x14\x03\x14\x03\x15\x03\x15\x05\x15\xE2\n\x15\x03\x16" + - "\x03\x16\x03\x16\x07\x16\xE7\n\x16\f\x16\x0E\x16\xEA\v\x16\x03\x17\x03" + - "\x17\x03\x17\x07\x17\xEF\n\x17\f\x17\x0E\x17\xF2\v\x17\x03\x18\x03\x18" + - "\x03\x19\x03\x19\x03\x1A\x03\x1A\x03\x1A\x03\x1A\x05\x1A\xFC\n\x1A\x03" + - "\x1B\x03\x1B\x03\x1B\x03\x1C\x03\x1C\x03\x1C\x03\x1C\x07\x1C\u0105\n\x1C" + - "\f\x1C\x0E\x1C\u0108\v\x1C\x03\x1D\x03\x1D\x05\x1D\u010C\n\x1D\x03\x1D" + - "\x03\x1D\x05\x1D\u0110\n\x1D\x03\x1E\x03\x1E\x03\x1E\x03\x1E\x07\x1E\u0116" + - "\n\x1E\f\x1E\x0E\x1E\u0119\v\x1E\x03\x1F\x03\x1F\x03\x1F\x03\x1F\x03\x1F" + - "\x05\x1F\u0120\n\x1F\x03 \x03 \x03!\x03!\x05!\u0126\n!\x03\"\x03\"\x03" + - "#\x03#\x03$\x03$\x03$\x03%\x03%\x03%\x03%\x03%\x02\x02\x05\x04\f\x14&" + - "\x02\x02\x04\x02\x06\x02\b\x02\n\x02\f\x02\x0E\x02\x10\x02\x12\x02\x14" + - "\x02\x16\x02\x18\x02\x1A\x02\x1C\x02\x1E\x02 \x02\"\x02$\x02&\x02(\x02" + - "*\x02,\x02.\x020\x022\x024\x026\x028\x02:\x02<\x02>\x02@\x02B\x02D\x02" + - "F\x02H\x02\x02\x06\x03\x02!\"\x03\x02#%\x03\x02/0\x03\x02*+\x02\u0135" + - "\x02J\x03\x02\x02\x02\x04M\x03\x02\x02\x02\x06[\x03\x02\x02\x02\bc\x03" + - "\x02\x02\x02\ne\x03\x02\x02\x02\fl\x03\x02\x02\x02\x0E{\x03\x02\x02\x02" + - "\x10}\x03\x02\x02\x02\x12\x81\x03\x02\x02\x02\x14\x94\x03\x02\x02\x02" + - "\x16\xB5\x03\x02\x02\x02\x18\xB7\x03\x02\x02\x02\x1A\xBA\x03\x02\x02\x02" + - "\x1C\xC7\x03\x02\x02\x02\x1E\xC9\x03\x02\x02\x02 \xCB\x03\x02\x02\x02" + - "\"\xD4\x03\x02\x02\x02$\xD7\x03\x02\x02\x02&\xDD\x03\x02\x02\x02(\xE1" + - "\x03\x02\x02\x02*\xE3\x03\x02\x02\x02,\xEB\x03\x02\x02\x02.\xF3\x03\x02" + - "\x02\x020\xF5\x03\x02\x02\x022\xFB\x03\x02\x02\x024\xFD\x03\x02\x02\x02" + - "6\u0100\x03\x02\x02\x028\u0109\x03\x02\x02\x02:\u0111\x03\x02\x02\x02" + - "<\u011F\x03\x02\x02\x02>\u0121\x03\x02\x02\x02@\u0125\x03\x02\x02\x02" + - "B\u0127\x03\x02\x02\x02D\u0129\x03\x02\x02\x02F\u012B\x03\x02\x02\x02" + - "H\u012E\x03\x02\x02\x02JK\x05\x04\x03\x02KL\x07\x02\x02\x03L\x03\x03\x02" + - "\x02\x02MN\b\x03\x01\x02NO\x05\x06\x04\x02OU\x03\x02\x02\x02PQ\f\x03\x02" + - "\x02QR\x07\x0F\x02\x02RT\x05\b\x05\x02SP\x03\x02\x02\x02TW\x03\x02\x02" + - "\x02US\x03\x02\x02\x02UV\x03\x02\x02\x02V\x05\x03\x02\x02\x02WU\x03\x02" + - "\x02\x02X\\\x05F$\x02Y\\\x05 \x11\x02Z\\\x05\x18\r\x02[X\x03\x02\x02\x02" + - "[Y\x03\x02\x02\x02[Z\x03\x02\x02\x02\\\x07\x03\x02\x02\x02]d\x05\"\x12" + - "\x02^d\x054\x1B\x02_d\x05:\x1E\x02`d\x056\x1C\x02ad\x05$\x13\x02bd\x05" + - "\n\x06\x02c]\x03\x02\x02\x02c^\x03\x02\x02\x02c_\x03\x02\x02\x02c`\x03" + - "\x02\x02\x02ca\x03\x02\x02\x02cb\x03\x02\x02\x02d\t\x03\x02\x02\x02ef" + - "\x07\b\x02\x02fg\x05\f\x07\x02g\v\x03\x02\x02\x02hi\b\x07\x01\x02ij\x07" + - "\x1B\x02\x02jm\x05\f\x07\x06km\x05\x0E\b\x02lh\x03\x02\x02\x02lk\x03\x02" + - "\x02\x02mv\x03\x02\x02\x02no\f\x04\x02\x02op\x07\x14\x02\x02pu\x05\f\x07" + - "\x05qr\f\x03\x02\x02rs\x07\x1D\x02\x02su\x05\f\x07\x04tn\x03\x02\x02\x02" + - "tq\x03\x02\x02\x02ux\x03\x02\x02\x02vt\x03\x02\x02\x02vw\x03\x02\x02\x02" + - "w\r\x03\x02\x02\x02xv\x03\x02\x02\x02y|\x05\x14\v\x02z|\x05\x10\t\x02" + - "{y\x03\x02\x02\x02{z\x03\x02\x02\x02|\x0F\x03\x02\x02\x02}~\x05\x14\v" + - "\x02~\x7F\x05D#\x02\x7F\x80\x05\x14\v\x02\x80\x11\x03\x02\x02\x02\x81" + - "\x82\x050\x19\x02\x82\x8B\x07\x18\x02\x02\x83\x88\x05(\x15\x02\x84\x85" + - "\x07\x16\x02\x02\x85\x87\x05(\x15\x02\x86\x84\x03\x02\x02\x02\x87\x8A" + - "\x03\x02\x02\x02\x88\x86\x03\x02\x02\x02\x88\x89\x03\x02\x02\x02\x89\x8C" + - "\x03\x02\x02\x02\x8A\x88\x03\x02\x02\x02\x8B\x83\x03\x02\x02\x02\x8B\x8C" + - "\x03\x02\x02\x02\x8C\x8D\x03\x02\x02\x02\x8D\x8E\x07\x1E\x02\x02\x8E\x13" + - "\x03\x02\x02\x02\x8F\x90\b\v\x01\x02\x90\x95\x05\x16\f\x02\x91\x95\x05" + - "\x12\n\x02\x92\x93\t\x02\x02\x02\x93\x95\x05\x14\v\x05\x94\x8F\x03\x02" + - "\x02\x02\x94\x91\x03\x02\x02\x02\x94\x92\x03\x02\x02\x02\x95\x9E\x03\x02" + - "\x02\x02\x96\x97\f\x04\x02\x02\x97\x98\t\x03\x02\x02\x98\x9D\x05\x14\v" + - "\x05\x99\x9A\f\x03\x02\x02\x9A\x9B\t\x02\x02\x02\x9B\x9D\x05\x14\v\x04" + - "\x9C\x96\x03\x02\x02\x02\x9C\x99\x03\x02\x02\x02\x9D\xA0\x03\x02\x02\x02" + - "\x9E\x9C\x03\x02\x02\x02\x9E\x9F\x03\x02\x02\x02\x9F\x15\x03\x02\x02\x02" + - "\xA0\x9E\x03\x02\x02\x02\xA1\xB6\x052\x1A\x02\xA2\xB6\x05*\x16\x02\xA3" + - "\xA4\x07\x18\x02\x02\xA4\xA5\x05\f\x07\x02\xA5\xA6\x07\x1E\x02\x02\xA6" + - "\xB6\x03\x02\x02\x02\xA7\xA8\x05.\x18\x02\xA8\xB1\x07\x18\x02\x02\xA9" + - "\xAE\x05\f\x07\x02\xAA\xAB\x07\x16\x02\x02\xAB\xAD\x05\f\x07\x02\xAC\xAA" + - "\x03\x02\x02\x02\xAD\xB0\x03\x02\x02\x02\xAE\xAC\x03\x02\x02\x02\xAE\xAF" + - "\x03\x02\x02\x02\xAF\xB2\x03\x02\x02\x02\xB0\xAE\x03\x02\x02\x02\xB1\xA9" + - "\x03\x02\x02\x02\xB1\xB2\x03\x02\x02\x02\xB2\xB3\x03\x02\x02\x02\xB3\xB4" + - "\x07\x1E\x02\x02\xB4\xB6\x03\x02\x02\x02\xB5\xA1\x03\x02\x02\x02\xB5\xA2" + - "\x03\x02\x02\x02\xB5\xA3\x03\x02\x02\x02\xB5\xA7\x03\x02\x02\x02\xB6\x17" + - "\x03\x02\x02\x02\xB7\xB8\x07\x06\x02\x02\xB8\xB9\x05\x1A\x0E\x02\xB9\x19" + - "\x03\x02\x02\x02\xBA\xBF\x05\x1C\x0F\x02\xBB\xBC\x07\x16\x02\x02\xBC\xBE" + - "\x05\x1C\x0F\x02\xBD\xBB\x03\x02\x02\x02\xBE\xC1\x03\x02\x02\x02\xBF\xBD" + - "\x03\x02\x02\x02\xBF\xC0\x03\x02\x02\x02\xC0\x1B\x03\x02\x02\x02\xC1\xBF" + - "\x03\x02\x02\x02\xC2\xC8\x05\f\x07\x02\xC3\xC4\x05\x1E\x10\x02\xC4\xC5" + - "\x07\x15\x02\x02\xC5\xC6\x05\f\x07\x02\xC6\xC8\x03\x02\x02\x02\xC7\xC2" + - "\x03\x02\x02\x02\xC7\xC3\x03\x02\x02\x02\xC8\x1D\x03\x02\x02\x02\xC9\xCA" + - "\x05.\x18\x02\xCA\x1F\x03\x02\x02\x02\xCB\xCC\x07\x05\x02\x02\xCC\xD1" + - "\x05&\x14\x02\xCD\xCE\x07\x16\x02\x02\xCE\xD0\x05&\x14\x02\xCF\xCD\x03" + - "\x02\x02\x02\xD0\xD3\x03\x02\x02\x02\xD1\xCF\x03\x02\x02\x02\xD1\xD2\x03" + - "\x02\x02\x02\xD2!\x03\x02\x02\x02\xD3\xD1\x03\x02\x02\x02\xD4\xD5\x07" + - "\x03\x02\x02\xD5\xD6\x05\x1A\x0E\x02\xD6#\x03\x02\x02\x02\xD7\xD8\x07" + - "\x07\x02\x02\xD8\xDB\x05\x1A\x0E\x02\xD9\xDA\x07\x13\x02\x02\xDA\xDC\x05" + - ",\x17\x02\xDB\xD9\x03\x02\x02\x02\xDB\xDC\x03\x02\x02\x02\xDC%\x03\x02" + - "\x02\x02\xDD\xDE\t\x04\x02\x02\xDE\'\x03\x02\x02\x02\xDF\xE2\x05*\x16" + - "\x02\xE0\xE2\x05B\"\x02\xE1\xDF\x03\x02\x02\x02\xE1\xE0\x03\x02\x02\x02" + - "\xE2)\x03\x02\x02\x02\xE3\xE8\x05.\x18\x02\xE4\xE5\x07\x17\x02\x02\xE5" + - "\xE7\x05.\x18\x02\xE6\xE4\x03\x02\x02\x02\xE7\xEA\x03\x02\x02\x02\xE8" + - "\xE6\x03\x02\x02\x02\xE8\xE9\x03\x02\x02\x02\xE9+\x03\x02\x02\x02\xEA" + - "\xE8\x03\x02\x02\x02\xEB\xF0\x05*\x16\x02\xEC\xED\x07\x16\x02\x02\xED" + - "\xEF\x05*\x16\x02\xEE\xEC\x03\x02\x02\x02\xEF\xF2\x03\x02\x02\x02\xF0" + - "\xEE\x03\x02\x02\x02\xF0\xF1\x03\x02\x02\x02\xF1-\x03\x02\x02\x02\xF2" + - "\xF0\x03\x02\x02\x02\xF3\xF4\t\x05\x02\x02\xF4/\x03\x02\x02\x02\xF5\xF6" + - "\x07)\x02\x02\xF61\x03\x02\x02\x02\xF7\xFC\x07\x1C\x02\x02\xF8\xFC\x05" + - "@!\x02\xF9\xFC\x05> \x02\xFA\xFC\x05B\"\x02\xFB\xF7\x03\x02\x02\x02\xFB" + - "\xF8\x03\x02\x02\x02\xFB\xF9\x03\x02\x02\x02\xFB\xFA\x03\x02\x02\x02\xFC" + - "3\x03\x02\x02\x02\xFD\xFE\x07\n\x02\x02\xFE\xFF\x07\x11\x02\x02\xFF5\x03" + - "\x02\x02\x02\u0100\u0101\x07\t\x02\x02\u0101\u0106\x058\x1D\x02\u0102" + - "\u0103\x07\x16\x02\x02\u0103\u0105\x058\x1D\x02\u0104\u0102\x03\x02\x02" + - "\x02\u0105\u0108\x03\x02\x02\x02\u0106\u0104\x03\x02\x02\x02\u0106\u0107" + - "\x03\x02\x02\x02\u01077\x03\x02\x02\x02\u0108\u0106\x03\x02\x02\x02\u0109" + - "\u010B\x05\f\x07\x02\u010A\u010C\x07&\x02\x02\u010B\u010A\x03\x02\x02" + - "\x02\u010B\u010C\x03\x02\x02\x02\u010C\u010F\x03\x02\x02\x02\u010D\u010E" + - "\x07\'\x02\x02\u010E\u0110\x07(\x02\x02\u010F\u010D\x03\x02\x02\x02\u010F" + - "\u0110\x03\x02\x02\x02\u01109\x03\x02\x02\x02\u0111\u0112\x07\v\x02\x02" + - "\u0112\u0117\x05<\x1F\x02\u0113\u0114\x07\x16\x02\x02\u0114\u0116\x05" + - "<\x1F\x02\u0115\u0113\x03\x02\x02\x02\u0116\u0119\x03\x02\x02\x02\u0117" + - "\u0115\x03\x02\x02\x02\u0117\u0118\x03\x02\x02\x02\u0118;\x03\x02\x02" + - "\x02\u0119\u0117\x03\x02\x02\x02\u011A\u0120\x05&\x14\x02\u011B\u011C" + - "\x05&\x14\x02\u011C\u011D\x07\x15\x02\x02\u011D\u011E\x05&\x14\x02\u011E" + - "\u0120\x03\x02\x02\x02\u011F\u011A\x03\x02\x02\x02\u011F\u011B\x03\x02" + - "\x02\x02\u0120=\x03\x02\x02\x02\u0121\u0122\x07\x1F\x02\x02\u0122?\x03" + - "\x02\x02\x02\u0123\u0126\x07\x12\x02\x02\u0124\u0126\x07\x11\x02\x02\u0125" + - "\u0123\x03\x02\x02\x02\u0125\u0124\x03\x02\x02\x02\u0126A\x03\x02\x02" + - "\x02\u0127\u0128\x07\x10\x02\x02\u0128C\x03\x02\x02\x02\u0129\u012A\x07" + - " \x02\x02\u012AE\x03\x02\x02\x02\u012B\u012C\x07\x04\x02\x02\u012C\u012D" + - "\x05H%\x02\u012DG\x03\x02\x02\x02\u012E\u012F\x07\x19\x02\x02\u012F\u0130" + - "\x05\x04\x03\x02\u0130\u0131\x07\x1A\x02\x02\u0131I\x03\x02\x02\x02\x1F" + - "U[cltv{\x88\x8B\x94\x9C\x9E\xAE\xB1\xB5\xBF\xC7\xD1\xDB\xE1\xE8\xF0\xFB" + - "\u0106\u010B\u010F\u0117\u011F\u0125"; - public static __ATN: ATN; - public static get _ATN(): ATN { - if (!esql_parser.__ATN) { - esql_parser.__ATN = new ATNDeserializer().deserialize(Utils.toCharArray(esql_parser._serializedATN)); - } + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 450; + this.numericValue(); + } + break; - return esql_parser.__ATN; - } + case 3: + this.enterOuterAlt(_localctx, 3); + { + this.state = 451; + this.booleanValue(); + } + break; + case 4: + this.enterOuterAlt(_localctx, 4); + { + this.state = 452; + this.string(); + } + break; + + case 5: + this.enterOuterAlt(_localctx, 5); + { + this.state = 453; + this.match(esql_parser.OPENING_BRACKET); + this.state = 454; + this.numericValue(); + this.state = 459; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 455; + this.match(esql_parser.COMMA); + this.state = 456; + this.numericValue(); + } + } + this.state = 461; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + this.state = 462; + this.match(esql_parser.CLOSING_BRACKET); + } + break; + + case 6: + this.enterOuterAlt(_localctx, 6); + { + this.state = 464; + this.match(esql_parser.OPENING_BRACKET); + this.state = 465; + this.booleanValue(); + this.state = 470; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 466; + this.match(esql_parser.COMMA); + this.state = 467; + this.booleanValue(); + } + } + this.state = 472; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + this.state = 473; + this.match(esql_parser.CLOSING_BRACKET); + } + break; + + case 7: + this.enterOuterAlt(_localctx, 7); + { + this.state = 475; + this.match(esql_parser.OPENING_BRACKET); + this.state = 476; + this.string(); + this.state = 481; + this._errHandler.sync(this); + _la = this._input.LA(1); + while (_la === esql_parser.COMMA) { + { + { + this.state = 477; + this.match(esql_parser.COMMA); + this.state = 478; + this.string(); + } + } + this.state = 483; + this._errHandler.sync(this); + _la = this._input.LA(1); + } + this.state = 484; + this.match(esql_parser.CLOSING_BRACKET); + } + break; + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public numericValue(): NumericValueContext { + let _localctx: NumericValueContext = new NumericValueContext(this._ctx, this.state); + this.enterRule(_localctx, 72, esql_parser.RULE_numericValue); + try { + this.state = 490; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case esql_parser.DECIMAL_LITERAL: + this.enterOuterAlt(_localctx, 1); + { + this.state = 488; + this.decimalValue(); + } + break; + case esql_parser.INTEGER_LITERAL: + this.enterOuterAlt(_localctx, 2); + { + this.state = 489; + this.integerValue(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public limitCommand(): LimitCommandContext { + let _localctx: LimitCommandContext = new LimitCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 74, esql_parser.RULE_limitCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 492; + this.match(esql_parser.LIMIT); + this.state = 493; + this.match(esql_parser.INTEGER_LITERAL); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public sortCommand(): SortCommandContext { + let _localctx: SortCommandContext = new SortCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 76, esql_parser.RULE_sortCommand); + try { + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 495; + this.match(esql_parser.SORT); + this.state = 496; + this.orderExpression(); + this.state = 501; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 49, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 497; + this.match(esql_parser.COMMA); + this.state = 498; + this.orderExpression(); + } + } + } + this.state = 503; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 49, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public orderExpression(): OrderExpressionContext { + let _localctx: OrderExpressionContext = new OrderExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 78, esql_parser.RULE_orderExpression); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 504; + this.booleanExpression(0); + this.state = 506; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 50, this._ctx) ) { + case 1: + { + this.state = 505; + this.match(esql_parser.ORDERING); + } + break; + } + this.state = 510; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 51, this._ctx) ) { + case 1: + { + this.state = 508; + this.match(esql_parser.NULLS_ORDERING); + { + this.state = 509; + this.match(esql_parser.NULLS_ORDERING_DIRECTION); + } + } + break; + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public projectCommand(): ProjectCommandContext { + let _localctx: ProjectCommandContext = new ProjectCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 80, esql_parser.RULE_projectCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 512; + this.match(esql_parser.PROJECT); + this.state = 513; + this.qualifiedNames(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public keepCommand(): KeepCommandContext { + let _localctx: KeepCommandContext = new KeepCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 82, esql_parser.RULE_keepCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 515; + this.match(esql_parser.KEEP); + this.state = 516; + this.qualifiedNames(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public dropCommand(): DropCommandContext { + let _localctx: DropCommandContext = new DropCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 84, esql_parser.RULE_dropCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 518; + this.match(esql_parser.DROP); + this.state = 519; + this.qualifiedNames(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public renameVariable(): RenameVariableContext { + let _localctx: RenameVariableContext = new RenameVariableContext(this._ctx, this.state); + this.enterRule(_localctx, 86, esql_parser.RULE_renameVariable); + try { + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 521; + this.identifier(); + this.state = 526; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 52, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 522; + this.match(esql_parser.DOT); + this.state = 523; + this.identifier(); + } + } + } + this.state = 528; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 52, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public renameCommand(): RenameCommandContext { + let _localctx: RenameCommandContext = new RenameCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 88, esql_parser.RULE_renameCommand); + try { + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 529; + this.match(esql_parser.RENAME); + this.state = 530; + this.renameClause(); + this.state = 535; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 53, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 531; + this.match(esql_parser.COMMA); + this.state = 532; + this.renameClause(); + } + } + } + this.state = 537; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 53, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public renameClause(): RenameClauseContext { + let _localctx: RenameClauseContext = new RenameClauseContext(this._ctx, this.state); + this.enterRule(_localctx, 90, esql_parser.RULE_renameClause); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 538; + this.qualifiedName(); + this.state = 539; + this.match(esql_parser.AS); + this.state = 540; + this.renameVariable(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public dissectCommand(): DissectCommandContext { + let _localctx: DissectCommandContext = new DissectCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 92, esql_parser.RULE_dissectCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 542; + this.match(esql_parser.DISSECT); + this.state = 543; + this.qualifiedNames(); + this.state = 544; + this.string(); + this.state = 546; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 54, this._ctx) ) { + case 1: + { + this.state = 545; + this.commandOptions(); + } + break; + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public grokCommand(): GrokCommandContext { + let _localctx: GrokCommandContext = new GrokCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 94, esql_parser.RULE_grokCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 548; + this.match(esql_parser.GROK); + this.state = 549; + this.qualifiedNames(); + this.state = 550; + this.string(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public commandOptions(): CommandOptionsContext { + let _localctx: CommandOptionsContext = new CommandOptionsContext(this._ctx, this.state); + this.enterRule(_localctx, 96, esql_parser.RULE_commandOptions); + try { + let _alt: number; + this.enterOuterAlt(_localctx, 1); + { + this.state = 552; + this.commandOption(); + this.state = 557; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 55, this._ctx); + while (_alt !== 2 && _alt !== ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + { + { + this.state = 553; + this.match(esql_parser.COMMA); + this.state = 554; + this.commandOption(); + } + } + } + this.state = 559; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 55, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public commandOption(): CommandOptionContext { + let _localctx: CommandOptionContext = new CommandOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 98, esql_parser.RULE_commandOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 560; + this.identifier(); + this.state = 561; + this.match(esql_parser.ASSIGN); + this.state = 562; + this.constant(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public booleanValue(): BooleanValueContext { + let _localctx: BooleanValueContext = new BooleanValueContext(this._ctx, this.state); + this.enterRule(_localctx, 100, esql_parser.RULE_booleanValue); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 564; + this.match(esql_parser.BOOLEAN_VALUE); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public number(): NumberContext { + let _localctx: NumberContext = new NumberContext(this._ctx, this.state); + this.enterRule(_localctx, 102, esql_parser.RULE_number); + try { + this.state = 568; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case esql_parser.DECIMAL_LITERAL: + _localctx = new DecimalLiteralContext(_localctx); + this.enterOuterAlt(_localctx, 1); + { + this.state = 566; + this.match(esql_parser.DECIMAL_LITERAL); + } + break; + case esql_parser.INTEGER_LITERAL: + _localctx = new IntegerLiteralContext(_localctx); + this.enterOuterAlt(_localctx, 2); + { + this.state = 567; + this.match(esql_parser.INTEGER_LITERAL); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public decimalValue(): DecimalValueContext { + let _localctx: DecimalValueContext = new DecimalValueContext(this._ctx, this.state); + this.enterRule(_localctx, 104, esql_parser.RULE_decimalValue); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 570; + this.match(esql_parser.DECIMAL_LITERAL); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public integerValue(): IntegerValueContext { + let _localctx: IntegerValueContext = new IntegerValueContext(this._ctx, this.state); + this.enterRule(_localctx, 106, esql_parser.RULE_integerValue); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 572; + this.match(esql_parser.INTEGER_LITERAL); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public string(): StringContext { + let _localctx: StringContext = new StringContext(this._ctx, this.state); + this.enterRule(_localctx, 108, esql_parser.RULE_string); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 574; + this.match(esql_parser.STRING); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public comparisonOperator(): ComparisonOperatorContext { + let _localctx: ComparisonOperatorContext = new ComparisonOperatorContext(this._ctx, this.state); + this.enterRule(_localctx, 110, esql_parser.RULE_comparisonOperator); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 576; + this.match(esql_parser.COMPARISON_OPERATOR); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public explainCommand(): ExplainCommandContext { + let _localctx: ExplainCommandContext = new ExplainCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 112, esql_parser.RULE_explainCommand); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 578; + this.match(esql_parser.EXPLAIN); + this.state = 579; + this.subqueryExpression(); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public subqueryExpression(): SubqueryExpressionContext { + let _localctx: SubqueryExpressionContext = new SubqueryExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 114, esql_parser.RULE_subqueryExpression); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 581; + this.match(esql_parser.OPENING_BRACKET); + this.state = 582; + this.query(0); + this.state = 583; + this.match(esql_parser.CLOSING_BRACKET); + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + public showCommand(): ShowCommandContext { + let _localctx: ShowCommandContext = new ShowCommandContext(this._ctx, this.state); + this.enterRule(_localctx, 116, esql_parser.RULE_showCommand); + try { + this.state = 589; + this._errHandler.sync(this); + switch ( this.interpreter.adaptivePredict(this._input, 57, this._ctx) ) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 585; + this.match(esql_parser.SHOW); + this.state = 586; + this.match(esql_parser.INFO); + } + break; + + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 587; + this.match(esql_parser.SHOW); + this.state = 588; + this.match(esql_parser.FUNCTIONS); + } + break; + } + } + catch (re) { + if (re instanceof RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + + public sempred(_localctx: RuleContext, ruleIndex: number, predIndex: number): boolean { + switch (ruleIndex) { + case 1: + return this.query_sempred(_localctx as QueryContext, predIndex); + + case 8: + return this.whereBooleanExpression_sempred(_localctx as WhereBooleanExpressionContext, predIndex); + + case 9: + return this.booleanExpression_sempred(_localctx as BooleanExpressionContext, predIndex); + + case 15: + return this.operatorExpression_sempred(_localctx as OperatorExpressionContext, predIndex); + } + return true; + } + private query_sempred(_localctx: QueryContext, predIndex: number): boolean { + switch (predIndex) { + case 0: + return this.precpred(this._ctx, 1); + } + return true; + } + private whereBooleanExpression_sempred(_localctx: WhereBooleanExpressionContext, predIndex: number): boolean { + switch (predIndex) { + case 1: + return this.precpred(this._ctx, 5); + + case 2: + return this.precpred(this._ctx, 4); + } + return true; + } + private booleanExpression_sempred(_localctx: BooleanExpressionContext, predIndex: number): boolean { + switch (predIndex) { + case 3: + return this.precpred(this._ctx, 2); + + case 4: + return this.precpred(this._ctx, 1); + } + return true; + } + private operatorExpression_sempred(_localctx: OperatorExpressionContext, predIndex: number): boolean { + switch (predIndex) { + case 5: + return this.precpred(this._ctx, 2); + + case 6: + return this.precpred(this._ctx, 1); + } + return true; + } + + private static readonly _serializedATNSegments: number = 2; + private static readonly _serializedATNSegment0: string = + "\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x03S\u0252\x04\x02" + + "\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04\x07" + + "\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f\t\f\x04\r\t\r\x04" + + "\x0E\t\x0E\x04\x0F\t\x0F\x04\x10\t\x10\x04\x11\t\x11\x04\x12\t\x12\x04" + + "\x13\t\x13\x04\x14\t\x14\x04\x15\t\x15\x04\x16\t\x16\x04\x17\t\x17\x04" + + "\x18\t\x18\x04\x19\t\x19\x04\x1A\t\x1A\x04\x1B\t\x1B\x04\x1C\t\x1C\x04" + + "\x1D\t\x1D\x04\x1E\t\x1E\x04\x1F\t\x1F\x04 \t \x04!\t!\x04\"\t\"\x04#" + + "\t#\x04$\t$\x04%\t%\x04&\t&\x04\'\t\'\x04(\t(\x04)\t)\x04*\t*\x04+\t+" + + "\x04,\t,\x04-\t-\x04.\t.\x04/\t/\x040\t0\x041\t1\x042\t2\x043\t3\x044" + + "\t4\x045\t5\x046\t6\x047\t7\x048\t8\x049\t9\x04:\t:\x04;\t;\x04<\t<\x03" + + "\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x07" + + "\x03\x82\n\x03\f\x03\x0E\x03\x85\v\x03\x03\x04\x03\x04\x03\x04\x03\x04" + + "\x05\x04\x8B\n\x04\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03" + + "\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x05\x05\x9A\n\x05" + + "\x03\x06\x03\x06\x03\x06\x03\x06\x05\x06\xA0\n\x06\x03\x06\x03\x06\x03" + + "\x06\x03\x06\x07\x06\xA6\n\x06\f\x06\x0E\x06\xA9\v\x06\x05\x06\xAB\n\x06" + + "\x03\x07\x03\x07\x03\x07\x05\x07\xB0\n\x07\x03\x07\x03\x07\x03\b\x03\b" + + "\x03\b\x03\t\x03\t\x03\t\x03\n\x03\n\x03\n\x03\n\x03\n\x03\n\x03\n\x05" + + "\n\xC1\n\n\x03\n\x03\n\x03\n\x03\n\x03\n\x07\n\xC8\n\n\f\n\x0E\n\xCB\v" + + "\n\x03\n\x03\n\x03\n\x05\n\xD0\n\n\x03\n\x03\n\x03\n\x03\n\x03\n\x07\n" + + "\xD7\n\n\f\n\x0E\n\xDA\v\n\x05\n\xDC\n\n\x03\n\x03\n\x03\n\x03\n\x03\n" + + "\x05\n\xE3\n\n\x03\n\x03\n\x05\n\xE7\n\n\x03\n\x03\n\x03\n\x03\n\x03\n" + + "\x03\n\x07\n\xEF\n\n\f\n\x0E\n\xF2\v\n\x03\v\x03\v\x03\v\x03\v\x05\v\xF8" + + "\n\v\x03\v\x03\v\x03\v\x03\v\x03\v\x03\v\x07\v\u0100\n\v\f\v\x0E\v\u0103" + + "\v\v\x03\f\x03\f\x05\f\u0107\n\f\x03\f\x03\f\x03\f\x03\f\x03\f\x05\f\u010E" + + "\n\f\x03\f\x03\f\x03\f\x05\f\u0113\n\f\x03\r\x03\r\x05\r\u0117\n\r\x03" + + "\x0E\x03\x0E\x03\x0E\x03\x0E\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x07" + + "\x0F\u0122\n\x0F\f\x0F\x0E\x0F\u0125\v\x0F\x05\x0F\u0127\n\x0F\x03\x0F" + + "\x03\x0F\x03\x10\x03\x10\x03\x10\x03\x10\x03\x10\x07\x10\u0130\n\x10\f" + + "\x10\x0E\x10\u0133\v\x10\x05\x10\u0135\n\x10\x03\x10\x03\x10\x03\x11\x03" + + "\x11\x03\x11\x03\x11\x03\x11\x03\x11\x05\x11\u013F\n\x11\x03\x11\x03\x11" + + "\x03\x11\x03\x11\x03\x11\x03\x11\x07\x11\u0147\n\x11\f\x11\x0E\x11\u014A" + + "\v\x11\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12" + + "\x03\x12\x03\x12\x03\x12\x07\x12\u0157\n\x12\f\x12\x0E\x12\u015A\v\x12" + + "\x05\x12\u015C\n\x12\x03\x12\x03\x12\x05\x12\u0160\n\x12\x03\x13\x03\x13" + + "\x03\x13\x03\x14\x03\x14\x03\x14\x07\x14\u0168\n\x14\f\x14\x0E\x14\u016B" + + "\v\x14\x03\x15\x03\x15\x03\x15\x03\x15\x03\x15\x05\x15\u0172\n\x15\x03" + + "\x16\x03\x16\x03\x17\x03\x17\x03\x18\x03\x18\x03\x18\x03\x18\x07\x18\u017C" + + "\n\x18\f\x18\x0E\x18\u017F\v\x18\x03\x18\x05\x18\u0182\n\x18\x03\x19\x03" + + "\x19\x03\x19\x03\x19\x03\x19\x07\x19\u0189\n\x19\f\x19\x0E\x19\u018C\v" + + "\x19\x03\x19\x03\x19\x03\x1A\x03\x1A\x03\x1A\x03\x1B\x03\x1B\x05\x1B\u0195" + + "\n\x1B\x03\x1B\x03\x1B\x05\x1B\u0199\n\x1B\x03\x1C\x03\x1C\x03\x1D\x03" + + "\x1D\x03\x1E\x03\x1E\x03\x1E\x05\x1E\u01A2\n\x1E\x03\x1F\x03\x1F\x03\x1F" + + "\x03\x1F\x03\x1F\x03\x1F\x03\x1F\x03\x1F\x05\x1F\u01AC\n\x1F\x03 \x03" + + " \x03 \x07 \u01B1\n \f \x0E \u01B4\v \x03!\x03!\x03!\x07!\u01B9\n!\f!" + + "\x0E!\u01BC\v!\x03\"\x03\"\x03#\x03#\x03$\x03$\x03%\x03%\x03%\x03%\x03" + + "%\x03%\x03%\x03%\x07%\u01CC\n%\f%\x0E%\u01CF\v%\x03%\x03%\x03%\x03%\x03" + + "%\x03%\x07%\u01D7\n%\f%\x0E%\u01DA\v%\x03%\x03%\x03%\x03%\x03%\x03%\x07" + + "%\u01E2\n%\f%\x0E%\u01E5\v%\x03%\x03%\x05%\u01E9\n%\x03&\x03&\x05&\u01ED" + + "\n&\x03\'\x03\'\x03\'\x03(\x03(\x03(\x03(\x07(\u01F6\n(\f(\x0E(\u01F9" + + "\v(\x03)\x03)\x05)\u01FD\n)\x03)\x03)\x05)\u0201\n)\x03*\x03*\x03*\x03" + + "+\x03+\x03+\x03,\x03,\x03,\x03-\x03-\x03-\x07-\u020F\n-\f-\x0E-\u0212" + + "\v-\x03.\x03.\x03.\x03.\x07.\u0218\n.\f.\x0E.\u021B\v.\x03/\x03/\x03/" + + "\x03/\x030\x030\x030\x030\x050\u0225\n0\x031\x031\x031\x031\x032\x032" + + "\x032\x072\u022E\n2\f2\x0E2\u0231\v2\x033\x033\x033\x033\x034\x034\x03" + + "5\x035\x055\u023B\n5\x036\x036\x037\x037\x038\x038\x039\x039\x03:\x03" + + ":\x03:\x03;\x03;\x03;\x03;\x03<\x03<\x03<\x03<\x05<\u0250\n<\x03<\x02" + + "\x02\x06\x04\x12\x14 =\x02\x02\x04\x02\x06\x02\b\x02\n\x02\f\x02\x0E\x02" + + "\x10\x02\x12\x02\x14\x02\x16\x02\x18\x02\x1A\x02\x1C\x02\x1E\x02 \x02" + + "\"\x02$\x02&\x02(\x02*\x02,\x02.\x020\x022\x024\x026\x028\x02:\x02<\x02" + + ">\x02@\x02B\x02D\x02F\x02H\x02J\x02L\x02N\x02P\x02R\x02T\x02V\x02X\x02" + + "Z\x02\\\x02^\x02`\x02b\x02d\x02f\x02h\x02j\x02l\x02n\x02p\x02r\x02t\x02" + + "v\x02\x02\x07\x03\x0256\x03\x0279\x03\x02NO\x03\x02GH\x04\x0277AB\x02" + + "\u026F\x02x\x03\x02\x02\x02\x04{\x03\x02\x02\x02\x06\x8A\x03\x02\x02\x02" + + "\b\x99\x03\x02\x02\x02\n\x9B\x03\x02\x02\x02\f\xAF\x03\x02\x02\x02\x0E" + + "\xB3\x03\x02\x02\x02\x10\xB6\x03\x02\x02\x02\x12\xE6\x03\x02\x02\x02\x14" + + "\xF7\x03\x02\x02\x02\x16\u0112\x03\x02\x02\x02\x18\u0116\x03\x02\x02\x02" + + "\x1A\u0118\x03\x02\x02\x02\x1C\u011C\x03\x02\x02\x02\x1E\u012A\x03\x02" + + "\x02\x02 \u013E\x03\x02\x02\x02\"\u015F\x03\x02\x02\x02$\u0161\x03\x02" + + "\x02\x02&\u0164\x03\x02\x02\x02(\u0171\x03\x02\x02\x02*\u0173\x03\x02" + + "\x02\x02,\u0175\x03\x02\x02\x02.\u0177\x03\x02\x02\x020\u0183\x03\x02" + + "\x02\x022\u018F\x03\x02\x02\x024\u0192\x03\x02\x02\x026\u019A\x03\x02" + + "\x02\x028\u019C\x03\x02\x02\x02:\u01A1\x03\x02\x02\x02<\u01AB\x03\x02" + + "\x02\x02>\u01AD\x03\x02\x02\x02@\u01B5\x03\x02\x02\x02B\u01BD\x03\x02" + + "\x02\x02D\u01BF\x03\x02\x02\x02F\u01C1\x03\x02\x02\x02H\u01E8\x03\x02" + + "\x02\x02J\u01EC\x03\x02\x02\x02L\u01EE\x03\x02\x02\x02N\u01F1\x03\x02" + + "\x02\x02P\u01FA\x03\x02\x02\x02R\u0202\x03\x02\x02\x02T\u0205\x03\x02" + + "\x02\x02V\u0208\x03\x02\x02\x02X\u020B\x03\x02\x02\x02Z\u0213\x03\x02" + + "\x02\x02\\\u021C\x03\x02\x02\x02^\u0220\x03\x02\x02\x02`\u0226\x03\x02" + + "\x02\x02b\u022A\x03\x02\x02\x02d\u0232\x03\x02\x02\x02f\u0236\x03\x02" + + "\x02\x02h\u023A\x03\x02\x02\x02j\u023C\x03\x02\x02\x02l\u023E\x03\x02" + + "\x02\x02n\u0240\x03\x02\x02\x02p\u0242\x03\x02\x02\x02r\u0244\x03\x02" + + "\x02\x02t\u0247\x03\x02\x02\x02v\u024F\x03\x02\x02\x02xy\x05\x04\x03\x02" + + "yz\x07\x02\x02\x03z\x03\x03\x02\x02\x02{|\b\x03\x01\x02|}\x05\x06\x04" + + "\x02}\x83\x03\x02\x02\x02~\x7F\f\x03\x02\x02\x7F\x80\x07\x1A\x02\x02\x80" + + "\x82\x05\b\x05\x02\x81~\x03\x02\x02\x02\x82\x85\x03\x02\x02\x02\x83\x81" + + "\x03\x02\x02\x02\x83\x84\x03\x02\x02\x02\x84\x05\x03\x02\x02\x02\x85\x83" + + "\x03\x02\x02\x02\x86\x8B\x05r:\x02\x87\x8B\x05.\x18\x02\x88\x8B\x05$\x13" + + "\x02\x89\x8B\x05v<\x02\x8A\x86\x03\x02\x02\x02\x8A\x87\x03\x02\x02\x02" + + "\x8A\x88\x03\x02\x02\x02\x8A\x89\x03\x02\x02\x02\x8B\x07\x03\x02\x02\x02" + + "\x8C\x9A\x052\x1A\x02\x8D\x9A\x05L\'\x02\x8E\x9A\x05R*\x02\x8F\x9A\x05" + + "T+\x02\x90\x9A\x05Z.\x02\x91\x9A\x05V,\x02\x92\x9A\x05^0\x02\x93\x9A\x05" + + "`1\x02\x94\x9A\x05N(\x02\x95\x9A\x054\x1B\x02\x96\x9A\x05\x10\t\x02\x97" + + "\x9A\x05\x0E\b\x02\x98\x9A\x05\n\x06\x02\x99\x8C\x03\x02\x02\x02\x99\x8D" + + "\x03\x02\x02\x02\x99\x8E\x03\x02\x02\x02\x99\x8F\x03\x02\x02\x02\x99\x90" + + "\x03\x02\x02\x02\x99\x91\x03\x02\x02\x02\x99\x92\x03\x02\x02\x02\x99\x93" + + "\x03\x02\x02\x02\x99\x94\x03\x02\x02\x02\x99\x95\x03\x02\x02\x02\x99\x96" + + "\x03\x02\x02\x02\x99\x97\x03\x02\x02\x02\x99\x98\x03\x02\x02\x02\x9A\t" + + "\x03\x02\x02\x02\x9B\x9C\x07\x12\x02\x02\x9C\x9F\x058\x1D\x02\x9D\x9E" + + "\x07L\x02\x02\x9E\xA0\x05*\x16\x02\x9F\x9D\x03\x02\x02\x02\x9F\xA0\x03" + + "\x02\x02\x02\xA0\xAA\x03\x02\x02\x02\xA1\xA2\x07M\x02\x02\xA2\xA7\x05" + + "\f\x07\x02\xA3\xA4\x07\"\x02\x02\xA4\xA6\x05\f\x07\x02\xA5\xA3\x03\x02" + + "\x02\x02\xA6\xA9\x03\x02\x02\x02\xA7\xA5\x03\x02\x02\x02\xA7\xA8\x03\x02" + + "\x02\x02\xA8\xAB\x03\x02\x02\x02\xA9\xA7\x03\x02\x02\x02\xAA\xA1\x03\x02" + + "\x02\x02\xAA\xAB\x03\x02\x02\x02\xAB\v\x03\x02\x02\x02\xAC\xAD\x05*\x16" + + "\x02\xAD\xAE\x07!\x02\x02\xAE\xB0\x03\x02\x02\x02\xAF\xAC\x03\x02\x02" + + "\x02\xAF\xB0\x03\x02\x02\x02\xB0\xB1\x03\x02\x02\x02\xB1\xB2\x05*\x16" + + "\x02\xB2\r\x03\x02\x02\x02\xB3\xB4\x07\f\x02\x02\xB4\xB5\x05@!\x02\xB5" + + "\x0F\x03\x02\x02\x02\xB6\xB7\x07\n\x02\x02\xB7\xB8\x05\x12\n\x02\xB8\x11" + + "\x03\x02\x02\x02\xB9\xBA\b\n\x01\x02\xBA\xBB\x07\'\x02\x02\xBB\xE7\x05" + + "\x12\n\n\xBC\xE7\x05\x18\r\x02\xBD\xE7\x05\x16\f\x02\xBE\xC0\x05\x18\r" + + "\x02\xBF\xC1\x07\'\x02\x02\xC0\xBF\x03\x02\x02\x02\xC0\xC1\x03\x02\x02" + + "\x02\xC1\xC2\x03\x02\x02\x02\xC2\xC3\x07*\x02\x02\xC3\xC4\x07$\x02\x02" + + "\xC4\xC9\x05\x18\r\x02\xC5\xC6\x07\"\x02\x02\xC6\xC8\x05\x18\r\x02\xC7" + + "\xC5\x03\x02\x02\x02\xC8\xCB\x03\x02\x02\x02\xC9\xC7\x03\x02\x02\x02\xC9" + + "\xCA\x03\x02\x02\x02\xCA\xCC\x03\x02\x02\x02\xCB\xC9\x03\x02\x02\x02\xCC" + + "\xCD\x07/\x02\x02\xCD\xE7\x03\x02\x02\x02\xCE\xD0\x07\'\x02\x02\xCF\xCE" + + "\x03\x02\x02\x02\xCF\xD0\x03\x02\x02\x02\xD0\xD1\x03\x02\x02\x02\xD1\xD2" + + "\x07@\x02\x02\xD2\xD3\x07$\x02\x02\xD3\xDB\x05> \x02\xD4\xD5\x07\"\x02" + + "\x02\xD5\xD7\x05:\x1E\x02\xD6\xD4\x03\x02\x02\x02\xD7\xDA\x03\x02\x02" + + "\x02\xD8\xD6\x03\x02\x02\x02\xD8\xD9\x03\x02\x02\x02\xD9\xDC\x03\x02\x02" + + "\x02\xDA\xD8\x03\x02\x02\x02\xDB\xD8\x03\x02\x02\x02\xDB\xDC\x03\x02\x02" + + "\x02\xDC\xDD\x03\x02\x02\x02\xDD\xDE\x07/\x02\x02\xDE\xE7\x03\x02\x02" + + "\x02\xDF\xE0\x05\x18\r\x02\xE0\xE2\x07+\x02\x02\xE1\xE3\x07\'\x02\x02" + + "\xE2\xE1\x03\x02\x02\x02\xE2\xE3\x03\x02\x02\x02\xE3\xE4\x03\x02\x02\x02" + + "\xE4\xE5\x07-\x02\x02\xE5\xE7\x03\x02\x02\x02\xE6\xB9\x03\x02\x02\x02" + + "\xE6\xBC\x03\x02\x02\x02\xE6\xBD\x03\x02\x02\x02\xE6\xBE\x03\x02\x02\x02" + + "\xE6\xCF\x03\x02\x02\x02\xE6\xDF\x03\x02\x02\x02\xE7\xF0\x03\x02\x02\x02" + + "\xE8\xE9\f\x07\x02\x02\xE9\xEA\x07 \x02\x02\xEA\xEF\x05\x12\n\b\xEB\xEC" + + "\f\x06\x02\x02\xEC\xED\x07.\x02\x02\xED\xEF\x05\x12\n\x07\xEE\xE8\x03" + + "\x02\x02\x02\xEE\xEB\x03\x02\x02\x02\xEF\xF2\x03\x02\x02\x02\xF0\xEE\x03" + + "\x02\x02\x02\xF0\xF1\x03\x02\x02\x02\xF1\x13\x03\x02\x02\x02\xF2\xF0\x03" + + "\x02\x02\x02\xF3\xF4\b\v\x01\x02\xF4\xF5\x07\'\x02\x02\xF5\xF8\x05\x14" + + "\v\x06\xF6\xF8\x05\x18\r\x02\xF7\xF3\x03\x02\x02\x02\xF7\xF6\x03\x02\x02" + + "\x02\xF8\u0101\x03\x02\x02\x02\xF9\xFA\f\x04\x02\x02\xFA\xFB\x07 \x02" + + "\x02\xFB\u0100\x05\x14\v\x05\xFC\xFD\f\x03\x02\x02\xFD\xFE\x07.\x02\x02" + + "\xFE\u0100\x05\x14\v\x04\xFF\xF9\x03\x02\x02\x02\xFF\xFC\x03\x02\x02\x02" + + "\u0100\u0103\x03\x02\x02\x02\u0101\xFF\x03\x02\x02\x02\u0101\u0102\x03" + + "\x02\x02\x02\u0102\x15\x03\x02\x02\x02\u0103\u0101\x03\x02\x02\x02\u0104" + + "\u0106\x05\x18\r\x02\u0105\u0107\x07\'\x02\x02\u0106\u0105\x03\x02\x02" + + "\x02\u0106\u0107\x03\x02\x02\x02\u0107\u0108\x03\x02\x02\x02\u0108\u0109" + + "\x07(\x02\x02\u0109\u010A\x05n8\x02\u010A\u0113\x03\x02\x02\x02\u010B" + + "\u010D\x05\x18\r\x02\u010C\u010E\x07\'\x02\x02\u010D\u010C\x03\x02\x02" + + "\x02\u010D\u010E\x03\x02\x02\x02\u010E\u010F\x03\x02\x02\x02\u010F\u0110" + + "\x07)\x02\x02\u0110\u0111\x05n8\x02\u0111\u0113\x03\x02\x02\x02\u0112" + + "\u0104\x03\x02\x02\x02\u0112\u010B\x03\x02\x02\x02\u0113\x17\x03\x02\x02" + + "\x02\u0114\u0117\x05 \x11\x02\u0115\u0117\x05\x1A\x0E\x02\u0116\u0114" + + "\x03\x02\x02\x02\u0116\u0115\x03\x02\x02\x02\u0117\x19\x03\x02\x02\x02" + + "\u0118\u0119\x05 \x11\x02\u0119\u011A\x05p9\x02\u011A\u011B\x05 \x11\x02" + + "\u011B\x1B\x03\x02\x02\x02\u011C\u011D\x05F$\x02\u011D\u0126\x07$\x02" + + "\x02\u011E\u0123\x05:\x1E\x02\u011F\u0120\x07\"\x02\x02\u0120\u0122\x05" + + ":\x1E\x02\u0121\u011F\x03\x02\x02\x02\u0122\u0125\x03\x02\x02\x02\u0123" + + "\u0121\x03\x02\x02\x02\u0123\u0124\x03\x02\x02\x02\u0124\u0127\x03\x02" + + "\x02\x02\u0125\u0123\x03\x02\x02\x02\u0126\u011E\x03\x02\x02\x02\u0126" + + "\u0127\x03\x02\x02\x02\u0127\u0128\x03\x02\x02\x02\u0128\u0129\x07/\x02" + + "\x02\u0129\x1D\x03\x02\x02\x02\u012A\u012B\x05D#\x02\u012B\u0134\x07$" + + "\x02\x02\u012C\u0131\x05<\x1F\x02\u012D\u012E\x07\"\x02\x02\u012E\u0130" + + "\x05<\x1F\x02\u012F\u012D\x03\x02\x02\x02\u0130\u0133\x03\x02\x02\x02" + + "\u0131\u012F\x03\x02\x02\x02\u0131\u0132\x03\x02\x02\x02\u0132\u0135\x03" + + "\x02\x02\x02\u0133\u0131\x03\x02\x02\x02\u0134\u012C\x03\x02\x02\x02\u0134" + + "\u0135\x03\x02\x02\x02\u0135\u0136\x03\x02\x02\x02\u0136\u0137\x07/\x02" + + "\x02\u0137\x1F\x03\x02\x02\x02\u0138\u0139\b\x11\x01\x02\u0139\u013F\x05" + + "\"\x12\x02\u013A\u013F\x05\x1C\x0F\x02\u013B\u013F\x05\x1E\x10\x02\u013C" + + "\u013D\t\x02\x02\x02\u013D\u013F\x05 \x11\x05\u013E\u0138\x03\x02\x02" + + "\x02\u013E\u013A\x03\x02\x02\x02\u013E\u013B\x03\x02\x02\x02\u013E\u013C" + + "\x03\x02\x02\x02\u013F\u0148\x03\x02\x02\x02\u0140\u0141\f\x04\x02\x02" + + "\u0141\u0142\t\x03\x02\x02\u0142\u0147\x05 \x11\x05\u0143\u0144\f\x03" + + "\x02\x02\u0144\u0145\t\x02\x02\x02\u0145\u0147\x05 \x11\x04\u0146\u0140" + + "\x03\x02\x02\x02\u0146\u0143\x03\x02\x02\x02\u0147\u014A\x03\x02\x02\x02" + + "\u0148\u0146\x03\x02\x02\x02\u0148\u0149\x03\x02\x02\x02\u0149!\x03\x02" + + "\x02\x02\u014A\u0148\x03\x02\x02\x02\u014B\u0160\x05H%\x02\u014C\u0160" + + "\x05> \x02\u014D\u014E\x07$\x02\x02\u014E\u014F\x05\x14\v\x02\u014F\u0150" + + "\x07/\x02\x02\u0150\u0160\x03\x02\x02\x02\u0151\u0152\x05B\"\x02\u0152" + + "\u015B\x07$\x02\x02\u0153\u0158\x05\x14\v\x02\u0154\u0155\x07\"\x02\x02" + + "\u0155\u0157\x05\x14\v\x02\u0156\u0154\x03\x02\x02\x02\u0157\u015A\x03" + + "\x02\x02\x02\u0158\u0156\x03\x02\x02\x02\u0158\u0159\x03\x02\x02\x02\u0159" + + "\u015C\x03\x02\x02\x02\u015A\u0158\x03\x02\x02\x02\u015B\u0153\x03\x02" + + "\x02\x02\u015B\u015C\x03\x02\x02\x02\u015C\u015D\x03\x02\x02\x02\u015D" + + "\u015E\x07/\x02\x02\u015E\u0160\x03\x02\x02\x02\u015F\u014B\x03\x02\x02" + + "\x02\u015F\u014C\x03\x02\x02\x02\u015F\u014D\x03\x02\x02\x02\u015F\u0151" + + "\x03\x02\x02\x02\u0160#\x03\x02\x02\x02\u0161\u0162\x07\b\x02\x02\u0162" + + "\u0163\x05&\x14\x02\u0163%\x03\x02\x02\x02\u0164\u0169\x05(\x15\x02\u0165" + + "\u0166\x07\"\x02\x02\u0166\u0168\x05(\x15\x02\u0167\u0165\x03\x02\x02" + + "\x02\u0168\u016B\x03\x02\x02\x02\u0169\u0167\x03\x02\x02\x02\u0169\u016A" + + "\x03\x02\x02\x02\u016A\'\x03\x02\x02\x02\u016B\u0169\x03\x02\x02\x02\u016C" + + "\u0172\x05\x14\v\x02\u016D\u016E\x05,\x17\x02\u016E\u016F\x07!\x02\x02" + + "\u016F\u0170\x05\x14\v\x02\u0170\u0172\x03\x02\x02\x02\u0171\u016C\x03" + + "\x02\x02\x02\u0171\u016D\x03\x02\x02\x02\u0172)\x03\x02\x02\x02\u0173" + + "\u0174\t\x04\x02\x02\u0174+\x03\x02\x02\x02\u0175\u0176\x05B\"\x02\u0176" + + "-\x03\x02\x02\x02\u0177\u0178\x07\x07\x02\x02\u0178\u017D\x056\x1C\x02" + + "\u0179\u017A\x07\"\x02\x02\u017A\u017C\x056\x1C\x02\u017B\u0179\x03\x02" + + "\x02\x02\u017C\u017F\x03\x02\x02\x02\u017D\u017B\x03\x02\x02\x02\u017D" + + "\u017E\x03\x02\x02\x02\u017E\u0181\x03\x02\x02\x02\u017F\u017D\x03\x02" + + "\x02\x02\u0180\u0182\x050\x19\x02\u0181\u0180\x03\x02\x02\x02\u0181\u0182" + + "\x03\x02\x02\x02\u0182/\x03\x02\x02\x02\u0183\u0184\x07%\x02\x02\u0184" + + "\u0185\x07F\x02\x02\u0185\u018A\x056\x1C\x02\u0186\u0187\x07\"\x02\x02" + + "\u0187\u0189\x056\x1C\x02\u0188\u0186\x03\x02\x02\x02\u0189\u018C\x03" + + "\x02\x02\x02\u018A\u0188\x03\x02\x02\x02\u018A\u018B\x03\x02\x02\x02\u018B" + + "\u018D\x03\x02\x02\x02\u018C\u018A\x03\x02\x02\x02\u018D\u018E\x07&\x02" + + "\x02\u018E1\x03\x02\x02\x02\u018F\u0190\x07\x05\x02\x02\u0190\u0191\x05" + + "&\x14\x02\u01913\x03\x02\x02\x02\u0192\u0194\x07\t\x02\x02\u0193\u0195" + + "\x05&\x14\x02\u0194\u0193\x03\x02\x02\x02\u0194\u0195\x03\x02\x02\x02" + + "\u0195\u0198\x03\x02\x02\x02\u0196\u0197\x07\x1E\x02\x02\u0197\u0199\x05" + + "@!\x02\u0198\u0196\x03\x02\x02\x02\u0198\u0199\x03\x02\x02\x02\u01995" + + "\x03\x02\x02\x02\u019A\u019B\t\x05\x02\x02\u019B7\x03\x02\x02\x02\u019C" + + "\u019D\t\x04\x02\x02\u019D9\x03\x02\x02\x02\u019E\u01A2\x05> \x02\u019F" + + "\u01A2\x05n8\x02\u01A0\u01A2\x05h5\x02\u01A1\u019E\x03\x02\x02\x02\u01A1" + + "\u019F\x03\x02\x02\x02\u01A1\u01A0\x03\x02\x02\x02\u01A2;\x03\x02\x02" + + "\x02\u01A3\u01AC\x05> \x02\u01A4\u01AC\x05n8\x02\u01A5\u01AC\x05h5\x02" + + "\u01A6\u01AC\x05 \x11\x02\u01A7\u01A8\x05h5\x02\u01A8\u01A9\x07\x1F\x02" + + "\x02\u01A9\u01AC\x03\x02\x02\x02\u01AA\u01AC\x05\x1A\x0E\x02\u01AB\u01A3" + + "\x03\x02\x02\x02\u01AB\u01A4\x03\x02\x02\x02\u01AB\u01A5\x03\x02\x02\x02" + + "\u01AB\u01A6\x03\x02\x02\x02\u01AB\u01A7\x03\x02\x02\x02\u01AB\u01AA\x03" + + "\x02\x02\x02\u01AC=\x03\x02\x02\x02\u01AD\u01B2\x05B\"\x02\u01AE\u01AF" + + "\x07#\x02\x02\u01AF\u01B1\x05B\"\x02\u01B0\u01AE\x03\x02\x02\x02\u01B1" + + "\u01B4\x03\x02\x02\x02\u01B2\u01B0\x03\x02\x02\x02\u01B2\u01B3\x03\x02" + + "\x02\x02\u01B3?\x03\x02\x02\x02\u01B4\u01B2\x03\x02\x02\x02\u01B5\u01BA" + + "\x05> \x02\u01B6\u01B7\x07\"\x02\x02\u01B7\u01B9\x05> \x02\u01B8\u01B6" + + "\x03\x02\x02\x02\u01B9\u01BC\x03\x02\x02\x02\u01BA\u01B8\x03\x02\x02\x02" + + "\u01BA\u01BB\x03\x02\x02\x02\u01BBA\x03\x02\x02\x02\u01BC\u01BA\x03\x02" + + "\x02\x02\u01BD\u01BE\t\x06\x02\x02\u01BEC\x03\x02\x02\x02\u01BF\u01C0" + + "\x07>\x02\x02\u01C0E\x03\x02\x02\x02\u01C1\u01C2\x07?\x02\x02\u01C2G\x03" + + "\x02\x02\x02\u01C3\u01E9\x07-\x02\x02\u01C4\u01E9\x05J&\x02\u01C5\u01E9" + + "\x05f4\x02\u01C6\u01E9\x05n8\x02\u01C7\u01C8\x07%\x02\x02\u01C8\u01CD" + + "\x05J&\x02\u01C9\u01CA\x07\"\x02\x02\u01CA\u01CC\x05J&\x02\u01CB\u01C9" + + "\x03\x02\x02\x02\u01CC\u01CF\x03\x02\x02\x02\u01CD\u01CB\x03\x02\x02\x02" + + "\u01CD\u01CE\x03\x02\x02\x02\u01CE\u01D0\x03\x02\x02\x02\u01CF\u01CD\x03" + + "\x02\x02\x02\u01D0\u01D1\x07&\x02\x02\u01D1\u01E9\x03\x02\x02\x02\u01D2" + + "\u01D3\x07%\x02\x02\u01D3\u01D8\x05f4\x02\u01D4\u01D5\x07\"\x02\x02\u01D5" + + "\u01D7\x05f4\x02\u01D6\u01D4\x03\x02\x02\x02\u01D7\u01DA\x03\x02\x02\x02" + + "\u01D8\u01D6\x03\x02\x02\x02\u01D8\u01D9\x03\x02\x02\x02\u01D9\u01DB\x03" + + "\x02\x02\x02\u01DA\u01D8\x03\x02\x02\x02\u01DB\u01DC\x07&\x02\x02\u01DC" + + "\u01E9\x03\x02\x02\x02\u01DD\u01DE\x07%\x02\x02\u01DE\u01E3\x05n8\x02" + + "\u01DF\u01E0\x07\"\x02\x02\u01E0\u01E2\x05n8\x02\u01E1\u01DF\x03\x02\x02" + + "\x02\u01E2\u01E5\x03\x02\x02\x02\u01E3\u01E1\x03\x02\x02\x02\u01E3\u01E4" + + "\x03\x02\x02\x02\u01E4\u01E6\x03\x02\x02\x02\u01E5\u01E3\x03\x02\x02\x02" + + "\u01E6\u01E7\x07&\x02\x02\u01E7\u01E9\x03\x02\x02\x02\u01E8\u01C3\x03" + + "\x02\x02\x02\u01E8\u01C4\x03\x02\x02\x02\u01E8\u01C5\x03\x02\x02\x02\u01E8" + + "\u01C6\x03\x02\x02\x02\u01E8\u01C7\x03\x02\x02\x02\u01E8\u01D2\x03\x02" + + "\x02\x02\u01E8\u01DD\x03\x02\x02\x02\u01E9I\x03\x02\x02\x02\u01EA\u01ED" + + "\x05j6\x02\u01EB\u01ED\x05l7\x02\u01EC\u01EA\x03\x02\x02\x02\u01EC\u01EB" + + "\x03\x02\x02\x02\u01EDK\x03\x02\x02\x02\u01EE\u01EF\x07\r\x02\x02\u01EF" + + "\u01F0\x07\x1C\x02\x02\u01F0M\x03\x02\x02\x02\u01F1\u01F2\x07\v\x02\x02" + + "\u01F2\u01F7\x05P)\x02\u01F3\u01F4\x07\"\x02\x02\u01F4\u01F6\x05P)\x02" + + "\u01F5\u01F3\x03\x02\x02\x02\u01F6\u01F9\x03\x02\x02\x02\u01F7\u01F5\x03" + + "\x02\x02\x02\u01F7\u01F8\x03\x02\x02\x02\u01F8O\x03\x02\x02\x02\u01F9" + + "\u01F7\x03\x02\x02\x02\u01FA\u01FC\x05\x14\v\x02\u01FB\u01FD\x07;\x02" + + "\x02\u01FC\u01FB\x03\x02\x02\x02\u01FC\u01FD\x03\x02\x02\x02\u01FD\u0200" + + "\x03\x02\x02\x02\u01FE\u01FF\x07<\x02\x02\u01FF\u0201\x07=\x02\x02\u0200" + + "\u01FE\x03\x02\x02\x02\u0200\u0201\x03\x02\x02\x02\u0201Q\x03\x02\x02" + + "\x02\u0202\u0203\x07\x0E\x02\x02\u0203\u0204\x05@!\x02\u0204S\x03\x02" + + "\x02\x02\u0205\u0206\x07\x13\x02\x02\u0206\u0207\x05@!\x02\u0207U\x03" + + "\x02\x02\x02\u0208\u0209\x07\x0F\x02\x02\u0209\u020A\x05@!\x02\u020AW" + + "\x03\x02\x02\x02\u020B\u0210\x05B\"\x02\u020C\u020D\x07#\x02\x02\u020D" + + "\u020F\x05B\"\x02\u020E\u020C\x03\x02\x02\x02\u020F\u0212\x03\x02\x02" + + "\x02\u0210\u020E\x03\x02\x02\x02\u0210\u0211\x03\x02\x02\x02\u0211Y\x03" + + "\x02\x02\x02\u0212\u0210\x03\x02\x02\x02\u0213\u0214\x07\x10\x02\x02\u0214" + + "\u0219\x05\\/\x02\u0215\u0216\x07\"\x02\x02\u0216\u0218\x05\\/\x02\u0217" + + "\u0215\x03\x02\x02\x02\u0218\u021B\x03\x02\x02\x02\u0219\u0217\x03\x02" + + "\x02\x02\u0219\u021A\x03\x02\x02\x02\u021A[\x03\x02\x02\x02\u021B\u0219" + + "\x03\x02\x02\x02\u021C\u021D\x05> \x02\u021D\u021E\x07,\x02\x02\u021E" + + "\u021F\x05X-\x02\u021F]\x03\x02\x02\x02\u0220\u0221\x07\x03\x02\x02\u0221" + + "\u0222\x05@!\x02\u0222\u0224\x05n8\x02\u0223\u0225\x05b2\x02\u0224\u0223" + + "\x03\x02\x02\x02\u0224\u0225\x03\x02\x02\x02\u0225_\x03\x02\x02\x02\u0226" + + "\u0227\x07\x04\x02\x02\u0227\u0228\x05@!\x02\u0228\u0229\x05n8\x02\u0229" + + "a\x03\x02\x02\x02\u022A\u022F\x05d3\x02\u022B\u022C\x07\"\x02\x02\u022C" + + "\u022E\x05d3\x02\u022D\u022B\x03\x02\x02\x02\u022E\u0231\x03\x02\x02\x02" + + "\u022F\u022D\x03\x02\x02\x02\u022F\u0230\x03\x02\x02\x02\u0230c\x03\x02" + + "\x02\x02\u0231\u022F\x03\x02\x02\x02\u0232\u0233\x05B\"\x02\u0233\u0234" + + "\x07!\x02\x02\u0234\u0235\x05H%\x02\u0235e\x03\x02\x02\x02\u0236\u0237" + + "\x073\x02\x02\u0237g\x03\x02\x02\x02\u0238\u023B\x07\x1D\x02\x02\u0239" + + "\u023B\x07\x1C\x02"; + private static readonly _serializedATNSegment1: string = + "\x02\u023A\u0238\x03\x02\x02\x02\u023A\u0239\x03\x02\x02\x02\u023Bi\x03" + + "\x02\x02\x02\u023C\u023D\x07\x1D\x02\x02\u023Dk\x03\x02\x02\x02\u023E" + + "\u023F\x07\x1C\x02\x02\u023Fm\x03\x02\x02\x02\u0240\u0241\x07\x1B\x02" + + "\x02\u0241o\x03\x02\x02\x02\u0242\u0243\x074\x02\x02\u0243q\x03\x02\x02" + + "\x02\u0244\u0245\x07\x06\x02\x02\u0245\u0246\x05t;\x02\u0246s\x03\x02" + + "\x02\x02\u0247\u0248\x07%\x02\x02\u0248\u0249\x05\x04\x03\x02\u0249\u024A" + + "\x07&\x02\x02\u024Au\x03\x02\x02\x02\u024B\u024C\x07\x11\x02\x02\u024C" + + "\u0250\x071\x02\x02\u024D\u024E\x07\x11\x02\x02\u024E\u0250\x072\x02\x02" + + "\u024F\u024B\x03\x02\x02\x02\u024F\u024D\x03\x02\x02\x02\u0250w\x03\x02" + + "\x02\x02<\x83\x8A\x99\x9F\xA7\xAA\xAF\xC0\xC9\xCF\xD8\xDB\xE2\xE6\xEE" + + "\xF0\xF7\xFF\u0101\u0106\u010D\u0112\u0116\u0123\u0126\u0131\u0134\u013E" + + "\u0146\u0148\u0158\u015B\u015F\u0169\u0171\u017D\u0181\u018A\u0194\u0198" + + "\u01A1\u01AB\u01B2\u01BA\u01CD\u01D8\u01E3\u01E8\u01EC\u01F7\u01FC\u0200" + + "\u0210\u0219\u0224\u022F\u023A\u024F"; + public static readonly _serializedATN: string = Utils.join( + [ + esql_parser._serializedATNSegment0, + esql_parser._serializedATNSegment1, + ], + "", + ); + public static __ATN: ATN; + public static get _ATN(): ATN { + if (!esql_parser.__ATN) { + esql_parser.__ATN = new ATNDeserializer().deserialize(Utils.toCharArray(esql_parser._serializedATN)); + } + + return esql_parser.__ATN; + } + +} + +export class SingleStatementContext extends ParserRuleContext { + public query(): QueryContext { + return this.getRuleContext(0, QueryContext); + } + public EOF(): TerminalNode { return this.getToken(esql_parser.EOF, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_singleStatement; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterSingleStatement) { + listener.enterSingleStatement(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitSingleStatement) { + listener.exitSingleStatement(this); + } + } +} + + +export class QueryContext extends ParserRuleContext { + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_query; } + public copyFrom(ctx: QueryContext): void { + super.copyFrom(ctx); + } +} +export class SingleCommandQueryContext extends QueryContext { + public sourceCommand(): SourceCommandContext { + return this.getRuleContext(0, SourceCommandContext); + } + constructor(ctx: QueryContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterSingleCommandQuery) { + listener.enterSingleCommandQuery(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitSingleCommandQuery) { + listener.exitSingleCommandQuery(this); + } + } +} +export class CompositeQueryContext extends QueryContext { + public query(): QueryContext { + return this.getRuleContext(0, QueryContext); + } + public PIPE(): TerminalNode { return this.getToken(esql_parser.PIPE, 0); } + public processingCommand(): ProcessingCommandContext { + return this.getRuleContext(0, ProcessingCommandContext); + } + constructor(ctx: QueryContext) { + super(ctx.parent, ctx.invokingState); + this.copyFrom(ctx); + } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterCompositeQuery) { + listener.enterCompositeQuery(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitCompositeQuery) { + listener.exitCompositeQuery(this); + } + } +} + + +export class SourceCommandContext extends ParserRuleContext { + public explainCommand(): ExplainCommandContext | undefined { + return this.tryGetRuleContext(0, ExplainCommandContext); + } + public fromCommand(): FromCommandContext | undefined { + return this.tryGetRuleContext(0, FromCommandContext); + } + public rowCommand(): RowCommandContext | undefined { + return this.tryGetRuleContext(0, RowCommandContext); + } + public showCommand(): ShowCommandContext | undefined { + return this.tryGetRuleContext(0, ShowCommandContext); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_sourceCommand; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterSourceCommand) { + listener.enterSourceCommand(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitSourceCommand) { + listener.exitSourceCommand(this); + } + } +} + + +export class ProcessingCommandContext extends ParserRuleContext { + public evalCommand(): EvalCommandContext | undefined { + return this.tryGetRuleContext(0, EvalCommandContext); + } + public limitCommand(): LimitCommandContext | undefined { + return this.tryGetRuleContext(0, LimitCommandContext); + } + public projectCommand(): ProjectCommandContext | undefined { + return this.tryGetRuleContext(0, ProjectCommandContext); + } + public keepCommand(): KeepCommandContext | undefined { + return this.tryGetRuleContext(0, KeepCommandContext); + } + public renameCommand(): RenameCommandContext | undefined { + return this.tryGetRuleContext(0, RenameCommandContext); + } + public dropCommand(): DropCommandContext | undefined { + return this.tryGetRuleContext(0, DropCommandContext); + } + public dissectCommand(): DissectCommandContext | undefined { + return this.tryGetRuleContext(0, DissectCommandContext); + } + public grokCommand(): GrokCommandContext | undefined { + return this.tryGetRuleContext(0, GrokCommandContext); + } + public sortCommand(): SortCommandContext | undefined { + return this.tryGetRuleContext(0, SortCommandContext); + } + public statsCommand(): StatsCommandContext | undefined { + return this.tryGetRuleContext(0, StatsCommandContext); + } + public whereCommand(): WhereCommandContext | undefined { + return this.tryGetRuleContext(0, WhereCommandContext); + } + public mvExpandCommand(): MvExpandCommandContext | undefined { + return this.tryGetRuleContext(0, MvExpandCommandContext); + } + public enrichCommand(): EnrichCommandContext | undefined { + return this.tryGetRuleContext(0, EnrichCommandContext); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_processingCommand; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterProcessingCommand) { + listener.enterProcessingCommand(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitProcessingCommand) { + listener.exitProcessingCommand(this); + } + } +} + + +export class EnrichCommandContext extends ParserRuleContext { + public _policyName: EnrichIdentifierContext; + public _matchField: EnrichFieldIdentifierContext; + public ENRICH(): TerminalNode { return this.getToken(esql_parser.ENRICH, 0); } + public enrichIdentifier(): EnrichIdentifierContext { + return this.getRuleContext(0, EnrichIdentifierContext); + } + public ON(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ON, 0); } + public WITH(): TerminalNode | undefined { return this.tryGetToken(esql_parser.WITH, 0); } + public enrichWithClause(): EnrichWithClauseContext[]; + public enrichWithClause(i: number): EnrichWithClauseContext; + public enrichWithClause(i?: number): EnrichWithClauseContext | EnrichWithClauseContext[] { + if (i === undefined) { + return this.getRuleContexts(EnrichWithClauseContext); + } else { + return this.getRuleContext(i, EnrichWithClauseContext); + } + } + public enrichFieldIdentifier(): EnrichFieldIdentifierContext | undefined { + return this.tryGetRuleContext(0, EnrichFieldIdentifierContext); + } + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_enrichCommand; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterEnrichCommand) { + listener.enterEnrichCommand(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitEnrichCommand) { + listener.exitEnrichCommand(this); + } + } +} + + +export class EnrichWithClauseContext extends ParserRuleContext { + public _newName: EnrichFieldIdentifierContext; + public _enrichField: EnrichFieldIdentifierContext; + public enrichFieldIdentifier(): EnrichFieldIdentifierContext[]; + public enrichFieldIdentifier(i: number): EnrichFieldIdentifierContext; + public enrichFieldIdentifier(i?: number): EnrichFieldIdentifierContext | EnrichFieldIdentifierContext[] { + if (i === undefined) { + return this.getRuleContexts(EnrichFieldIdentifierContext); + } else { + return this.getRuleContext(i, EnrichFieldIdentifierContext); + } + } + public ASSIGN(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASSIGN, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_enrichWithClause; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterEnrichWithClause) { + listener.enterEnrichWithClause(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitEnrichWithClause) { + listener.exitEnrichWithClause(this); + } + } +} + + +export class MvExpandCommandContext extends ParserRuleContext { + public MV_EXPAND(): TerminalNode { return this.getToken(esql_parser.MV_EXPAND, 0); } + public qualifiedNames(): QualifiedNamesContext { + return this.getRuleContext(0, QualifiedNamesContext); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_mvExpandCommand; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterMvExpandCommand) { + listener.enterMvExpandCommand(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitMvExpandCommand) { + listener.exitMvExpandCommand(this); + } + } +} + + +export class WhereCommandContext extends ParserRuleContext { + public WHERE(): TerminalNode { return this.getToken(esql_parser.WHERE, 0); } + public whereBooleanExpression(): WhereBooleanExpressionContext { + return this.getRuleContext(0, WhereBooleanExpressionContext); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_whereCommand; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterWhereCommand) { + listener.enterWhereCommand(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitWhereCommand) { + listener.exitWhereCommand(this); + } + } +} + + +export class WhereBooleanExpressionContext extends ParserRuleContext { + public _left: WhereBooleanExpressionContext; + public _operator: Token; + public _right: WhereBooleanExpressionContext; + public NOT(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NOT, 0); } + public whereBooleanExpression(): WhereBooleanExpressionContext[]; + public whereBooleanExpression(i: number): WhereBooleanExpressionContext; + public whereBooleanExpression(i?: number): WhereBooleanExpressionContext | WhereBooleanExpressionContext[] { + if (i === undefined) { + return this.getRuleContexts(WhereBooleanExpressionContext); + } else { + return this.getRuleContext(i, WhereBooleanExpressionContext); + } + } + public valueExpression(): ValueExpressionContext[]; + public valueExpression(i: number): ValueExpressionContext; + public valueExpression(i?: number): ValueExpressionContext | ValueExpressionContext[] { + if (i === undefined) { + return this.getRuleContexts(ValueExpressionContext); + } else { + return this.getRuleContext(i, ValueExpressionContext); + } + } + public regexBooleanExpression(): RegexBooleanExpressionContext | undefined { + return this.tryGetRuleContext(0, RegexBooleanExpressionContext); + } + public AND(): TerminalNode | undefined { return this.tryGetToken(esql_parser.AND, 0); } + public OR(): TerminalNode | undefined { return this.tryGetToken(esql_parser.OR, 0); } + public IN(): TerminalNode | undefined { return this.tryGetToken(esql_parser.IN, 0); } + public LP(): TerminalNode | undefined { return this.tryGetToken(esql_parser.LP, 0); } + public RP(): TerminalNode | undefined { return this.tryGetToken(esql_parser.RP, 0); } + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } + } + public WHERE_FUNCTIONS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.WHERE_FUNCTIONS, 0); } + public qualifiedName(): QualifiedNameContext | undefined { + return this.tryGetRuleContext(0, QualifiedNameContext); + } + public functionExpressionArgument(): FunctionExpressionArgumentContext[]; + public functionExpressionArgument(i: number): FunctionExpressionArgumentContext; + public functionExpressionArgument(i?: number): FunctionExpressionArgumentContext | FunctionExpressionArgumentContext[] { + if (i === undefined) { + return this.getRuleContexts(FunctionExpressionArgumentContext); + } else { + return this.getRuleContext(i, FunctionExpressionArgumentContext); + } + } + public IS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.IS, 0); } + public NULL(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NULL, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_whereBooleanExpression; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterWhereBooleanExpression) { + listener.enterWhereBooleanExpression(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitWhereBooleanExpression) { + listener.exitWhereBooleanExpression(this); + } + } +} + + +export class BooleanExpressionContext extends ParserRuleContext { + public _left: BooleanExpressionContext; + public _operator: Token; + public _right: BooleanExpressionContext; + public NOT(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NOT, 0); } + public booleanExpression(): BooleanExpressionContext[]; + public booleanExpression(i: number): BooleanExpressionContext; + public booleanExpression(i?: number): BooleanExpressionContext | BooleanExpressionContext[] { + if (i === undefined) { + return this.getRuleContexts(BooleanExpressionContext); + } else { + return this.getRuleContext(i, BooleanExpressionContext); + } + } + public valueExpression(): ValueExpressionContext | undefined { + return this.tryGetRuleContext(0, ValueExpressionContext); + } + public AND(): TerminalNode | undefined { return this.tryGetToken(esql_parser.AND, 0); } + public OR(): TerminalNode | undefined { return this.tryGetToken(esql_parser.OR, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_booleanExpression; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterBooleanExpression) { + listener.enterBooleanExpression(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitBooleanExpression) { + listener.exitBooleanExpression(this); + } + } } -export class SingleStatementContext extends ParserRuleContext { - public query(): QueryContext { - return this.getRuleContext(0, QueryContext); + +export class RegexBooleanExpressionContext extends ParserRuleContext { + public _kind: Token; + public _pattern: StringContext; + public valueExpression(): ValueExpressionContext { + return this.getRuleContext(0, ValueExpressionContext); } - public EOF(): TerminalNode { return this.getToken(esql_parser.EOF, 0); } + public LIKE(): TerminalNode | undefined { return this.tryGetToken(esql_parser.LIKE, 0); } + public string(): StringContext { + return this.getRuleContext(0, StringContext); + } + public NOT(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NOT, 0); } + public RLIKE(): TerminalNode | undefined { return this.tryGetToken(esql_parser.RLIKE, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_singleStatement; } + public get ruleIndex(): number { return esql_parser.RULE_regexBooleanExpression; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterSingleStatement) { - listener.enterSingleStatement(this); + if (listener.enterRegexBooleanExpression) { + listener.enterRegexBooleanExpression(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitSingleStatement) { - listener.exitSingleStatement(this); + if (listener.exitRegexBooleanExpression) { + listener.exitRegexBooleanExpression(this); } } } -export class QueryContext extends ParserRuleContext { +export class ValueExpressionContext extends ParserRuleContext { + public operatorExpression(): OperatorExpressionContext | undefined { + return this.tryGetRuleContext(0, OperatorExpressionContext); + } + public comparison(): ComparisonContext | undefined { + return this.tryGetRuleContext(0, ComparisonContext); + } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_query; } - public copyFrom(ctx: QueryContext): void { - super.copyFrom(ctx); + public get ruleIndex(): number { return esql_parser.RULE_valueExpression; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterValueExpression) { + listener.enterValueExpression(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitValueExpression) { + listener.exitValueExpression(this); + } } } -export class SingleCommandQueryContext extends QueryContext { - public sourceCommand(): SourceCommandContext { - return this.getRuleContext(0, SourceCommandContext); + + +export class ComparisonContext extends ParserRuleContext { + public _left: OperatorExpressionContext; + public _right: OperatorExpressionContext; + public comparisonOperator(): ComparisonOperatorContext { + return this.getRuleContext(0, ComparisonOperatorContext); } - constructor(ctx: QueryContext) { - super(ctx.parent, ctx.invokingState); - this.copyFrom(ctx); + public operatorExpression(): OperatorExpressionContext[]; + public operatorExpression(i: number): OperatorExpressionContext; + public operatorExpression(i?: number): OperatorExpressionContext | OperatorExpressionContext[] { + if (i === undefined) { + return this.getRuleContexts(OperatorExpressionContext); + } else { + return this.getRuleContext(i, OperatorExpressionContext); + } } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_comparison; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterSingleCommandQuery) { - listener.enterSingleCommandQuery(this); + if (listener.enterComparison) { + listener.enterComparison(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitSingleCommandQuery) { - listener.exitSingleCommandQuery(this); + if (listener.exitComparison) { + listener.exitComparison(this); } } } -export class CompositeQueryContext extends QueryContext { - public query(): QueryContext { - return this.getRuleContext(0, QueryContext); + + +export class MathFnContext extends ParserRuleContext { + public functionIdentifier(): FunctionIdentifierContext { + return this.getRuleContext(0, FunctionIdentifierContext); } - public PIPE(): TerminalNode { return this.getToken(esql_parser.PIPE, 0); } - public processingCommand(): ProcessingCommandContext { - return this.getRuleContext(0, ProcessingCommandContext); + public LP(): TerminalNode { return this.getToken(esql_parser.LP, 0); } + public RP(): TerminalNode { return this.getToken(esql_parser.RP, 0); } + public functionExpressionArgument(): FunctionExpressionArgumentContext[]; + public functionExpressionArgument(i: number): FunctionExpressionArgumentContext; + public functionExpressionArgument(i?: number): FunctionExpressionArgumentContext | FunctionExpressionArgumentContext[] { + if (i === undefined) { + return this.getRuleContexts(FunctionExpressionArgumentContext); + } else { + return this.getRuleContext(i, FunctionExpressionArgumentContext); + } } - constructor(ctx: QueryContext) { - super(ctx.parent, ctx.invokingState); - this.copyFrom(ctx); + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); } // @Override + public get ruleIndex(): number { return esql_parser.RULE_mathFn; } + // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterCompositeQuery) { - listener.enterCompositeQuery(this); + if (listener.enterMathFn) { + listener.enterMathFn(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitCompositeQuery) { - listener.exitCompositeQuery(this); + if (listener.exitMathFn) { + listener.exitMathFn(this); + } + } +} + + +export class MathEvalFnContext extends ParserRuleContext { + public mathFunctionIdentifier(): MathFunctionIdentifierContext { + return this.getRuleContext(0, MathFunctionIdentifierContext); + } + public LP(): TerminalNode { return this.getToken(esql_parser.LP, 0); } + public RP(): TerminalNode { return this.getToken(esql_parser.RP, 0); } + public mathFunctionExpressionArgument(): MathFunctionExpressionArgumentContext[]; + public mathFunctionExpressionArgument(i: number): MathFunctionExpressionArgumentContext; + public mathFunctionExpressionArgument(i?: number): MathFunctionExpressionArgumentContext | MathFunctionExpressionArgumentContext[] { + if (i === undefined) { + return this.getRuleContexts(MathFunctionExpressionArgumentContext); + } else { + return this.getRuleContext(i, MathFunctionExpressionArgumentContext); + } + } + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_mathEvalFn; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterMathEvalFn) { + listener.enterMathEvalFn(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitMathEvalFn) { + listener.exitMathEvalFn(this); + } + } +} + + +export class OperatorExpressionContext extends ParserRuleContext { + public _left: OperatorExpressionContext; + public _operator: Token; + public _right: OperatorExpressionContext; + public primaryExpression(): PrimaryExpressionContext | undefined { + return this.tryGetRuleContext(0, PrimaryExpressionContext); + } + public mathFn(): MathFnContext | undefined { + return this.tryGetRuleContext(0, MathFnContext); + } + public mathEvalFn(): MathEvalFnContext | undefined { + return this.tryGetRuleContext(0, MathEvalFnContext); + } + public operatorExpression(): OperatorExpressionContext[]; + public operatorExpression(i: number): OperatorExpressionContext; + public operatorExpression(i?: number): OperatorExpressionContext | OperatorExpressionContext[] { + if (i === undefined) { + return this.getRuleContexts(OperatorExpressionContext); + } else { + return this.getRuleContext(i, OperatorExpressionContext); + } + } + public MINUS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.MINUS, 0); } + public PLUS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.PLUS, 0); } + public ASTERISK(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASTERISK, 0); } + public SLASH(): TerminalNode | undefined { return this.tryGetToken(esql_parser.SLASH, 0); } + public PERCENT(): TerminalNode | undefined { return this.tryGetToken(esql_parser.PERCENT, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_operatorExpression; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterOperatorExpression) { + listener.enterOperatorExpression(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitOperatorExpression) { + listener.exitOperatorExpression(this); + } + } +} + + +export class PrimaryExpressionContext extends ParserRuleContext { + public constant(): ConstantContext | undefined { + return this.tryGetRuleContext(0, ConstantContext); + } + public qualifiedName(): QualifiedNameContext | undefined { + return this.tryGetRuleContext(0, QualifiedNameContext); + } + public LP(): TerminalNode | undefined { return this.tryGetToken(esql_parser.LP, 0); } + public booleanExpression(): BooleanExpressionContext[]; + public booleanExpression(i: number): BooleanExpressionContext; + public booleanExpression(i?: number): BooleanExpressionContext | BooleanExpressionContext[] { + if (i === undefined) { + return this.getRuleContexts(BooleanExpressionContext); + } else { + return this.getRuleContext(i, BooleanExpressionContext); + } + } + public RP(): TerminalNode | undefined { return this.tryGetToken(esql_parser.RP, 0); } + public identifier(): IdentifierContext | undefined { + return this.tryGetRuleContext(0, IdentifierContext); + } + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_primaryExpression; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterPrimaryExpression) { + listener.enterPrimaryExpression(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitPrimaryExpression) { + listener.exitPrimaryExpression(this); } } } -export class SourceCommandContext extends ParserRuleContext { - public explainCommand(): ExplainCommandContext | undefined { - return this.tryGetRuleContext(0, ExplainCommandContext); - } - public fromCommand(): FromCommandContext | undefined { - return this.tryGetRuleContext(0, FromCommandContext); - } - public rowCommand(): RowCommandContext | undefined { - return this.tryGetRuleContext(0, RowCommandContext); +export class RowCommandContext extends ParserRuleContext { + public ROW(): TerminalNode { return this.getToken(esql_parser.ROW, 0); } + public fields(): FieldsContext { + return this.getRuleContext(0, FieldsContext); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_sourceCommand; } + public get ruleIndex(): number { return esql_parser.RULE_rowCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterSourceCommand) { - listener.enterSourceCommand(this); + if (listener.enterRowCommand) { + listener.enterRowCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitSourceCommand) { - listener.exitSourceCommand(this); + if (listener.exitRowCommand) { + listener.exitRowCommand(this); } } } -export class ProcessingCommandContext extends ParserRuleContext { - public evalCommand(): EvalCommandContext | undefined { - return this.tryGetRuleContext(0, EvalCommandContext); - } - public limitCommand(): LimitCommandContext | undefined { - return this.tryGetRuleContext(0, LimitCommandContext); - } - public projectCommand(): ProjectCommandContext | undefined { - return this.tryGetRuleContext(0, ProjectCommandContext); - } - public sortCommand(): SortCommandContext | undefined { - return this.tryGetRuleContext(0, SortCommandContext); - } - public statsCommand(): StatsCommandContext | undefined { - return this.tryGetRuleContext(0, StatsCommandContext); +export class FieldsContext extends ParserRuleContext { + public field(): FieldContext[]; + public field(i: number): FieldContext; + public field(i?: number): FieldContext | FieldContext[] { + if (i === undefined) { + return this.getRuleContexts(FieldContext); + } else { + return this.getRuleContext(i, FieldContext); + } } - public whereCommand(): WhereCommandContext | undefined { - return this.tryGetRuleContext(0, WhereCommandContext); + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_processingCommand; } + public get ruleIndex(): number { return esql_parser.RULE_fields; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterProcessingCommand) { - listener.enterProcessingCommand(this); + if (listener.enterFields) { + listener.enterFields(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitProcessingCommand) { - listener.exitProcessingCommand(this); + if (listener.exitFields) { + listener.exitFields(this); } } } -export class WhereCommandContext extends ParserRuleContext { - public WHERE(): TerminalNode { return this.getToken(esql_parser.WHERE, 0); } +export class FieldContext extends ParserRuleContext { public booleanExpression(): BooleanExpressionContext { return this.getRuleContext(0, BooleanExpressionContext); } + public userVariable(): UserVariableContext | undefined { + return this.tryGetRuleContext(0, UserVariableContext); + } + public ASSIGN(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASSIGN, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_whereCommand; } + public get ruleIndex(): number { return esql_parser.RULE_field; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterWhereCommand) { - listener.enterWhereCommand(this); + if (listener.enterField) { + listener.enterField(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitWhereCommand) { - listener.exitWhereCommand(this); + if (listener.exitField) { + listener.exitField(this); } } } -export class BooleanExpressionContext extends ParserRuleContext { - public _left: BooleanExpressionContext; - public _operator: Token; - public _right: BooleanExpressionContext; - public NOT(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NOT, 0); } - public booleanExpression(): BooleanExpressionContext[]; - public booleanExpression(i: number): BooleanExpressionContext; - public booleanExpression(i?: number): BooleanExpressionContext | BooleanExpressionContext[] { - if (i === undefined) { - return this.getRuleContexts(BooleanExpressionContext); - } else { - return this.getRuleContext(i, BooleanExpressionContext); - } - } - public valueExpression(): ValueExpressionContext | undefined { - return this.tryGetRuleContext(0, ValueExpressionContext); - } - public AND(): TerminalNode | undefined { return this.tryGetToken(esql_parser.AND, 0); } - public OR(): TerminalNode | undefined { return this.tryGetToken(esql_parser.OR, 0); } +export class EnrichFieldIdentifierContext extends ParserRuleContext { + public ENR_UNQUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ENR_UNQUOTED_IDENTIFIER, 0); } + public ENR_QUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ENR_QUOTED_IDENTIFIER, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_booleanExpression; } + public get ruleIndex(): number { return esql_parser.RULE_enrichFieldIdentifier; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterBooleanExpression) { - listener.enterBooleanExpression(this); + if (listener.enterEnrichFieldIdentifier) { + listener.enterEnrichFieldIdentifier(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitBooleanExpression) { - listener.exitBooleanExpression(this); + if (listener.exitEnrichFieldIdentifier) { + listener.exitEnrichFieldIdentifier(this); } } } -export class ValueExpressionContext extends ParserRuleContext { - public operatorExpression(): OperatorExpressionContext | undefined { - return this.tryGetRuleContext(0, OperatorExpressionContext); - } - public comparison(): ComparisonContext | undefined { - return this.tryGetRuleContext(0, ComparisonContext); +export class UserVariableContext extends ParserRuleContext { + public identifier(): IdentifierContext { + return this.getRuleContext(0, IdentifierContext); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_valueExpression; } + public get ruleIndex(): number { return esql_parser.RULE_userVariable; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterValueExpression) { - listener.enterValueExpression(this); + if (listener.enterUserVariable) { + listener.enterUserVariable(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitValueExpression) { - listener.exitValueExpression(this); + if (listener.exitUserVariable) { + listener.exitUserVariable(this); } } } -export class ComparisonContext extends ParserRuleContext { - public _left: OperatorExpressionContext; - public _right: OperatorExpressionContext; - public comparisonOperator(): ComparisonOperatorContext { - return this.getRuleContext(0, ComparisonOperatorContext); +export class FromCommandContext extends ParserRuleContext { + public FROM(): TerminalNode { return this.getToken(esql_parser.FROM, 0); } + public sourceIdentifier(): SourceIdentifierContext[]; + public sourceIdentifier(i: number): SourceIdentifierContext; + public sourceIdentifier(i?: number): SourceIdentifierContext | SourceIdentifierContext[] { + if (i === undefined) { + return this.getRuleContexts(SourceIdentifierContext); + } else { + return this.getRuleContext(i, SourceIdentifierContext); + } } - public operatorExpression(): OperatorExpressionContext[]; - public operatorExpression(i: number): OperatorExpressionContext; - public operatorExpression(i?: number): OperatorExpressionContext | OperatorExpressionContext[] { + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { if (i === undefined) { - return this.getRuleContexts(OperatorExpressionContext); + return this.getTokens(esql_parser.COMMA); } else { - return this.getRuleContext(i, OperatorExpressionContext); + return this.getToken(esql_parser.COMMA, i); } } + public metadata(): MetadataContext | undefined { + return this.tryGetRuleContext(0, MetadataContext); + } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_comparison; } + public get ruleIndex(): number { return esql_parser.RULE_fromCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterComparison) { - listener.enterComparison(this); + if (listener.enterFromCommand) { + listener.enterFromCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitComparison) { - listener.exitComparison(this); + if (listener.exitFromCommand) { + listener.exitFromCommand(this); } } } -export class MathFnContext extends ParserRuleContext { - public functionIdentifier(): FunctionIdentifierContext { - return this.getRuleContext(0, FunctionIdentifierContext); - } - public LP(): TerminalNode { return this.getToken(esql_parser.LP, 0); } - public RP(): TerminalNode { return this.getToken(esql_parser.RP, 0); } - public functionExpressionArgument(): FunctionExpressionArgumentContext[]; - public functionExpressionArgument(i: number): FunctionExpressionArgumentContext; - public functionExpressionArgument(i?: number): FunctionExpressionArgumentContext | FunctionExpressionArgumentContext[] { +export class MetadataContext extends ParserRuleContext { + public OPENING_BRACKET(): TerminalNode { return this.getToken(esql_parser.OPENING_BRACKET, 0); } + public METADATA(): TerminalNode { return this.getToken(esql_parser.METADATA, 0); } + public sourceIdentifier(): SourceIdentifierContext[]; + public sourceIdentifier(i: number): SourceIdentifierContext; + public sourceIdentifier(i?: number): SourceIdentifierContext | SourceIdentifierContext[] { if (i === undefined) { - return this.getRuleContexts(FunctionExpressionArgumentContext); + return this.getRuleContexts(SourceIdentifierContext); } else { - return this.getRuleContext(i, FunctionExpressionArgumentContext); + return this.getRuleContext(i, SourceIdentifierContext); } } + public CLOSING_BRACKET(): TerminalNode { return this.getToken(esql_parser.CLOSING_BRACKET, 0); } public COMMA(): TerminalNode[]; public COMMA(i: number): TerminalNode; public COMMA(i?: number): TerminalNode | TerminalNode[] { @@ -2306,241 +4413,236 @@ export class MathFnContext extends ParserRuleContext { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_mathFn; } + public get ruleIndex(): number { return esql_parser.RULE_metadata; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterMathFn) { - listener.enterMathFn(this); + if (listener.enterMetadata) { + listener.enterMetadata(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitMathFn) { - listener.exitMathFn(this); + if (listener.exitMetadata) { + listener.exitMetadata(this); } } } -export class OperatorExpressionContext extends ParserRuleContext { - public _left: OperatorExpressionContext; - public _operator: Token; - public _right: OperatorExpressionContext; - public primaryExpression(): PrimaryExpressionContext | undefined { - return this.tryGetRuleContext(0, PrimaryExpressionContext); - } - public mathFn(): MathFnContext | undefined { - return this.tryGetRuleContext(0, MathFnContext); - } - public operatorExpression(): OperatorExpressionContext[]; - public operatorExpression(i: number): OperatorExpressionContext; - public operatorExpression(i?: number): OperatorExpressionContext | OperatorExpressionContext[] { - if (i === undefined) { - return this.getRuleContexts(OperatorExpressionContext); - } else { - return this.getRuleContext(i, OperatorExpressionContext); - } +export class EvalCommandContext extends ParserRuleContext { + public EVAL(): TerminalNode { return this.getToken(esql_parser.EVAL, 0); } + public fields(): FieldsContext { + return this.getRuleContext(0, FieldsContext); } - public MINUS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.MINUS, 0); } - public PLUS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.PLUS, 0); } - public ASTERISK(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASTERISK, 0); } - public SLASH(): TerminalNode | undefined { return this.tryGetToken(esql_parser.SLASH, 0); } - public PERCENT(): TerminalNode | undefined { return this.tryGetToken(esql_parser.PERCENT, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_operatorExpression; } + public get ruleIndex(): number { return esql_parser.RULE_evalCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterOperatorExpression) { - listener.enterOperatorExpression(this); + if (listener.enterEvalCommand) { + listener.enterEvalCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitOperatorExpression) { - listener.exitOperatorExpression(this); + if (listener.exitEvalCommand) { + listener.exitEvalCommand(this); } } } -export class PrimaryExpressionContext extends ParserRuleContext { - public constant(): ConstantContext | undefined { - return this.tryGetRuleContext(0, ConstantContext); - } - public qualifiedName(): QualifiedNameContext | undefined { - return this.tryGetRuleContext(0, QualifiedNameContext); - } - public LP(): TerminalNode | undefined { return this.tryGetToken(esql_parser.LP, 0); } - public booleanExpression(): BooleanExpressionContext[]; - public booleanExpression(i: number): BooleanExpressionContext; - public booleanExpression(i?: number): BooleanExpressionContext | BooleanExpressionContext[] { - if (i === undefined) { - return this.getRuleContexts(BooleanExpressionContext); - } else { - return this.getRuleContext(i, BooleanExpressionContext); - } - } - public RP(): TerminalNode | undefined { return this.tryGetToken(esql_parser.RP, 0); } - public identifier(): IdentifierContext | undefined { - return this.tryGetRuleContext(0, IdentifierContext); +export class StatsCommandContext extends ParserRuleContext { + public STATS(): TerminalNode { return this.getToken(esql_parser.STATS, 0); } + public fields(): FieldsContext | undefined { + return this.tryGetRuleContext(0, FieldsContext); } - public COMMA(): TerminalNode[]; - public COMMA(i: number): TerminalNode; - public COMMA(i?: number): TerminalNode | TerminalNode[] { - if (i === undefined) { - return this.getTokens(esql_parser.COMMA); - } else { - return this.getToken(esql_parser.COMMA, i); - } + public BY(): TerminalNode | undefined { return this.tryGetToken(esql_parser.BY, 0); } + public qualifiedNames(): QualifiedNamesContext | undefined { + return this.tryGetRuleContext(0, QualifiedNamesContext); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_primaryExpression; } + public get ruleIndex(): number { return esql_parser.RULE_statsCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterPrimaryExpression) { - listener.enterPrimaryExpression(this); + if (listener.enterStatsCommand) { + listener.enterStatsCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitPrimaryExpression) { - listener.exitPrimaryExpression(this); + if (listener.exitStatsCommand) { + listener.exitStatsCommand(this); } } } -export class RowCommandContext extends ParserRuleContext { - public ROW(): TerminalNode { return this.getToken(esql_parser.ROW, 0); } - public fields(): FieldsContext { - return this.getRuleContext(0, FieldsContext); - } +export class SourceIdentifierContext extends ParserRuleContext { + public SRC_UNQUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.SRC_UNQUOTED_IDENTIFIER, 0); } + public SRC_QUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.SRC_QUOTED_IDENTIFIER, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_rowCommand; } + public get ruleIndex(): number { return esql_parser.RULE_sourceIdentifier; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterRowCommand) { - listener.enterRowCommand(this); + if (listener.enterSourceIdentifier) { + listener.enterSourceIdentifier(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitRowCommand) { - listener.exitRowCommand(this); + if (listener.exitSourceIdentifier) { + listener.exitSourceIdentifier(this); } } } -export class FieldsContext extends ParserRuleContext { - public field(): FieldContext[]; - public field(i: number): FieldContext; - public field(i?: number): FieldContext | FieldContext[] { - if (i === undefined) { - return this.getRuleContexts(FieldContext); - } else { - return this.getRuleContext(i, FieldContext); +export class EnrichIdentifierContext extends ParserRuleContext { + public ENR_UNQUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ENR_UNQUOTED_IDENTIFIER, 0); } + public ENR_QUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ENR_QUOTED_IDENTIFIER, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_enrichIdentifier; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterEnrichIdentifier) { + listener.enterEnrichIdentifier(this); } } - public COMMA(): TerminalNode[]; - public COMMA(i: number): TerminalNode; - public COMMA(i?: number): TerminalNode | TerminalNode[] { - if (i === undefined) { - return this.getTokens(esql_parser.COMMA); - } else { - return this.getToken(esql_parser.COMMA, i); + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitEnrichIdentifier) { + listener.exitEnrichIdentifier(this); } } +} + + +export class FunctionExpressionArgumentContext extends ParserRuleContext { + public qualifiedName(): QualifiedNameContext | undefined { + return this.tryGetRuleContext(0, QualifiedNameContext); + } + public string(): StringContext | undefined { + return this.tryGetRuleContext(0, StringContext); + } + public number(): NumberContext | undefined { + return this.tryGetRuleContext(0, NumberContext); + } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_fields; } + public get ruleIndex(): number { return esql_parser.RULE_functionExpressionArgument; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterFields) { - listener.enterFields(this); + if (listener.enterFunctionExpressionArgument) { + listener.enterFunctionExpressionArgument(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitFields) { - listener.exitFields(this); + if (listener.exitFunctionExpressionArgument) { + listener.exitFunctionExpressionArgument(this); } } } -export class FieldContext extends ParserRuleContext { - public booleanExpression(): BooleanExpressionContext { - return this.getRuleContext(0, BooleanExpressionContext); +export class MathFunctionExpressionArgumentContext extends ParserRuleContext { + public qualifiedName(): QualifiedNameContext | undefined { + return this.tryGetRuleContext(0, QualifiedNameContext); } - public userVariable(): UserVariableContext | undefined { - return this.tryGetRuleContext(0, UserVariableContext); + public string(): StringContext | undefined { + return this.tryGetRuleContext(0, StringContext); + } + public number(): NumberContext | undefined { + return this.tryGetRuleContext(0, NumberContext); + } + public operatorExpression(): OperatorExpressionContext | undefined { + return this.tryGetRuleContext(0, OperatorExpressionContext); + } + public DATE_LITERAL(): TerminalNode | undefined { return this.tryGetToken(esql_parser.DATE_LITERAL, 0); } + public comparison(): ComparisonContext | undefined { + return this.tryGetRuleContext(0, ComparisonContext); } - public ASSIGN(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASSIGN, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_field; } + public get ruleIndex(): number { return esql_parser.RULE_mathFunctionExpressionArgument; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterField) { - listener.enterField(this); + if (listener.enterMathFunctionExpressionArgument) { + listener.enterMathFunctionExpressionArgument(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitField) { - listener.exitField(this); + if (listener.exitMathFunctionExpressionArgument) { + listener.exitMathFunctionExpressionArgument(this); } } } -export class UserVariableContext extends ParserRuleContext { - public identifier(): IdentifierContext { - return this.getRuleContext(0, IdentifierContext); +export class QualifiedNameContext extends ParserRuleContext { + public identifier(): IdentifierContext[]; + public identifier(i: number): IdentifierContext; + public identifier(i?: number): IdentifierContext | IdentifierContext[] { + if (i === undefined) { + return this.getRuleContexts(IdentifierContext); + } else { + return this.getRuleContext(i, IdentifierContext); + } + } + public DOT(): TerminalNode[]; + public DOT(i: number): TerminalNode; + public DOT(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.DOT); + } else { + return this.getToken(esql_parser.DOT, i); + } } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_userVariable; } + public get ruleIndex(): number { return esql_parser.RULE_qualifiedName; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterUserVariable) { - listener.enterUserVariable(this); + if (listener.enterQualifiedName) { + listener.enterQualifiedName(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitUserVariable) { - listener.exitUserVariable(this); + if (listener.exitQualifiedName) { + listener.exitQualifiedName(this); } } } -export class FromCommandContext extends ParserRuleContext { - public FROM(): TerminalNode { return this.getToken(esql_parser.FROM, 0); } - public sourceIdentifier(): SourceIdentifierContext[]; - public sourceIdentifier(i: number): SourceIdentifierContext; - public sourceIdentifier(i?: number): SourceIdentifierContext | SourceIdentifierContext[] { +export class QualifiedNamesContext extends ParserRuleContext { + public qualifiedName(): QualifiedNameContext[]; + public qualifiedName(i: number): QualifiedNameContext; + public qualifiedName(i?: number): QualifiedNameContext | QualifiedNameContext[] { if (i === undefined) { - return this.getRuleContexts(SourceIdentifierContext); + return this.getRuleContexts(QualifiedNameContext); } else { - return this.getRuleContext(i, SourceIdentifierContext); + return this.getRuleContext(i, QualifiedNameContext); } } public COMMA(): TerminalNode[]; @@ -2556,173 +4658,209 @@ export class FromCommandContext extends ParserRuleContext { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_fromCommand; } + public get ruleIndex(): number { return esql_parser.RULE_qualifiedNames; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterFromCommand) { - listener.enterFromCommand(this); + if (listener.enterQualifiedNames) { + listener.enterQualifiedNames(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitFromCommand) { - listener.exitFromCommand(this); + if (listener.exitQualifiedNames) { + listener.exitQualifiedNames(this); } } } -export class EvalCommandContext extends ParserRuleContext { - public EVAL(): TerminalNode { return this.getToken(esql_parser.EVAL, 0); } - public fields(): FieldsContext { - return this.getRuleContext(0, FieldsContext); - } +export class IdentifierContext extends ParserRuleContext { + public UNQUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.UNQUOTED_IDENTIFIER, 0); } + public QUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.QUOTED_IDENTIFIER, 0); } + public ASTERISK(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASTERISK, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_evalCommand; } + public get ruleIndex(): number { return esql_parser.RULE_identifier; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterEvalCommand) { - listener.enterEvalCommand(this); + if (listener.enterIdentifier) { + listener.enterIdentifier(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitEvalCommand) { - listener.exitEvalCommand(this); + if (listener.exitIdentifier) { + listener.exitIdentifier(this); } } } -export class StatsCommandContext extends ParserRuleContext { - public STATS(): TerminalNode { return this.getToken(esql_parser.STATS, 0); } - public fields(): FieldsContext { - return this.getRuleContext(0, FieldsContext); - } - public BY(): TerminalNode | undefined { return this.tryGetToken(esql_parser.BY, 0); } - public qualifiedNames(): QualifiedNamesContext | undefined { - return this.tryGetRuleContext(0, QualifiedNamesContext); - } +export class MathFunctionIdentifierContext extends ParserRuleContext { + public MATH_FUNCTION(): TerminalNode { return this.getToken(esql_parser.MATH_FUNCTION, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_statsCommand; } + public get ruleIndex(): number { return esql_parser.RULE_mathFunctionIdentifier; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterStatsCommand) { - listener.enterStatsCommand(this); + if (listener.enterMathFunctionIdentifier) { + listener.enterMathFunctionIdentifier(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitStatsCommand) { - listener.exitStatsCommand(this); + if (listener.exitMathFunctionIdentifier) { + listener.exitMathFunctionIdentifier(this); } } } -export class SourceIdentifierContext extends ParserRuleContext { - public SRC_UNQUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.SRC_UNQUOTED_IDENTIFIER, 0); } - public SRC_QUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.SRC_QUOTED_IDENTIFIER, 0); } +export class FunctionIdentifierContext extends ParserRuleContext { + public UNARY_FUNCTION(): TerminalNode { return this.getToken(esql_parser.UNARY_FUNCTION, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_sourceIdentifier; } + public get ruleIndex(): number { return esql_parser.RULE_functionIdentifier; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterSourceIdentifier) { - listener.enterSourceIdentifier(this); + if (listener.enterFunctionIdentifier) { + listener.enterFunctionIdentifier(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitSourceIdentifier) { - listener.exitSourceIdentifier(this); + if (listener.exitFunctionIdentifier) { + listener.exitFunctionIdentifier(this); } } } -export class FunctionExpressionArgumentContext extends ParserRuleContext { - public qualifiedName(): QualifiedNameContext | undefined { - return this.tryGetRuleContext(0, QualifiedNameContext); +export class ConstantContext extends ParserRuleContext { + public NULL(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NULL, 0); } + public numericValue(): NumericValueContext[]; + public numericValue(i: number): NumericValueContext; + public numericValue(i?: number): NumericValueContext | NumericValueContext[] { + if (i === undefined) { + return this.getRuleContexts(NumericValueContext); + } else { + return this.getRuleContext(i, NumericValueContext); + } } - public string(): StringContext | undefined { - return this.tryGetRuleContext(0, StringContext); + public booleanValue(): BooleanValueContext[]; + public booleanValue(i: number): BooleanValueContext; + public booleanValue(i?: number): BooleanValueContext | BooleanValueContext[] { + if (i === undefined) { + return this.getRuleContexts(BooleanValueContext); + } else { + return this.getRuleContext(i, BooleanValueContext); + } + } + public string(): StringContext[]; + public string(i: number): StringContext; + public string(i?: number): StringContext | StringContext[] { + if (i === undefined) { + return this.getRuleContexts(StringContext); + } else { + return this.getRuleContext(i, StringContext); + } + } + public OPENING_BRACKET(): TerminalNode | undefined { return this.tryGetToken(esql_parser.OPENING_BRACKET, 0); } + public CLOSING_BRACKET(): TerminalNode | undefined { return this.tryGetToken(esql_parser.CLOSING_BRACKET, 0); } + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_functionExpressionArgument; } + public get ruleIndex(): number { return esql_parser.RULE_constant; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterFunctionExpressionArgument) { - listener.enterFunctionExpressionArgument(this); + if (listener.enterConstant) { + listener.enterConstant(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitFunctionExpressionArgument) { - listener.exitFunctionExpressionArgument(this); + if (listener.exitConstant) { + listener.exitConstant(this); } } } -export class QualifiedNameContext extends ParserRuleContext { - public identifier(): IdentifierContext[]; - public identifier(i: number): IdentifierContext; - public identifier(i?: number): IdentifierContext | IdentifierContext[] { - if (i === undefined) { - return this.getRuleContexts(IdentifierContext); - } else { - return this.getRuleContext(i, IdentifierContext); +export class NumericValueContext extends ParserRuleContext { + public decimalValue(): DecimalValueContext | undefined { + return this.tryGetRuleContext(0, DecimalValueContext); + } + public integerValue(): IntegerValueContext | undefined { + return this.tryGetRuleContext(0, IntegerValueContext); + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_numericValue; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterNumericValue) { + listener.enterNumericValue(this); } } - public DOT(): TerminalNode[]; - public DOT(i: number): TerminalNode; - public DOT(i?: number): TerminalNode | TerminalNode[] { - if (i === undefined) { - return this.getTokens(esql_parser.DOT); - } else { - return this.getToken(esql_parser.DOT, i); + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitNumericValue) { + listener.exitNumericValue(this); } } +} + + +export class LimitCommandContext extends ParserRuleContext { + public LIMIT(): TerminalNode { return this.getToken(esql_parser.LIMIT, 0); } + public INTEGER_LITERAL(): TerminalNode { return this.getToken(esql_parser.INTEGER_LITERAL, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_qualifiedName; } + public get ruleIndex(): number { return esql_parser.RULE_limitCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterQualifiedName) { - listener.enterQualifiedName(this); + if (listener.enterLimitCommand) { + listener.enterLimitCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitQualifiedName) { - listener.exitQualifiedName(this); + if (listener.exitLimitCommand) { + listener.exitLimitCommand(this); } } } -export class QualifiedNamesContext extends ParserRuleContext { - public qualifiedName(): QualifiedNameContext[]; - public qualifiedName(i: number): QualifiedNameContext; - public qualifiedName(i?: number): QualifiedNameContext | QualifiedNameContext[] { +export class SortCommandContext extends ParserRuleContext { + public SORT(): TerminalNode { return this.getToken(esql_parser.SORT, 0); } + public orderExpression(): OrderExpressionContext[]; + public orderExpression(i: number): OrderExpressionContext; + public orderExpression(i?: number): OrderExpressionContext | OrderExpressionContext[] { if (i === undefined) { - return this.getRuleContexts(QualifiedNameContext); + return this.getRuleContexts(OrderExpressionContext); } else { - return this.getRuleContext(i, QualifiedNameContext); + return this.getRuleContext(i, OrderExpressionContext); } } public COMMA(): TerminalNode[]; @@ -2738,260 +4876,298 @@ export class QualifiedNamesContext extends ParserRuleContext { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_qualifiedNames; } + public get ruleIndex(): number { return esql_parser.RULE_sortCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterQualifiedNames) { - listener.enterQualifiedNames(this); + if (listener.enterSortCommand) { + listener.enterSortCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitQualifiedNames) { - listener.exitQualifiedNames(this); + if (listener.exitSortCommand) { + listener.exitSortCommand(this); } } } -export class IdentifierContext extends ParserRuleContext { - public UNQUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.UNQUOTED_IDENTIFIER, 0); } - public QUOTED_IDENTIFIER(): TerminalNode | undefined { return this.tryGetToken(esql_parser.QUOTED_IDENTIFIER, 0); } +export class OrderExpressionContext extends ParserRuleContext { + public booleanExpression(): BooleanExpressionContext { + return this.getRuleContext(0, BooleanExpressionContext); + } + public ORDERING(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ORDERING, 0); } + public NULLS_ORDERING(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NULLS_ORDERING, 0); } + public NULLS_ORDERING_DIRECTION(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NULLS_ORDERING_DIRECTION, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_identifier; } + public get ruleIndex(): number { return esql_parser.RULE_orderExpression; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterIdentifier) { - listener.enterIdentifier(this); + if (listener.enterOrderExpression) { + listener.enterOrderExpression(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitIdentifier) { - listener.exitIdentifier(this); + if (listener.exitOrderExpression) { + listener.exitOrderExpression(this); } } } -export class FunctionIdentifierContext extends ParserRuleContext { - public UNARY_FUNCTION(): TerminalNode { return this.getToken(esql_parser.UNARY_FUNCTION, 0); } +export class ProjectCommandContext extends ParserRuleContext { + public PROJECT(): TerminalNode { return this.getToken(esql_parser.PROJECT, 0); } + public qualifiedNames(): QualifiedNamesContext { + return this.getRuleContext(0, QualifiedNamesContext); + } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_functionIdentifier; } + public get ruleIndex(): number { return esql_parser.RULE_projectCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterFunctionIdentifier) { - listener.enterFunctionIdentifier(this); + if (listener.enterProjectCommand) { + listener.enterProjectCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitFunctionIdentifier) { - listener.exitFunctionIdentifier(this); + if (listener.exitProjectCommand) { + listener.exitProjectCommand(this); } } } -export class ConstantContext extends ParserRuleContext { +export class KeepCommandContext extends ParserRuleContext { + public KEEP(): TerminalNode { return this.getToken(esql_parser.KEEP, 0); } + public qualifiedNames(): QualifiedNamesContext { + return this.getRuleContext(0, QualifiedNamesContext); + } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_constant; } - public copyFrom(ctx: ConstantContext): void { - super.copyFrom(ctx); - } -} -export class NullLiteralContext extends ConstantContext { - public NULL(): TerminalNode { return this.getToken(esql_parser.NULL, 0); } - constructor(ctx: ConstantContext) { - super(ctx.parent, ctx.invokingState); - this.copyFrom(ctx); - } + public get ruleIndex(): number { return esql_parser.RULE_keepCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterNullLiteral) { - listener.enterNullLiteral(this); + if (listener.enterKeepCommand) { + listener.enterKeepCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitNullLiteral) { - listener.exitNullLiteral(this); + if (listener.exitKeepCommand) { + listener.exitKeepCommand(this); } } } -export class NumericLiteralContext extends ConstantContext { - public number(): NumberContext { - return this.getRuleContext(0, NumberContext); + + +export class DropCommandContext extends ParserRuleContext { + public DROP(): TerminalNode { return this.getToken(esql_parser.DROP, 0); } + public qualifiedNames(): QualifiedNamesContext { + return this.getRuleContext(0, QualifiedNamesContext); } - constructor(ctx: ConstantContext) { - super(ctx.parent, ctx.invokingState); - this.copyFrom(ctx); + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); } // @Override + public get ruleIndex(): number { return esql_parser.RULE_dropCommand; } + // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterNumericLiteral) { - listener.enterNumericLiteral(this); + if (listener.enterDropCommand) { + listener.enterDropCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitNumericLiteral) { - listener.exitNumericLiteral(this); + if (listener.exitDropCommand) { + listener.exitDropCommand(this); } } } -export class BooleanLiteralContext extends ConstantContext { - public booleanValue(): BooleanValueContext { - return this.getRuleContext(0, BooleanValueContext); + + +export class RenameVariableContext extends ParserRuleContext { + public identifier(): IdentifierContext[]; + public identifier(i: number): IdentifierContext; + public identifier(i?: number): IdentifierContext | IdentifierContext[] { + if (i === undefined) { + return this.getRuleContexts(IdentifierContext); + } else { + return this.getRuleContext(i, IdentifierContext); + } } - constructor(ctx: ConstantContext) { - super(ctx.parent, ctx.invokingState); - this.copyFrom(ctx); + public DOT(): TerminalNode[]; + public DOT(i: number): TerminalNode; + public DOT(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.DOT); + } else { + return this.getToken(esql_parser.DOT, i); + } + } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); } // @Override + public get ruleIndex(): number { return esql_parser.RULE_renameVariable; } + // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterBooleanLiteral) { - listener.enterBooleanLiteral(this); + if (listener.enterRenameVariable) { + listener.enterRenameVariable(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitBooleanLiteral) { - listener.exitBooleanLiteral(this); + if (listener.exitRenameVariable) { + listener.exitRenameVariable(this); } } } -export class StringLiteralContext extends ConstantContext { - public string(): StringContext { - return this.getRuleContext(0, StringContext); + + +export class RenameCommandContext extends ParserRuleContext { + public RENAME(): TerminalNode { return this.getToken(esql_parser.RENAME, 0); } + public renameClause(): RenameClauseContext[]; + public renameClause(i: number): RenameClauseContext; + public renameClause(i?: number): RenameClauseContext | RenameClauseContext[] { + if (i === undefined) { + return this.getRuleContexts(RenameClauseContext); + } else { + return this.getRuleContext(i, RenameClauseContext); + } } - constructor(ctx: ConstantContext) { - super(ctx.parent, ctx.invokingState); - this.copyFrom(ctx); + public COMMA(): TerminalNode[]; + public COMMA(i: number): TerminalNode; + public COMMA(i?: number): TerminalNode | TerminalNode[] { + if (i === undefined) { + return this.getTokens(esql_parser.COMMA); + } else { + return this.getToken(esql_parser.COMMA, i); + } } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_renameCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterStringLiteral) { - listener.enterStringLiteral(this); + if (listener.enterRenameCommand) { + listener.enterRenameCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitStringLiteral) { - listener.exitStringLiteral(this); + if (listener.exitRenameCommand) { + listener.exitRenameCommand(this); } } } -export class LimitCommandContext extends ParserRuleContext { - public LIMIT(): TerminalNode { return this.getToken(esql_parser.LIMIT, 0); } - public INTEGER_LITERAL(): TerminalNode { return this.getToken(esql_parser.INTEGER_LITERAL, 0); } +export class RenameClauseContext extends ParserRuleContext { + public qualifiedName(): QualifiedNameContext { + return this.getRuleContext(0, QualifiedNameContext); + } + public AS(): TerminalNode { return this.getToken(esql_parser.AS, 0); } + public renameVariable(): RenameVariableContext { + return this.getRuleContext(0, RenameVariableContext); + } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_limitCommand; } + public get ruleIndex(): number { return esql_parser.RULE_renameClause; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterLimitCommand) { - listener.enterLimitCommand(this); + if (listener.enterRenameClause) { + listener.enterRenameClause(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitLimitCommand) { - listener.exitLimitCommand(this); + if (listener.exitRenameClause) { + listener.exitRenameClause(this); } } } -export class SortCommandContext extends ParserRuleContext { - public SORT(): TerminalNode { return this.getToken(esql_parser.SORT, 0); } - public orderExpression(): OrderExpressionContext[]; - public orderExpression(i: number): OrderExpressionContext; - public orderExpression(i?: number): OrderExpressionContext | OrderExpressionContext[] { - if (i === undefined) { - return this.getRuleContexts(OrderExpressionContext); - } else { - return this.getRuleContext(i, OrderExpressionContext); - } +export class DissectCommandContext extends ParserRuleContext { + public DISSECT(): TerminalNode { return this.getToken(esql_parser.DISSECT, 0); } + public qualifiedNames(): QualifiedNamesContext { + return this.getRuleContext(0, QualifiedNamesContext); } - public COMMA(): TerminalNode[]; - public COMMA(i: number): TerminalNode; - public COMMA(i?: number): TerminalNode | TerminalNode[] { - if (i === undefined) { - return this.getTokens(esql_parser.COMMA); - } else { - return this.getToken(esql_parser.COMMA, i); - } + public string(): StringContext { + return this.getRuleContext(0, StringContext); + } + public commandOptions(): CommandOptionsContext | undefined { + return this.tryGetRuleContext(0, CommandOptionsContext); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_sortCommand; } + public get ruleIndex(): number { return esql_parser.RULE_dissectCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterSortCommand) { - listener.enterSortCommand(this); + if (listener.enterDissectCommand) { + listener.enterDissectCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitSortCommand) { - listener.exitSortCommand(this); + if (listener.exitDissectCommand) { + listener.exitDissectCommand(this); } } } -export class OrderExpressionContext extends ParserRuleContext { - public booleanExpression(): BooleanExpressionContext { - return this.getRuleContext(0, BooleanExpressionContext); +export class GrokCommandContext extends ParserRuleContext { + public GROK(): TerminalNode { return this.getToken(esql_parser.GROK, 0); } + public qualifiedNames(): QualifiedNamesContext { + return this.getRuleContext(0, QualifiedNamesContext); + } + public string(): StringContext { + return this.getRuleContext(0, StringContext); } - public ORDERING(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ORDERING, 0); } - public NULLS_ORDERING(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NULLS_ORDERING, 0); } - public NULLS_ORDERING_DIRECTION(): TerminalNode | undefined { return this.tryGetToken(esql_parser.NULLS_ORDERING_DIRECTION, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_orderExpression; } + public get ruleIndex(): number { return esql_parser.RULE_grokCommand; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterOrderExpression) { - listener.enterOrderExpression(this); + if (listener.enterGrokCommand) { + listener.enterGrokCommand(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitOrderExpression) { - listener.exitOrderExpression(this); + if (listener.exitGrokCommand) { + listener.exitGrokCommand(this); } } } -export class ProjectCommandContext extends ParserRuleContext { - public PROJECT(): TerminalNode { return this.getToken(esql_parser.PROJECT, 0); } - public projectClause(): ProjectClauseContext[]; - public projectClause(i: number): ProjectClauseContext; - public projectClause(i?: number): ProjectClauseContext | ProjectClauseContext[] { +export class CommandOptionsContext extends ParserRuleContext { + public commandOption(): CommandOptionContext[]; + public commandOption(i: number): CommandOptionContext; + public commandOption(i?: number): CommandOptionContext | CommandOptionContext[] { if (i === undefined) { - return this.getRuleContexts(ProjectClauseContext); + return this.getRuleContexts(CommandOptionContext); } else { - return this.getRuleContext(i, ProjectClauseContext); + return this.getRuleContext(i, CommandOptionContext); } } public COMMA(): TerminalNode[]; @@ -3007,50 +5183,45 @@ export class ProjectCommandContext extends ParserRuleContext { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_projectCommand; } + public get ruleIndex(): number { return esql_parser.RULE_commandOptions; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterProjectCommand) { - listener.enterProjectCommand(this); + if (listener.enterCommandOptions) { + listener.enterCommandOptions(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitProjectCommand) { - listener.exitProjectCommand(this); + if (listener.exitCommandOptions) { + listener.exitCommandOptions(this); } } } -export class ProjectClauseContext extends ParserRuleContext { - public _newName: SourceIdentifierContext; - public _oldName: SourceIdentifierContext; - public sourceIdentifier(): SourceIdentifierContext[]; - public sourceIdentifier(i: number): SourceIdentifierContext; - public sourceIdentifier(i?: number): SourceIdentifierContext | SourceIdentifierContext[] { - if (i === undefined) { - return this.getRuleContexts(SourceIdentifierContext); - } else { - return this.getRuleContext(i, SourceIdentifierContext); - } +export class CommandOptionContext extends ParserRuleContext { + public identifier(): IdentifierContext { + return this.getRuleContext(0, IdentifierContext); + } + public ASSIGN(): TerminalNode { return this.getToken(esql_parser.ASSIGN, 0); } + public constant(): ConstantContext { + return this.getRuleContext(0, ConstantContext); } - public ASSIGN(): TerminalNode | undefined { return this.tryGetToken(esql_parser.ASSIGN, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { super(parent, invokingState); } // @Override - public get ruleIndex(): number { return esql_parser.RULE_projectClause; } + public get ruleIndex(): number { return esql_parser.RULE_commandOption; } // @Override public enterRule(listener: esql_parserListener): void { - if (listener.enterProjectClause) { - listener.enterProjectClause(this); + if (listener.enterCommandOption) { + listener.enterCommandOption(this); } } // @Override public exitRule(listener: esql_parserListener): void { - if (listener.exitProjectClause) { - listener.exitProjectClause(this); + if (listener.exitCommandOption) { + listener.exitCommandOption(this); } } } @@ -3128,6 +5299,50 @@ export class IntegerLiteralContext extends NumberContext { } +export class DecimalValueContext extends ParserRuleContext { + public DECIMAL_LITERAL(): TerminalNode { return this.getToken(esql_parser.DECIMAL_LITERAL, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_decimalValue; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterDecimalValue) { + listener.enterDecimalValue(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitDecimalValue) { + listener.exitDecimalValue(this); + } + } +} + + +export class IntegerValueContext extends ParserRuleContext { + public INTEGER_LITERAL(): TerminalNode { return this.getToken(esql_parser.INTEGER_LITERAL, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_integerValue; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterIntegerValue) { + listener.enterIntegerValue(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitIntegerValue) { + listener.exitIntegerValue(this); + } + } +} + + export class StringContext extends ParserRuleContext { public STRING(): TerminalNode { return this.getToken(esql_parser.STRING, 0); } constructor(parent: ParserRuleContext | undefined, invokingState: number) { @@ -3223,3 +5438,27 @@ export class SubqueryExpressionContext extends ParserRuleContext { } +export class ShowCommandContext extends ParserRuleContext { + public SHOW(): TerminalNode { return this.getToken(esql_parser.SHOW, 0); } + public INFO(): TerminalNode | undefined { return this.tryGetToken(esql_parser.INFO, 0); } + public FUNCTIONS(): TerminalNode | undefined { return this.tryGetToken(esql_parser.FUNCTIONS, 0); } + constructor(parent: ParserRuleContext | undefined, invokingState: number) { + super(parent, invokingState); + } + // @Override + public get ruleIndex(): number { return esql_parser.RULE_showCommand; } + // @Override + public enterRule(listener: esql_parserListener): void { + if (listener.enterShowCommand) { + listener.enterShowCommand(this); + } + } + // @Override + public exitRule(listener: esql_parserListener): void { + if (listener.exitShowCommand) { + listener.exitShowCommand(this); + } + } +} + + diff --git a/packages/kbn-monaco/src/esql/antlr/esql_parser_listener.ts b/packages/kbn-monaco/src/esql/antlr/esql_parser_listener.ts index 2b943a8bcff45..99a91b0bd84a3 100644 --- a/packages/kbn-monaco/src/esql/antlr/esql_parser_listener.ts +++ b/packages/kbn-monaco/src/esql/antlr/esql_parser_listener.ts @@ -4,10 +4,6 @@ import { ParseTreeListener } from "antlr4ts/tree/ParseTreeListener"; -import { NullLiteralContext } from "./esql_parser"; -import { NumericLiteralContext } from "./esql_parser"; -import { BooleanLiteralContext } from "./esql_parser"; -import { StringLiteralContext } from "./esql_parser"; import { DecimalLiteralContext } from "./esql_parser"; import { IntegerLiteralContext } from "./esql_parser"; import { SingleCommandQueryContext } from "./esql_parser"; @@ -16,38 +12,61 @@ import { SingleStatementContext } from "./esql_parser"; import { QueryContext } from "./esql_parser"; import { SourceCommandContext } from "./esql_parser"; import { ProcessingCommandContext } from "./esql_parser"; +import { EnrichCommandContext } from "./esql_parser"; +import { EnrichWithClauseContext } from "./esql_parser"; +import { MvExpandCommandContext } from "./esql_parser"; import { WhereCommandContext } from "./esql_parser"; +import { WhereBooleanExpressionContext } from "./esql_parser"; import { BooleanExpressionContext } from "./esql_parser"; +import { RegexBooleanExpressionContext } from "./esql_parser"; import { ValueExpressionContext } from "./esql_parser"; import { ComparisonContext } from "./esql_parser"; import { MathFnContext } from "./esql_parser"; +import { MathEvalFnContext } from "./esql_parser"; import { OperatorExpressionContext } from "./esql_parser"; import { PrimaryExpressionContext } from "./esql_parser"; import { RowCommandContext } from "./esql_parser"; import { FieldsContext } from "./esql_parser"; import { FieldContext } from "./esql_parser"; +import { EnrichFieldIdentifierContext } from "./esql_parser"; import { UserVariableContext } from "./esql_parser"; import { FromCommandContext } from "./esql_parser"; +import { MetadataContext } from "./esql_parser"; import { EvalCommandContext } from "./esql_parser"; import { StatsCommandContext } from "./esql_parser"; import { SourceIdentifierContext } from "./esql_parser"; +import { EnrichIdentifierContext } from "./esql_parser"; import { FunctionExpressionArgumentContext } from "./esql_parser"; +import { MathFunctionExpressionArgumentContext } from "./esql_parser"; import { QualifiedNameContext } from "./esql_parser"; import { QualifiedNamesContext } from "./esql_parser"; import { IdentifierContext } from "./esql_parser"; +import { MathFunctionIdentifierContext } from "./esql_parser"; import { FunctionIdentifierContext } from "./esql_parser"; import { ConstantContext } from "./esql_parser"; +import { NumericValueContext } from "./esql_parser"; import { LimitCommandContext } from "./esql_parser"; import { SortCommandContext } from "./esql_parser"; import { OrderExpressionContext } from "./esql_parser"; import { ProjectCommandContext } from "./esql_parser"; -import { ProjectClauseContext } from "./esql_parser"; +import { KeepCommandContext } from "./esql_parser"; +import { DropCommandContext } from "./esql_parser"; +import { RenameVariableContext } from "./esql_parser"; +import { RenameCommandContext } from "./esql_parser"; +import { RenameClauseContext } from "./esql_parser"; +import { DissectCommandContext } from "./esql_parser"; +import { GrokCommandContext } from "./esql_parser"; +import { CommandOptionsContext } from "./esql_parser"; +import { CommandOptionContext } from "./esql_parser"; import { BooleanValueContext } from "./esql_parser"; import { NumberContext } from "./esql_parser"; +import { DecimalValueContext } from "./esql_parser"; +import { IntegerValueContext } from "./esql_parser"; import { StringContext } from "./esql_parser"; import { ComparisonOperatorContext } from "./esql_parser"; import { ExplainCommandContext } from "./esql_parser"; import { SubqueryExpressionContext } from "./esql_parser"; +import { ShowCommandContext } from "./esql_parser"; /** @@ -55,58 +74,6 @@ import { SubqueryExpressionContext } from "./esql_parser"; * `esql_parser`. */ export interface esql_parserListener extends ParseTreeListener { - /** - * Enter a parse tree produced by the `nullLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - enterNullLiteral?: (ctx: NullLiteralContext) => void; - /** - * Exit a parse tree produced by the `nullLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - exitNullLiteral?: (ctx: NullLiteralContext) => void; - - /** - * Enter a parse tree produced by the `numericLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - enterNumericLiteral?: (ctx: NumericLiteralContext) => void; - /** - * Exit a parse tree produced by the `numericLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - exitNumericLiteral?: (ctx: NumericLiteralContext) => void; - - /** - * Enter a parse tree produced by the `booleanLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - enterBooleanLiteral?: (ctx: BooleanLiteralContext) => void; - /** - * Exit a parse tree produced by the `booleanLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - exitBooleanLiteral?: (ctx: BooleanLiteralContext) => void; - - /** - * Enter a parse tree produced by the `stringLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - enterStringLiteral?: (ctx: StringLiteralContext) => void; - /** - * Exit a parse tree produced by the `stringLiteral` - * labeled alternative in `esql_parser.constant`. - * @param ctx the parse tree - */ - exitStringLiteral?: (ctx: StringLiteralContext) => void; - /** * Enter a parse tree produced by the `decimalLiteral` * labeled alternative in `esql_parser.number`. @@ -203,6 +170,39 @@ export interface esql_parserListener extends ParseTreeListener { */ exitProcessingCommand?: (ctx: ProcessingCommandContext) => void; + /** + * Enter a parse tree produced by `esql_parser.enrichCommand`. + * @param ctx the parse tree + */ + enterEnrichCommand?: (ctx: EnrichCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.enrichCommand`. + * @param ctx the parse tree + */ + exitEnrichCommand?: (ctx: EnrichCommandContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.enrichWithClause`. + * @param ctx the parse tree + */ + enterEnrichWithClause?: (ctx: EnrichWithClauseContext) => void; + /** + * Exit a parse tree produced by `esql_parser.enrichWithClause`. + * @param ctx the parse tree + */ + exitEnrichWithClause?: (ctx: EnrichWithClauseContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.mvExpandCommand`. + * @param ctx the parse tree + */ + enterMvExpandCommand?: (ctx: MvExpandCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.mvExpandCommand`. + * @param ctx the parse tree + */ + exitMvExpandCommand?: (ctx: MvExpandCommandContext) => void; + /** * Enter a parse tree produced by `esql_parser.whereCommand`. * @param ctx the parse tree @@ -214,6 +214,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitWhereCommand?: (ctx: WhereCommandContext) => void; + /** + * Enter a parse tree produced by `esql_parser.whereBooleanExpression`. + * @param ctx the parse tree + */ + enterWhereBooleanExpression?: (ctx: WhereBooleanExpressionContext) => void; + /** + * Exit a parse tree produced by `esql_parser.whereBooleanExpression`. + * @param ctx the parse tree + */ + exitWhereBooleanExpression?: (ctx: WhereBooleanExpressionContext) => void; + /** * Enter a parse tree produced by `esql_parser.booleanExpression`. * @param ctx the parse tree @@ -225,6 +236,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitBooleanExpression?: (ctx: BooleanExpressionContext) => void; + /** + * Enter a parse tree produced by `esql_parser.regexBooleanExpression`. + * @param ctx the parse tree + */ + enterRegexBooleanExpression?: (ctx: RegexBooleanExpressionContext) => void; + /** + * Exit a parse tree produced by `esql_parser.regexBooleanExpression`. + * @param ctx the parse tree + */ + exitRegexBooleanExpression?: (ctx: RegexBooleanExpressionContext) => void; + /** * Enter a parse tree produced by `esql_parser.valueExpression`. * @param ctx the parse tree @@ -258,6 +280,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitMathFn?: (ctx: MathFnContext) => void; + /** + * Enter a parse tree produced by `esql_parser.mathEvalFn`. + * @param ctx the parse tree + */ + enterMathEvalFn?: (ctx: MathEvalFnContext) => void; + /** + * Exit a parse tree produced by `esql_parser.mathEvalFn`. + * @param ctx the parse tree + */ + exitMathEvalFn?: (ctx: MathEvalFnContext) => void; + /** * Enter a parse tree produced by `esql_parser.operatorExpression`. * @param ctx the parse tree @@ -313,6 +346,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitField?: (ctx: FieldContext) => void; + /** + * Enter a parse tree produced by `esql_parser.enrichFieldIdentifier`. + * @param ctx the parse tree + */ + enterEnrichFieldIdentifier?: (ctx: EnrichFieldIdentifierContext) => void; + /** + * Exit a parse tree produced by `esql_parser.enrichFieldIdentifier`. + * @param ctx the parse tree + */ + exitEnrichFieldIdentifier?: (ctx: EnrichFieldIdentifierContext) => void; + /** * Enter a parse tree produced by `esql_parser.userVariable`. * @param ctx the parse tree @@ -335,6 +379,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitFromCommand?: (ctx: FromCommandContext) => void; + /** + * Enter a parse tree produced by `esql_parser.metadata`. + * @param ctx the parse tree + */ + enterMetadata?: (ctx: MetadataContext) => void; + /** + * Exit a parse tree produced by `esql_parser.metadata`. + * @param ctx the parse tree + */ + exitMetadata?: (ctx: MetadataContext) => void; + /** * Enter a parse tree produced by `esql_parser.evalCommand`. * @param ctx the parse tree @@ -368,6 +423,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitSourceIdentifier?: (ctx: SourceIdentifierContext) => void; + /** + * Enter a parse tree produced by `esql_parser.enrichIdentifier`. + * @param ctx the parse tree + */ + enterEnrichIdentifier?: (ctx: EnrichIdentifierContext) => void; + /** + * Exit a parse tree produced by `esql_parser.enrichIdentifier`. + * @param ctx the parse tree + */ + exitEnrichIdentifier?: (ctx: EnrichIdentifierContext) => void; + /** * Enter a parse tree produced by `esql_parser.functionExpressionArgument`. * @param ctx the parse tree @@ -379,6 +445,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitFunctionExpressionArgument?: (ctx: FunctionExpressionArgumentContext) => void; + /** + * Enter a parse tree produced by `esql_parser.mathFunctionExpressionArgument`. + * @param ctx the parse tree + */ + enterMathFunctionExpressionArgument?: (ctx: MathFunctionExpressionArgumentContext) => void; + /** + * Exit a parse tree produced by `esql_parser.mathFunctionExpressionArgument`. + * @param ctx the parse tree + */ + exitMathFunctionExpressionArgument?: (ctx: MathFunctionExpressionArgumentContext) => void; + /** * Enter a parse tree produced by `esql_parser.qualifiedName`. * @param ctx the parse tree @@ -412,6 +489,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitIdentifier?: (ctx: IdentifierContext) => void; + /** + * Enter a parse tree produced by `esql_parser.mathFunctionIdentifier`. + * @param ctx the parse tree + */ + enterMathFunctionIdentifier?: (ctx: MathFunctionIdentifierContext) => void; + /** + * Exit a parse tree produced by `esql_parser.mathFunctionIdentifier`. + * @param ctx the parse tree + */ + exitMathFunctionIdentifier?: (ctx: MathFunctionIdentifierContext) => void; + /** * Enter a parse tree produced by `esql_parser.functionIdentifier`. * @param ctx the parse tree @@ -434,6 +522,17 @@ export interface esql_parserListener extends ParseTreeListener { */ exitConstant?: (ctx: ConstantContext) => void; + /** + * Enter a parse tree produced by `esql_parser.numericValue`. + * @param ctx the parse tree + */ + enterNumericValue?: (ctx: NumericValueContext) => void; + /** + * Exit a parse tree produced by `esql_parser.numericValue`. + * @param ctx the parse tree + */ + exitNumericValue?: (ctx: NumericValueContext) => void; + /** * Enter a parse tree produced by `esql_parser.limitCommand`. * @param ctx the parse tree @@ -479,15 +578,103 @@ export interface esql_parserListener extends ParseTreeListener { exitProjectCommand?: (ctx: ProjectCommandContext) => void; /** - * Enter a parse tree produced by `esql_parser.projectClause`. + * Enter a parse tree produced by `esql_parser.keepCommand`. + * @param ctx the parse tree + */ + enterKeepCommand?: (ctx: KeepCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.keepCommand`. + * @param ctx the parse tree + */ + exitKeepCommand?: (ctx: KeepCommandContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.dropCommand`. + * @param ctx the parse tree + */ + enterDropCommand?: (ctx: DropCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.dropCommand`. + * @param ctx the parse tree + */ + exitDropCommand?: (ctx: DropCommandContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.renameVariable`. + * @param ctx the parse tree + */ + enterRenameVariable?: (ctx: RenameVariableContext) => void; + /** + * Exit a parse tree produced by `esql_parser.renameVariable`. + * @param ctx the parse tree + */ + exitRenameVariable?: (ctx: RenameVariableContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.renameCommand`. + * @param ctx the parse tree + */ + enterRenameCommand?: (ctx: RenameCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.renameCommand`. + * @param ctx the parse tree + */ + exitRenameCommand?: (ctx: RenameCommandContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.renameClause`. + * @param ctx the parse tree + */ + enterRenameClause?: (ctx: RenameClauseContext) => void; + /** + * Exit a parse tree produced by `esql_parser.renameClause`. + * @param ctx the parse tree + */ + exitRenameClause?: (ctx: RenameClauseContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.dissectCommand`. + * @param ctx the parse tree + */ + enterDissectCommand?: (ctx: DissectCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.dissectCommand`. + * @param ctx the parse tree + */ + exitDissectCommand?: (ctx: DissectCommandContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.grokCommand`. * @param ctx the parse tree */ - enterProjectClause?: (ctx: ProjectClauseContext) => void; + enterGrokCommand?: (ctx: GrokCommandContext) => void; /** - * Exit a parse tree produced by `esql_parser.projectClause`. + * Exit a parse tree produced by `esql_parser.grokCommand`. * @param ctx the parse tree */ - exitProjectClause?: (ctx: ProjectClauseContext) => void; + exitGrokCommand?: (ctx: GrokCommandContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.commandOptions`. + * @param ctx the parse tree + */ + enterCommandOptions?: (ctx: CommandOptionsContext) => void; + /** + * Exit a parse tree produced by `esql_parser.commandOptions`. + * @param ctx the parse tree + */ + exitCommandOptions?: (ctx: CommandOptionsContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.commandOption`. + * @param ctx the parse tree + */ + enterCommandOption?: (ctx: CommandOptionContext) => void; + /** + * Exit a parse tree produced by `esql_parser.commandOption`. + * @param ctx the parse tree + */ + exitCommandOption?: (ctx: CommandOptionContext) => void; /** * Enter a parse tree produced by `esql_parser.booleanValue`. @@ -511,6 +698,28 @@ export interface esql_parserListener extends ParseTreeListener { */ exitNumber?: (ctx: NumberContext) => void; + /** + * Enter a parse tree produced by `esql_parser.decimalValue`. + * @param ctx the parse tree + */ + enterDecimalValue?: (ctx: DecimalValueContext) => void; + /** + * Exit a parse tree produced by `esql_parser.decimalValue`. + * @param ctx the parse tree + */ + exitDecimalValue?: (ctx: DecimalValueContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.integerValue`. + * @param ctx the parse tree + */ + enterIntegerValue?: (ctx: IntegerValueContext) => void; + /** + * Exit a parse tree produced by `esql_parser.integerValue`. + * @param ctx the parse tree + */ + exitIntegerValue?: (ctx: IntegerValueContext) => void; + /** * Enter a parse tree produced by `esql_parser.string`. * @param ctx the parse tree @@ -554,5 +763,16 @@ export interface esql_parserListener extends ParseTreeListener { * @param ctx the parse tree */ exitSubqueryExpression?: (ctx: SubqueryExpressionContext) => void; + + /** + * Enter a parse tree produced by `esql_parser.showCommand`. + * @param ctx the parse tree + */ + enterShowCommand?: (ctx: ShowCommandContext) => void; + /** + * Exit a parse tree produced by `esql_parser.showCommand`. + * @param ctx the parse tree + */ + exitShowCommand?: (ctx: ShowCommandContext) => void; } diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/comparison_commands.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/comparison_commands.ts index ec8cfe8e596c1..92b2e8f7c31d1 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/comparison_commands.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/comparison_commands.ts @@ -85,4 +85,32 @@ export const comparisonCommandsDefinitions: AutocompleteCommandDefinition[] = [ }), sortText: 'D', }, + { + label: 'like', + insertText: 'like', + kind: 11, + detail: i18n.translate('monaco.esql.autocomplete.likeDoc', { + defaultMessage: 'Filter data based on string patterns', + }), + sortText: 'D', + }, + { + label: 'rlike', + insertText: 'rlike', + kind: 11, + detail: i18n.translate('monaco.esql.autocomplete.rlikeDoc', { + defaultMessage: 'Filter data based on string regular expressions', + }), + sortText: 'D', + }, + { + label: 'in', + insertText: 'in', + kind: 11, + detail: i18n.translate('monaco.esql.autocomplete.inDoc', { + defaultMessage: + 'Tests if the value an expression takes is contained in a list of other expressions', + }), + sortText: 'D', + }, ]; diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/dynamic_commands.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/dynamic_commands.ts index aa9a9f1777ff3..4a5a147ffcbde 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/dynamic_commands.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/dynamic_commands.ts @@ -9,6 +9,23 @@ import { i18n } from '@kbn/i18n'; import type { AutocompleteCommandDefinition } from '../types'; +export const buildPoliciesDefinitions = ( + policies: Array<{ name: string; indices: string[] }> +): AutocompleteCommandDefinition[] => + policies.map(({ name: label, indices }) => ({ + label, + insertText: label, + kind: 5, + detail: i18n.translate('monaco.esql.autocomplete.policyDefinition', { + defaultMessage: `Policy defined on {count, plural, one {index} other {indices}}: {indices}`, + values: { + count: indices.length, + indices: indices.join(', '), + }, + }), + sortText: 'D', + })); + export const buildFieldsDefinitions = (fields: string[]): AutocompleteCommandDefinition[] => fields.map((label) => ({ label, @@ -20,6 +37,37 @@ export const buildFieldsDefinitions = (fields: string[]): AutocompleteCommandDef sortText: 'D', })); +export const buildNoPoliciesAvailableDefinition = (): AutocompleteCommandDefinition[] => [ + { + label: i18n.translate('monaco.esql.autocomplete.noPoliciesLabel', { + defaultMessage: 'No available policy', + }), + insertText: '', + kind: 26, + detail: i18n.translate('monaco.esql.autocomplete.noPoliciesLabelsFound', { + defaultMessage: 'No policies found', + }), + sortText: 'D', + }, +]; + +export const buildMatchingFieldsDefinition = ( + matchingField: string, + fields: string[] +): AutocompleteCommandDefinition[] => + fields.map((label) => ({ + label, + insertText: label, + kind: 4, + detail: i18n.translate('monaco.esql.autocomplete.matchingFieldDefinition', { + defaultMessage: `Use to match on {matchingField} on the policy`, + values: { + matchingField, + }, + }), + sortText: 'D', + })); + export const buildNewVarDefinition = (label: string): AutocompleteCommandDefinition => { return { label, diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/functions_commands.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/functions_commands.ts index 119a443c40190..53add21af9f1a 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/functions_commands.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/functions_commands.ts @@ -11,21 +11,408 @@ import { buildDocumentation } from './utils'; import type { AutocompleteCommandDefinition } from '../types'; -export const roundCommandDefinition: AutocompleteCommandDefinition = { - label: 'round', - insertText: 'round', - kind: 1, - detail: i18n.translate('monaco.esql.autocomplete.roundDoc', { - defaultMessage: - 'Returns a number rounded to the decimal, specified by he closest integer value. The default is to round to an integer.', - }), - documentation: { - value: buildDocumentation('round(grouped[T]): aggregated[T]', [ - 'from index where field="value" | eval rounded = round(field)', - ]), - }, - sortText: 'C', -}; +export const whereCommandDefinition: AutocompleteCommandDefinition[] = [ + { + label: 'cidr_match', + insertText: 'cidr_match', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.cidrMatchDoc', { + defaultMessage: + 'The function takes a first parameter of type IP, followed by one or more parameters evaluated to a CIDR specificatione.', + }), + documentation: { + value: buildDocumentation('cidr_match(grouped[T]): aggregated[T]', [ + 'from index | eval cidr="10.0.0.0/8" | where cidr_match(ip_field, "127.0.0.1/30", cidr)', + ]), + }, + sortText: 'C', + }, +]; + +export const mathCommandDefinition: AutocompleteCommandDefinition[] = [ + { + label: 'round', + insertText: 'round', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.roundDoc', { + defaultMessage: + 'Returns a number rounded to the decimal, specified by he closest integer value. The default is to round to an integer.', + }), + documentation: { + value: buildDocumentation('round(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval rounded = round(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'abs', + insertText: 'abs', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.absDoc', { + defaultMessage: 'Returns the absolute value.', + }), + documentation: { + value: buildDocumentation('abs(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval abs_value = abs(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'pow', + insertText: 'pow', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.powDoc', { + defaultMessage: + 'Returns the the value of a base (first argument) raised to a power (second argument).', + }), + documentation: { + value: buildDocumentation('pow(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval s = POW(field, exponent)', + ]), + }, + sortText: 'C', + }, + { + label: 'log10', + insertText: 'log10', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.log10Doc', { + defaultMessage: 'Returns the log base 10.', + }), + documentation: { + value: buildDocumentation('log10(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval s = log10(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'concat', + insertText: 'concat', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.concatDoc', { + defaultMessage: 'Concatenates two or more strings.', + }), + documentation: { + value: buildDocumentation('concat(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval concatenated = concat(field1, "-", field2)', + ]), + }, + sortText: 'C', + }, + { + label: 'substring', + insertText: 'substring', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.substringDoc', { + defaultMessage: + 'Returns a substring of a string, specified by a start position and an optional length. This example returns the first three characters of every last name.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval new_string = substring(field, 1, 3)', + ]), + }, + sortText: 'C', + }, + { + label: 'trim', + insertText: 'trim', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.trimDoc', { + defaultMessage: 'Removes leading and trailing whitespaces from strings.', + }), + documentation: { + value: buildDocumentation('trim(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval new_string = trim(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'starts_with', + insertText: 'starts_with', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.startsWithDoc', { + defaultMessage: + 'Returns a boolean that indicates whether a keyword string starts with another string.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval new_string = starts_with(field, "a")', + ]), + }, + sortText: 'C', + }, + { + label: 'split', + insertText: 'split', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.splitDoc', { + defaultMessage: 'Splits a single valued string into multiple strings.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `ROW words="foo;bar;baz;qux;quux;corge" + | EVAL word = SPLIT(words, ";")`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_string', + insertText: 'to_string', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toStringDoc', { + defaultMessage: 'Converts to string.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL string = to_string(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_boolean', + insertText: 'to_boolean', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toBooleanDoc', { + defaultMessage: 'Converts to boolean.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL bool = to_boolean(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_datetime', + insertText: 'to_datetime', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toDateTimeDoc', { + defaultMessage: 'Converts to date.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL datetime = to_datetime(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_double', + insertText: 'to_double', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toDoubleDoc', { + defaultMessage: 'Converts to double.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL double = to_double(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_integer', + insertText: 'to_integer', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toIntegerDoc', { + defaultMessage: 'Converts to integer.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL int = to_integer(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_long', + insertText: 'to_long', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toLongDoc', { + defaultMessage: 'Converts to long.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL long = to_long(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_unsigned_long', + insertText: 'to_unsigned_long', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toUnsignedLongDoc', { + defaultMessage: 'Converts to unsigned long.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL long = to_unsigned_long(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_ip', + insertText: 'to_ip', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toIpDoc', { + defaultMessage: 'Converts to ip.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL ip = to_ip(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'to_version', + insertText: 'to_version', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.toVersionDoc', { + defaultMessage: 'Converts to version.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value"" + | EVAL version = to_version(field)`, + ]), + }, + sortText: 'C', + }, + { + label: 'date_format', + insertText: 'date_format', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.dateFormatDoc', { + defaultMessage: `Returns a string representation of a date in the provided format. If no format is specified, the "yyyy-MM-dd'T'HH:mm:ss.SSSZ" format is used.`, + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval hired = date_format(hire_date, "YYYY-MM-dd")', + ]), + }, + sortText: 'C', + }, + { + label: 'date_trunc', + insertText: 'date_trunc', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.dateTruncDoc', { + defaultMessage: `Rounds down a date to the closest interval.`, + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval year_hired = DATE_TRUNC(hire_date, 1 year)', + ]), + }, + sortText: 'C', + }, + { + label: 'date_parse', + insertText: 'date_parse', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.dateParseDoc', { + defaultMessage: `Parse dates from strings.`, + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value" | eval year_hired = date_parse(hire_date, yyyy-MM-dd'T'HH:mm:ss.SSS'Z')`, + ]), + }, + sortText: 'C', + }, + { + label: 'auto_bucket', + insertText: 'auto_bucket', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.autoBucketDoc', { + defaultMessage: `Automatically bucket dates based on a given range and bucket target.`, + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval hd = auto_bucket(hire_date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z")', + ]), + }, + sortText: 'C', + }, + { + label: 'is_finite', + insertText: 'is_finite', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.isFiniteDoc', { + defaultMessage: 'Returns a boolean that indicates whether its input is a finite number.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval s = is_finite(field/0)', + ]), + }, + sortText: 'C', + }, + { + label: 'is_infinite', + insertText: 'is_infinite', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.isInfiniteDoc', { + defaultMessage: 'Returns a boolean that indicates whether its input is infinite.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + 'from index where field="value" | eval s = is_infinite(field/0)', + ]), + }, + sortText: 'C', + }, + { + label: 'case', + insertText: 'case', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.caseDoc', { + defaultMessage: + 'Accepts pairs of conditions and values. The function returns the value that belongs to the first condition that evaluates to `true`. If the number of arguments is odd, the last argument is the default value which is returned when no condition matches.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value" | eval type = case( + languages <= 1, "monolingual", + languages <= 2, "bilingual", + "polyglot")`, + ]), + }, + sortText: 'C', + }, + { + label: 'length', + insertText: 'length', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.lengthDoc', { + defaultMessage: 'Returns the character length of a string.', + }), + documentation: { + value: buildDocumentation('substring(grouped[T]): aggregated[T]', [ + `from index where field="value" | eval fn_length = length(field)`, + ]), + }, + sortText: 'C', + }, +]; export const aggregationFunctionsDefinitions: AutocompleteCommandDefinition[] = [ { @@ -84,4 +471,75 @@ export const aggregationFunctionsDefinitions: AutocompleteCommandDefinition[] = }, sortText: 'C', }, + { + label: 'count', + insertText: 'count', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.countDoc', { + defaultMessage: 'Returns the count of the values in a field.', + }), + documentation: { + value: buildDocumentation('count(grouped[T]): aggregated[T]', [ + 'from index | stats count = count(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'count_distinct', + insertText: 'count_distinct', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.countDistinctDoc', { + defaultMessage: 'Returns the count of distinct values in a field.', + }), + documentation: { + value: buildDocumentation('count(grouped[T]): aggregated[T]', [ + 'from index | stats count = count_distinct(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'median', + insertText: 'median', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.medianDoc', { + defaultMessage: 'Returns the 50% percentile.', + }), + documentation: { + value: buildDocumentation('count(grouped[T]): aggregated[T]', [ + 'from index | stats count = median(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'median_absolute_deviation', + insertText: 'median_absolute_deviation', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.medianDeviationDoc', { + defaultMessage: + 'Returns the median of each data point’s deviation from the median of the entire sample.', + }), + documentation: { + value: buildDocumentation('count(grouped[T]): aggregated[T]', [ + 'from index | stats count = median_absolute_deviation(field)', + ]), + }, + sortText: 'C', + }, + { + label: 'percentile', + insertText: 'percentile', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.percentiletDoc', { + defaultMessage: 'Returns the n percentile of a field.', + }), + documentation: { + value: buildDocumentation('percentile(grouped[T]): aggregated[T]', [ + 'from index | stats pct = percentile(field, 90)', + ]), + }, + sortText: 'C', + }, ]; diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/index.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/index.ts index ef096d678acc3..e1fb514cfa4de 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/index.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/index.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -export { aggregationFunctionsDefinitions, roundCommandDefinition } from './functions_commands'; +export { + aggregationFunctionsDefinitions, + mathCommandDefinition, + whereCommandDefinition, +} from './functions_commands'; export { sourceCommandsDefinitions } from './source_commands'; export { processingCommandsDefinitions, pipeDefinition } from './processing_commands'; @@ -17,6 +21,7 @@ export { export { mathOperatorsCommandsDefinitions, assignOperatorDefinition, + asOperatorDefinition, byOperatorDefinition, openBracketDefinition, closeBracketDefinition, diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/operators_commands.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/operators_commands.ts index 21a5f6260cedd..91ccb74cb9501 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/operators_commands.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/operators_commands.ts @@ -11,7 +11,7 @@ import type { AutocompleteCommandDefinition } from '../types'; export const byOperatorDefinition: AutocompleteCommandDefinition = { label: 'by', - insertText: 'by ', + insertText: 'by', kind: 21, detail: i18n.translate('monaco.esql.autocomplete.byDoc', { defaultMessage: 'By', @@ -19,6 +19,36 @@ export const byOperatorDefinition: AutocompleteCommandDefinition = { sortText: 'D', }; +export const onOperatorDefinition: AutocompleteCommandDefinition = { + label: 'on', + insertText: 'on', + kind: 21, + detail: i18n.translate('monaco.esql.autocomplete.onDoc', { + defaultMessage: 'On', + }), + sortText: 'D', +}; + +export const withOperatorDefinition: AutocompleteCommandDefinition = { + label: 'with', + insertText: 'with', + kind: 21, + detail: i18n.translate('monaco.esql.autocomplete.withDoc', { + defaultMessage: 'With', + }), + sortText: 'D', +}; + +export const asOperatorDefinition: AutocompleteCommandDefinition = { + label: 'as', + insertText: 'as', + kind: 11, + detail: i18n.translate('monaco.esql.autocomplete.asDoc', { + defaultMessage: 'As', + }), + sortText: 'D', +}; + export const assignOperatorDefinition: AutocompleteCommandDefinition = { label: '=', insertText: '=', diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/processing_commands.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/processing_commands.ts index 8dbc1ebe3d9c0..a53330d638158 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/processing_commands.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_definitions/processing_commands.ts @@ -66,6 +66,46 @@ export const processingCommandsDefinitions: AutocompleteCommandDefinition[] = [ }, sortText: 'B', }, + { + label: 'keep', + insertText: 'keep', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.keepDoc', { + defaultMessage: 'Rearranges fields in the input table by applying the keep clauses in fields', + }), + documentation: { + value: buildDocumentation('keep fieldSpecification `,` fieldSpecification *', [ + '… | keep a,b', + ]), + }, + sortText: 'B', + }, + { + label: 'rename', + insertText: 'rename', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.renameDoc', { + defaultMessage: 'Renames an old column to a new one', + }), + documentation: { + value: buildDocumentation('rename new as old', ['… | rename a as b']), + }, + sortText: 'B', + }, + { + label: 'drop', + insertText: 'drop', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.dropDoc', { + defaultMessage: 'Drops columns', + }), + documentation: { + value: buildDocumentation('drop fieldSpecification `,` fieldSpecification *', [ + '… | drop a,b', + ]), + }, + sortText: 'B', + }, { label: 'sort', insertText: 'sort', @@ -96,4 +136,61 @@ export const processingCommandsDefinitions: AutocompleteCommandDefinition[] = [ }, sortText: 'B', }, + { + label: 'dissect', + insertText: 'dissect', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.dissectDoc', { + defaultMessage: + 'Extracts multiple string values from a single string input, based on a pattern', + }), + documentation: { + value: buildDocumentation( + 'dissect (append_separator=)?', + ['… | dissect a "%{b} %{c}";'] + ), + }, + sortText: 'B', + }, + { + label: 'grok', + insertText: 'grok', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.grokDoc', { + defaultMessage: + 'Extracts multiple string values from a single string input, based on a pattern', + }), + documentation: { + value: buildDocumentation('grok ', [ + '… | grok a "%{b} %{c}";', + ]), + }, + sortText: 'B', + }, + { + label: 'mv_expand', + insertText: 'mv_expand', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.mvExpandDoc', { + defaultMessage: 'Expands multivalued fields into one row per value, duplicating other fields', + }), + documentation: { + value: buildDocumentation('mv_expand field', [ + 'ROW a=[1,2,3], b="b", j=["a","b"] | MV_EXPAND a', + ]), + }, + sortText: 'B', + }, + { + label: 'enrich', + insertText: 'enrich', + kind: 1, + detail: i18n.translate('monaco.esql.autocomplete.enrichDoc', { + defaultMessage: 'Enrich table with another table', + }), + documentation: { + value: buildDocumentation('enrich policy', ['... | ENRICH a']), + }, + sortText: 'B', + }, ]; diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.test.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.test.ts index 157d111154f1f..bbcdb04060689 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.test.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.test.ts @@ -38,12 +38,22 @@ describe('autocomplete_listener', () => { testSuggestions('f', ['from']); testSuggestions('from ', ['SourceIdentifier']); testSuggestions('from a,', ['SourceIdentifier']); - testSuggestions('from a, b ', ['|']); + testSuggestions('from a, b ', ['SourceIdentifier']); }); describe('where', () => { - testSuggestions('from a | where ', ['FieldIdentifier']); - testSuggestions('from a | where "field" ', ['==', '!=', '<', '>', '<=', '>=']); + testSuggestions('from a | where ', ['cidr_match', 'FieldIdentifier']); + testSuggestions('from a | where "field" ', [ + '==', + '!=', + '<', + '>', + '<=', + '>=', + 'like', + 'rlike', + 'in', + ]); testSuggestions('from a | where "field" >= ', ['FieldIdentifier']); testSuggestions('from a | where "field" >= "field1" ', ['or', 'and', '|']); testSuggestions('from a | where "field" >= "field1" and ', ['FieldIdentifier']); @@ -54,9 +64,32 @@ describe('autocomplete_listener', () => { '>', '<=', '>=', + 'like', + 'rlike', + 'in', + ]); + testSuggestions('from a | stats a=avg("field") | where a ', [ + '==', + '!=', + '<', + '>', + '<=', + '>=', + 'like', + 'rlike', + 'in', + ]); + testSuggestions('from a | stats a=avg("b") | where "c" ', [ + '==', + '!=', + '<', + '>', + '<=', + '>=', + 'like', + 'rlike', + 'in', ]); - testSuggestions('from a | stats a=avg("field") | where a ', ['==', '!=', '<', '>', '<=', '>=']); - testSuggestions('from a | stats a=avg("b") | where "c" ', ['==', '!=', '<', '>', '<=', '>=']); testSuggestions('from a | where "field" >= "field1" and "field2 == ', ['FieldIdentifier']); }); @@ -72,11 +105,25 @@ describe('autocomplete_listener', () => { testSuggestions('from a | limit 4 ', ['|']); }); + describe('mv_expand', () => { + testSuggestions('from a | mv_expand ', ['FieldIdentifier']); + testSuggestions('from a | mv_expand a ', ['|']); + }); + describe('stats', () => { testSuggestions('from a | stats ', ['var0']); testSuggestions('from a | stats a ', ['=']); - testSuggestions('from a | stats a=', ['avg', 'max', 'min', 'sum', 'FieldIdentifier']); - testSuggestions('from a | stats a=b', ['|', 'by']); + testSuggestions('from a | stats a=', [ + 'avg', + 'max', + 'min', + 'sum', + 'count', + 'count_distinct', + 'median', + 'median_absolute_deviation', + 'percentile', + ]); testSuggestions('from a | stats a=b by ', ['FieldIdentifier']); testSuggestions('from a | stats a=c by d', ['|']); testSuggestions('from a | stats a=b, ', ['var0']); @@ -90,11 +137,75 @@ describe('autocomplete_listener', () => { testSuggestions('from a | stats a=min(b), b=max(', ['FieldIdentifier']); }); + describe('enrich', () => { + for (const prevCommand of [ + '', + '| enrich other-policy ', + '| enrich other-policy on b ', + '| enrich other-policy with c ', + ]) { + testSuggestions(`from a ${prevCommand}| enrich`, ['PolicyIdentifier']); + testSuggestions(`from a ${prevCommand}| enrich policy `, ['|', 'on', 'with']); + testSuggestions(`from a ${prevCommand}| enrich policy on `, [ + 'PolicyMatchingFieldIdentifier', + ]); + testSuggestions(`from a ${prevCommand}| enrich policy on b `, ['|', 'with']); + testSuggestions(`from a ${prevCommand}| enrich policy on b with `, [ + 'var0', + 'PolicyFieldIdentifier', + ]); + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 `, ['=', '|']); + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = `, [ + 'PolicyFieldIdentifier', + ]); + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = c `, ['|']); + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = c, `, [ + 'var1', + 'PolicyFieldIdentifier', + ]); + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = c, var1 `, ['=', '|']); + testSuggestions(`from a ${prevCommand}| enrich policy on b with var0 = c, var1 = `, [ + 'PolicyFieldIdentifier', + ]); + testSuggestions(`from a ${prevCommand}| enrich policy with `, [ + 'var0', + 'PolicyFieldIdentifier', + ]); + testSuggestions(`from a ${prevCommand}| enrich policy with c`, ['=', '|']); + } + }); + describe('eval', () => { testSuggestions('from a | eval ', ['var0']); testSuggestions('from a | eval a ', ['=']); - testSuggestions('from a | eval a=', ['round', 'FieldIdentifier']); - testSuggestions('from a | eval a=b', ['|', '+', '-', '/', '*']); + testSuggestions('from a | eval a=', [ + 'round', + 'abs', + 'pow', + 'log10', + 'concat', + 'substring', + 'trim', + 'starts_with', + 'split', + 'to_string', + 'to_boolean', + 'to_datetime', + 'to_double', + 'to_integer', + 'to_long', + 'to_unsigned_long', + 'to_ip', + 'to_version', + 'date_format', + 'date_trunc', + 'date_parse', + 'auto_bucket', + 'is_finite', + 'is_infinite', + 'case', + 'length', + ]); testSuggestions('from a | eval a=b, ', ['var0']); testSuggestions('from a | eval a=round', ['(']); testSuggestions('from a | eval a=round(', ['FieldIdentifier']); diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.ts index d3cda17124349..ad439caad1dce 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/autocomplete_listener.ts @@ -10,7 +10,12 @@ import type { AutocompleteCommandDefinition, UserDefinedVariables } from './type import { DynamicAutocompleteItem } from './dymanic_item'; import { esql_parserListener as ESQLParserListener } from '../../antlr/esql_parser_listener'; -import { esql_parser, esql_parser as ESQLParser } from '../../antlr/esql_parser'; +import { + esql_parser, + esql_parser as ESQLParser, + EnrichCommandContext, + EnrichWithClauseContext, +} from '../../antlr/esql_parser'; import { processingCommandsDefinitions, @@ -26,10 +31,12 @@ import { closeBracketDefinition, mathOperatorsCommandsDefinitions, aggregationFunctionsDefinitions, - roundCommandDefinition, + mathCommandDefinition, + whereCommandDefinition, assignOperatorDefinition, buildConstantsDefinitions, buildNewVarDefinition, + asOperatorDefinition, } from './autocomplete_definitions'; import { @@ -45,22 +52,49 @@ import { SourceIdentifierContext, UserVariableContext, BooleanExpressionContext, + RegexBooleanExpressionContext, + WhereBooleanExpressionContext, LimitCommandContext, ValueExpressionContext, + KeepCommandContext, + DropCommandContext, + RenameCommandContext, + DissectCommandContext, + GrokCommandContext, + MvExpandCommandContext, } from '../../antlr/esql_parser'; +import { + onOperatorDefinition, + withOperatorDefinition, +} from './autocomplete_definitions/operators_commands'; + +export function nonNullable(v: T): v is NonNullable { + return v != null; +} export class AutocompleteListener implements ESQLParserListener { private suggestions: Array = []; private readonly userDefinedVariables: UserDefinedVariables = { sourceIdentifiers: [], + policyIdentifiers: [], }; private readonly tables: string[][] = []; private parentContext: number | undefined; - private get fields() { - return this.tables.length > 1 - ? buildConstantsDefinitions(this.tables.at(-2)!) - : [DynamicAutocompleteItem.FieldIdentifier]; + private get fields(): [DynamicAutocompleteItem] { + return [DynamicAutocompleteItem.FieldIdentifier]; + } + + private get policies(): [DynamicAutocompleteItem] { + return [DynamicAutocompleteItem.PolicyIdentifier]; + } + + private get policyFields(): [DynamicAutocompleteItem] { + return [DynamicAutocompleteItem.PolicyFieldIdentifier]; + } + + private get policyMatchingField(): [DynamicAutocompleteItem] { + return [DynamicAutocompleteItem.PolicyMatchingFieldIdentifier]; } private get hasSuggestions() { @@ -71,16 +105,23 @@ export class AutocompleteListener implements ESQLParserListener { return node && node.payload?.startIndex >= 0; } - private getEndCommandSuggestions(skipDefinitions: AutocompleteCommandDefinition[] = []) { - const suggestions = [pipeDefinition]; - - if ( - !skipDefinitions.find((i) => i === byOperatorDefinition) && - this.parentContext === ESQLParser.STATS - ) { - suggestions.push(byOperatorDefinition); + private applyConditionalSuggestion( + skipDefinitions: AutocompleteCommandDefinition[], + targetDefinition: AutocompleteCommandDefinition, + context: number + ) { + if (!skipDefinitions.find((i) => i === targetDefinition) && this.parentContext === context) { + return targetDefinition; } - return suggestions; + } + + private getEndCommandSuggestions(skipDefinitions: AutocompleteCommandDefinition[] = []) { + return [ + pipeDefinition, + this.applyConditionalSuggestion(skipDefinitions, byOperatorDefinition, ESQLParser.STATS), + this.applyConditionalSuggestion(skipDefinitions, onOperatorDefinition, ESQLParser.ENRICH), + this.applyConditionalSuggestion(skipDefinitions, withOperatorDefinition, ESQLParser.ENRICH), + ].filter(nonNullable); } private getNewVarName() { @@ -112,11 +153,13 @@ export class AutocompleteListener implements ESQLParserListener { exitSourceCommand(ctx: SourceCommandContext) { if (ctx.exception) { this.suggestions = sourceCommandsDefinitions; - } else if (!this.hasSuggestions) { - this.suggestions = this.getEndCommandSuggestions(); } } + enterSourceIdentifier(ctx: SourceIdentifierContext) { + this.suggestions = [DynamicAutocompleteItem.SourceIdentifier]; + } + exitSourceIdentifier(ctx: SourceIdentifierContext) { if (!ctx.childCount) { this.suggestions = [DynamicAutocompleteItem.SourceIdentifier]; @@ -141,6 +184,11 @@ export class AutocompleteListener implements ESQLParserListener { enterStatsCommand(ctx: StatsCommandContext) { this.suggestions = []; this.parentContext = ESQLParser.STATS; + const fn = ctx.fields(); + if (!fn) { + this.suggestions = [buildNewVarDefinition(this.getNewVarName())]; + return; + } } enterEvalCommand(ctx: EvalCommandContext) { @@ -155,7 +203,84 @@ export class AutocompleteListener implements ESQLParserListener { } } + exitKeepCommand?(ctx: KeepCommandContext) { + const qn = ctx.qualifiedNames(); + if (qn && qn.text) { + if (qn.text.slice(-1) !== ',') { + this.suggestions = this.getEndCommandSuggestions(); + } + } + } + + exitDropCommand?(ctx: DropCommandContext) { + const qn = ctx.qualifiedNames(); + if (qn && qn.text) { + if (qn.text.slice(-1) !== ',') { + this.suggestions = this.getEndCommandSuggestions(); + } + } + } + + enterRenameCommand(ctx: RenameCommandContext) { + this.parentContext = ESQLParser.RENAME; + } + + exitRenameCommand?(ctx: RenameCommandContext) { + const rc = ctx.renameClause(); + const commaExists = ctx.COMMA(); + if (!rc[0].exception) { + const qn = rc[0].renameVariable(); + const asExists = this.isTerminalNodeExists(rc[0].AS()); + if (asExists && qn && !qn.text) { + this.suggestions = []; + } + if (qn && qn.text) { + if (!commaExists.length) { + this.suggestions = this.getEndCommandSuggestions(); + } + } + } + } + + exitDissectCommand?(ctx: DissectCommandContext) { + const qn = ctx.qualifiedNames(); + const pattern = ctx.string(); + if (qn && qn.text && pattern && pattern.text && pattern.text !== '') { + this.suggestions = this.getEndCommandSuggestions(); + } + } + + exitGrokCommand?(ctx: GrokCommandContext) { + const qn = ctx.qualifiedNames(); + const pattern = ctx.string(); + if (qn && qn.text && pattern && pattern.text && pattern.text !== '') { + this.suggestions = this.getEndCommandSuggestions(); + } + } + + exitMvExpandCommand?(ctx: MvExpandCommandContext) { + const qn = ctx.qualifiedNames(); + if (qn && qn.text) { + this.suggestions = this.getEndCommandSuggestions(); + } + } + exitQualifiedName(ctx: QualifiedNameContext) { + const isInEval = this.parentContext === ESQLParser.EVAL; + const isInStats = this.parentContext === ESQLParser.STATS; + const isInRename = this.parentContext === ESQLParser.RENAME; + if (this.parentContext && isInRename) { + if (!ctx.exception && ctx.text) { + this.suggestions = [asOperatorDefinition]; + } + } + if (this.parentContext && (isInStats || isInEval)) { + this.suggestions = [ + ...this.getEndCommandSuggestions(), + ...(isInEval ? mathOperatorsCommandsDefinitions : []), + ]; + } + if ( ctx .identifier() @@ -205,12 +330,12 @@ export class AutocompleteListener implements ESQLParserListener { const ve = ctx.valueExpression(); if (!ve) { if (this.parentContext === ESQLParser.STATS) { - this.suggestions = [...aggregationFunctionsDefinitions, ...this.fields]; + this.suggestions = [...aggregationFunctionsDefinitions]; return; } if (this.parentContext === ESQLParser.EVAL) { - this.suggestions = [roundCommandDefinition, ...this.fields]; + this.suggestions = [...mathCommandDefinition]; return; } } @@ -222,7 +347,9 @@ export class AutocompleteListener implements ESQLParserListener { const isInEval = this.parentContext === ESQLParser.EVAL; if (this.parentContext && (isInStats || isInEval)) { - const hasFN = ctx.tryGetToken(esql_parser.UNARY_FUNCTION, 0); + const hasFN = + ctx.tryGetToken(esql_parser.UNARY_FUNCTION, 0) || + ctx.tryGetToken(esql_parser.MATH_FUNCTION, 0); const hasLP = ctx.tryGetToken(esql_parser.LP, 0); const hasRP = ctx.tryGetToken(esql_parser.RP, 0); @@ -239,10 +366,12 @@ export class AutocompleteListener implements ESQLParserListener { } } else { if (ctx.childCount === 1) { - this.suggestions = [ - ...this.getEndCommandSuggestions(), - ...(isInEval ? mathOperatorsCommandsDefinitions : []), - ]; + if (ctx.text && ctx.text.indexOf('(') === -1) { + this.suggestions = [ + ...(isInEval ? mathCommandDefinition : []), + ...(isInStats ? aggregationFunctionsDefinitions : []), + ]; + } return; } } @@ -250,25 +379,117 @@ export class AutocompleteListener implements ESQLParserListener { } } + enterWhereBooleanExpression(ctx: WhereBooleanExpressionContext) { + this.suggestions = []; + } + enterWhereCommand(ctx: WhereCommandContext) { this.suggestions = []; this.parentContext = ESQLParser.WHERE; } + enterEnrichCommand(ctx: EnrichCommandContext) { + this.suggestions = []; + this.parentContext = ESQLParser.ENRICH; + } + + exitEnrichCommand(ctx: EnrichCommandContext) { + const policyName = ctx.enrichIdentifier().text; + if (policyName && !this.userDefinedVariables.policyIdentifiers.includes(policyName)) { + this.userDefinedVariables.policyIdentifiers.push(policyName); + } + + if (this.parentContext === ESQLParser.WITH) { + return; + } + if (!policyName) { + this.suggestions = this.policies; + } + + if (policyName) + if (this.parentContext === ESQLParser.ENRICH) { + const hasOn = this.isTerminalNodeExists(ctx.ON()); + if (hasOn && !ctx._matchField.text) { + this.suggestions = this.policyMatchingField; + } else { + this.suggestions = this.getEndCommandSuggestions( + hasOn ? [onOperatorDefinition] : undefined + ); + } + } + } + + enterEnrichWithClause(ctx: EnrichWithClauseContext) { + this.suggestions = []; + this.parentContext = ESQLParser.WITH; + } + + exitEnrichWithClause(ctx: EnrichWithClauseContext) { + const hasAssign = this.isTerminalNodeExists(ctx.ASSIGN()); + // Note: this gets filled only after the assign operation :( + if (ctx._newName?.text) { + this.tables.at(-1)?.push(ctx._newName.text); + } + + if (!ctx.exception && ctx.enrichFieldIdentifier().length === 1) { + // if it's after the assign operator, then suggest the fields from the policy + // TODO: need to check if the enrichFieldIdentifier given is a policyField or not and decide whether append the assignOperator + this.suggestions = !hasAssign + ? [assignOperatorDefinition, ...this.getEndCommandSuggestions()] + : this.policyFields; + } else { + this.suggestions = []; + if (!hasAssign) { + this.suggestions.push(buildNewVarDefinition(this.getNewVarName())); + } + if (!ctx._enrichField?.text) { + this.suggestions.push(...this.policyFields); + } + if (this.suggestions.length === 0) { + this.suggestions = this.getEndCommandSuggestions([ + onOperatorDefinition, + withOperatorDefinition, + ]); + } + } + } + exitWhereCommand(ctx: WhereCommandContext) { - const booleanExpression = ctx.booleanExpression(); + const booleanExpression = ctx.whereBooleanExpression(); if (booleanExpression.exception) { + if (!booleanExpression.text) { + this.suggestions = [...whereCommandDefinition, ...this.fields]; + return; + } this.suggestions = this.fields; return; } else { - const innerBooleanExpressions = booleanExpression.getRuleContexts(BooleanExpressionContext); + const innerBooleanExpressions = booleanExpression.getRuleContexts( + WhereBooleanExpressionContext + ); + const regexBooleanExpression = booleanExpression.getRuleContexts( + RegexBooleanExpressionContext + ); + + if (booleanExpression.WHERE_FUNCTIONS()) { + if (booleanExpression.COMMA().length) { + this.suggestions = []; + return; + } + } + + if (regexBooleanExpression.length) { + this.suggestions = []; + return; + } + if (innerBooleanExpressions.some((be) => be.exception)) { this.suggestions = this.fields; return; } } - if (!this.hasSuggestions) { + if (!this.hasSuggestions && !booleanExpression.WHERE_FUNCTIONS()) { this.suggestions = comparisonCommandsDefinitions; } } diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/dymanic_item.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/dymanic_item.ts index b819dc34059a1..621c8900447a0 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/dymanic_item.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/dymanic_item.ts @@ -9,10 +9,13 @@ export enum DynamicAutocompleteItem { SourceIdentifier = 'SourceIdentifier', FieldIdentifier = 'FieldIdentifier', + PolicyIdentifier = 'PolicyIdentifier', + PolicyFieldIdentifier = 'PolicyFieldIdentifier', + PolicyMatchingFieldIdentifier = 'PolicyMatchingFieldIdentifier', } +const DynamicAutocompleteItems = Object.values(DynamicAutocompleteItem); + export function isDynamicAutocompleteItem(v: unknown): v is DynamicAutocompleteItem { - return ( - v === DynamicAutocompleteItem.SourceIdentifier || v === DynamicAutocompleteItem.FieldIdentifier - ); + return DynamicAutocompleteItems.some((dai) => dai === v); } diff --git a/packages/kbn-monaco/src/esql/lib/autocomplete/types.ts b/packages/kbn-monaco/src/esql/lib/autocomplete/types.ts index 58438baa298a9..0b64f0871b27a 100644 --- a/packages/kbn-monaco/src/esql/lib/autocomplete/types.ts +++ b/packages/kbn-monaco/src/esql/lib/autocomplete/types.ts @@ -12,17 +12,21 @@ import { monaco } from '../../../..'; export interface ESQLCustomAutocompleteCallbacks { getSourceIdentifiers?: CallbackFn; getFieldsIdentifiers?: CallbackFn; + getPoliciesIdentifiers?: CallbackFn<{ name: string; indices: string[] }>; + getPolicyFieldsIdentifiers?: CallbackFn; + getPolicyMatchingFieldIdentifiers?: CallbackFn; } /** @internal **/ -type CallbackFn = (ctx: { +type CallbackFn = (ctx: { word: string; userDefinedVariables: UserDefinedVariables; -}) => string[] | Promise; +}) => T[] | Promise; /** @internal **/ export interface UserDefinedVariables { sourceIdentifiers: string[]; + policyIdentifiers: string[]; } /** @internal **/ diff --git a/packages/kbn-monaco/src/esql/lib/monaco/esql_completion_provider.ts b/packages/kbn-monaco/src/esql/lib/monaco/esql_completion_provider.ts index 40393fe1b844d..4a407c3519769 100644 --- a/packages/kbn-monaco/src/esql/lib/monaco/esql_completion_provider.ts +++ b/packages/kbn-monaco/src/esql/lib/monaco/esql_completion_provider.ts @@ -11,7 +11,11 @@ import { DynamicAutocompleteItem, isDynamicAutocompleteItem } from '../autocompl import { buildFieldsDefinitions, buildSourcesDefinitions, + buildPoliciesDefinitions, + buildNoPoliciesAvailableDefinition, + buildMatchingFieldsDefinition, } from '../autocomplete/autocomplete_definitions/dynamic_commands'; +import { pipeDefinition } from '../autocomplete/autocomplete_definitions'; import type { AutocompleteCommandDefinition, @@ -20,11 +24,6 @@ import type { } from '../autocomplete/types'; import type { ESQLWorker } from '../../worker/esql_worker'; -const emptyCompletionList: monaco.languages.CompletionList = { - incomplete: false, - suggestions: [], -}; - export class ESQLCompletionAdapter implements monaco.languages.CompletionItemProvider { constructor( private worker: (...uris: monaco.Uri[]) => Promise, @@ -40,16 +39,20 @@ export class ESQLCompletionAdapter implements monaco.languages.CompletionItemPro userDefinedVariables: UserDefinedVariables; } ): Promise { - let result: AutocompleteCommandDefinition[] = []; - - for (const suggestion of suggestions) { - if (isDynamicAutocompleteItem(suggestion)) { + const allSuggestions: AutocompleteCommandDefinition[][] = await Promise.all( + suggestions.map(async (suggestion) => { + if (!isDynamicAutocompleteItem(suggestion)) { + return [suggestion]; + } let dynamicItems: AutocompleteCommandDefinition[] = []; if (suggestion === DynamicAutocompleteItem.SourceIdentifier) { dynamicItems = buildSourcesDefinitions( (await this.callbacks?.getSourceIdentifiers?.(ctx)) ?? [] ); + if (!ctx.word && ctx.userDefinedVariables.sourceIdentifiers.length) { + dynamicItems = [pipeDefinition]; + } } if (suggestion === DynamicAutocompleteItem.FieldIdentifier) { @@ -57,13 +60,34 @@ export class ESQLCompletionAdapter implements monaco.languages.CompletionItemPro (await this.callbacks?.getFieldsIdentifiers?.(ctx)) ?? [] ); } - result = [...result, ...dynamicItems]; - } else { - result = [...result, suggestion]; - } - } - return result; + if (suggestion === DynamicAutocompleteItem.PolicyIdentifier) { + const results = await this.callbacks?.getPoliciesIdentifiers?.(ctx); + dynamicItems = results?.length + ? buildPoliciesDefinitions(results) + : buildNoPoliciesAvailableDefinition(); + } + + if (suggestion === DynamicAutocompleteItem.PolicyFieldIdentifier) { + dynamicItems = buildFieldsDefinitions( + (await this.callbacks?.getPolicyFieldsIdentifiers?.(ctx)) || [] + ); + } + + if (suggestion === DynamicAutocompleteItem.PolicyMatchingFieldIdentifier) { + const [fields = [], matchingField] = await Promise.all([ + this.callbacks?.getFieldsIdentifiers?.(ctx), + this.callbacks?.getPolicyMatchingFieldIdentifiers?.(ctx), + ]); + dynamicItems = matchingField?.length + ? buildMatchingFieldsDefinition(matchingField[0], fields) + : buildFieldsDefinitions(fields); + } + return dynamicItems; + }) + ); + + return allSuggestions.flat(); } async provideCompletionItems( @@ -72,21 +96,23 @@ export class ESQLCompletionAdapter implements monaco.languages.CompletionItemPro ): Promise { const lines = model.getLineCount(); - if ( + const currentLineChars = model.getValueInRange({ + startLineNumber: 0, + startColumn: 0, + endLineNumber: position.lineNumber, + endColumn: position.column, + }); + const wordInfo = model.getWordUntilPosition(position); + const worker = await this.worker(model.uri); + const providedSuggestions = lines !== position.lineNumber || model.getLineContent(position.lineNumber).trimEnd().length >= position.column - ) { - return emptyCompletionList; - } - - const worker = await this.worker(model.uri); - const wordInfo = model.getWordUntilPosition(position); - - const providedSuggestions = await worker.provideAutocompleteSuggestions(model.uri.toString(), { - word: wordInfo.word, - line: position.lineNumber, - index: position.column, - }); + ? await worker.provideAutocompleteSuggestionsFromString(currentLineChars) + : await worker.provideAutocompleteSuggestions(model.uri.toString(), { + word: wordInfo.word, + line: position.lineNumber, + index: position.column, + }); const withDynamicItems = providedSuggestions ? await this.injectDynamicAutocompleteItems(providedSuggestions.suggestions, { @@ -96,7 +122,6 @@ export class ESQLCompletionAdapter implements monaco.languages.CompletionItemPro : []; return { - incomplete: true, suggestions: withDynamicItems.map((i) => ({ ...i, range: { diff --git a/packages/kbn-monaco/src/esql/lib/monaco/esql_theme.ts b/packages/kbn-monaco/src/esql/lib/monaco/esql_theme.ts index 94c3c6bbe6897..6fc6caee2886f 100644 --- a/packages/kbn-monaco/src/esql/lib/monaco/esql_theme.ts +++ b/packages/kbn-monaco/src/esql/lib/monaco/esql_theme.ts @@ -27,7 +27,6 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ 'explain', 'row', 'limit', - 'project', 'ws', 'assign', 'comma', @@ -55,25 +54,48 @@ export const buildESQlTheme = (): monaco.editor.IStandaloneThemeData => ({ ...buildRuleGroup( [ 'from', + 'metadata', + 'mv_expand', 'stats', + 'dissect', + 'grok', + 'project', + 'keep', + 'rename', + 'drop', 'eval', 'sort', 'by', 'where', + 'not', + 'is', + 'like', + 'rlike', + 'in', + 'as', 'expr_ws', 'row', + 'show', 'limit', + 'cidr_match', 'nulls_ordering_direction', 'nulls_ordering', 'null', 'boolean_value', 'comparison_operator', + 'enrich', + 'on', + 'with', ], euiThemeVars.euiColorPrimaryText ), - // math functions + // aggregation functions ...buildRuleGroup(['unary_function'], euiThemeVars.euiColorPrimaryText), + // is null functions + ...buildRuleGroup(['where_functions'], euiThemeVars.euiColorPrimaryText), + // math functions + ...buildRuleGroup(['math_function'], euiThemeVars.euiColorPrimaryText), // operators ...buildRuleGroup( diff --git a/packages/kbn-monaco/src/esql/worker/esql_worker.ts b/packages/kbn-monaco/src/esql/worker/esql_worker.ts index 4d52c2b1094cb..4656ac9e9db7c 100644 --- a/packages/kbn-monaco/src/esql/worker/esql_worker.ts +++ b/packages/kbn-monaco/src/esql/worker/esql_worker.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { CharStreams } from 'antlr4ts'; +import { CharStreams, type CodePointCharStream } from 'antlr4ts'; import { monaco } from '../../monaco_imports'; import { AutocompleteListener } from '../lib/autocomplete/autocomplete_listener'; import type { BaseWorkerDefinition } from '../../types'; @@ -43,16 +43,9 @@ export class ESQLWorker implements BaseWorkerDefinition { return []; } - public async provideAutocompleteSuggestions( - modelUri: string, - meta: { - word: string; - line: number; - index: number; - } + private async provideAutocompleteSuggestionFromRawString( + inputStream: CodePointCharStream | undefined ) { - const inputStream = this.getModelCharStream(modelUri); - if (inputStream) { const errorListener = new ANTLREErrorListener(); const parseListener = new AutocompleteListener(); @@ -63,4 +56,19 @@ export class ESQLWorker implements BaseWorkerDefinition { return parseListener.getAutocompleteSuggestions(); } } + + public async provideAutocompleteSuggestions( + modelUri: string, + meta: { + word: string; + line: number; + index: number; + } + ) { + return this.provideAutocompleteSuggestionFromRawString(this.getModelCharStream(modelUri)); + } + + public async provideAutocompleteSuggestionsFromString(text: string) { + return this.provideAutocompleteSuggestionFromRawString(CharStreams.fromString(text)); + } } diff --git a/packages/kbn-search-api-panels/types.ts b/packages/kbn-search-api-panels/types.ts index 63edec82c345d..5aba2d7b46bc0 100644 --- a/packages/kbn-search-api-panels/types.ts +++ b/packages/kbn-search-api-panels/types.ts @@ -24,6 +24,8 @@ export interface LanguageDefinitionSnippetArguments { apiKey: string; indexName?: string; cloudId?: string; + ingestPipeline?: string; + extraIngestDocumentValues?: Record; } type CodeSnippet = string | ((args: LanguageDefinitionSnippetArguments) => string); diff --git a/packages/kbn-text-based-editor/src/__stories__/text_based_editor.stories.mdx b/packages/kbn-text-based-editor/src/__stories__/text_based_editor.stories.mdx index 0874305b1975b..f6e0a751e7755 100644 --- a/packages/kbn-text-based-editor/src/__stories__/text_based_editor.stories.mdx +++ b/packages/kbn-text-based-editor/src/__stories__/text_based_editor.stories.mdx @@ -31,7 +31,7 @@ The TextBasedLanguagesEditor component is a reusable component and can be used t name='compact mode' args={ { - query: { sql: 'SELECT field1, field2 FROM DATAVIEW' }, + query: { esql: 'from dataview | keep field1, field2' }, isCodeEditorExpanded:false, 'data-test-subj':'test-id' } @@ -51,7 +51,7 @@ When there are errors to the query the UI displays the errors to the editor: name='with errors' args={ { - query: { sql: 'SELECT field1, field2 FROM DATAVIEW' }, + query: { esql: 'from dataview | keep field1, field2' }, isCodeEditorExpanded:false, 'data-test-subj':'test-id', errors: [ @@ -76,7 +76,7 @@ When there the query is long and the editor is on the compact view: name='with long query' args={ { - query: { sql: 'SELECT field1, field2, field 3, field 4, field 5 FROM DATAVIEW WHERE field5 IS NOT NULL AND field4 IS NULL' }, + query: { esql: 'from dataview | keep field1, field2, field 3, field 4, field 5 | where field5 > 5 | stats var = avg(field3)' }, isCodeEditorExpanded:false, 'data-test-subj':'test-id', } @@ -97,7 +97,7 @@ The editor also works on the expanded mode: name='on expanded mode' args={ { - query: { sql: 'SELECT field1, field2 FROM DATAVIEW' }, + query: { esql: 'from dataview | keep field1, field2' }, isCodeEditorExpanded:true, 'data-test-subj':'test-id', } @@ -110,6 +110,27 @@ The editor also works on the expanded mode: +The editor also works on the expanded mode with the minimize button hidden: + + + + {Template.bind({})} + + + ## Component props The component exposes the following properties: diff --git a/packages/kbn-text-based-editor/src/editor_footer.tsx b/packages/kbn-text-based-editor/src/editor_footer.tsx index 3119d548098de..6f1e6cdd0b130 100644 --- a/packages/kbn-text-based-editor/src/editor_footer.tsx +++ b/packages/kbn-text-based-editor/src/editor_footer.tsx @@ -28,10 +28,130 @@ import type { MonacoError } from './helpers'; const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0; const COMMAND_KEY = isMac ? '⌘' : '^'; +const getConstsByType = (type: 'error' | 'warning', count: number) => { + if (type === 'error') { + return { + color: 'danger', + message: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.errorCount', { + defaultMessage: '{count} {count, plural, one {error} other {errors}}', + values: { count }, + }), + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.errorsTitle', { + defaultMessage: 'Errors', + }), + }; + } else { + return { + color: 'warning', + message: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.warningCount', { + defaultMessage: '{count} {count, plural, one {warning} other {warnings}}', + values: { count }, + }), + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.warningsTitle', { + defaultMessage: 'Warnings', + }), + }; + } +}; + +export function ErrorsWarningsPopover({ + isPopoverOpen, + items, + type, + refreshErrors, + setIsPopoverOpen, + onErrorClick, +}: { + isPopoverOpen: boolean; + items: MonacoError[]; + type: 'error' | 'warning'; + refreshErrors: () => void; + setIsPopoverOpen: (flag: boolean) => void; + onErrorClick: (error: MonacoError) => void; +}) { + const strings = getConstsByType(type, items.length); + return ( + + + + + + + { + refreshErrors(); + setIsPopoverOpen(!isPopoverOpen); + }} + > +

{strings.message}

+ + } + ownFocus={false} + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + > +
+ {strings.label} + + {items.map((item, index) => { + return ( + onErrorClick(item)} + > + + + + + + + + {i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.lineNumber', + { + defaultMessage: 'Line {lineNumber}', + values: { lineNumber: item.startLineNumber }, + } + )} + + + + + {item.message} + + + + ); + })} + +
+
+
+
+
+ ); +} + interface EditorFooterProps { lines: number; containerCSS: Interpolation; errors?: MonacoError[]; + warning?: MonacoError[]; detectTimestamp: boolean; onErrorClick: (error: MonacoError) => void; refreshErrors: () => void; @@ -41,6 +161,7 @@ export const EditorFooter = memo(function EditorFooter({ lines, containerCSS, errors, + warning, detectTimestamp, onErrorClick, refreshErrors, @@ -57,97 +178,24 @@ export const EditorFooter = memo(function EditorFooter({ {errors && errors.length > 0 && ( - - - - - - - { - refreshErrors(); - setIsPopoverOpen(!isPopoverOpen); - }} - > -

- {i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.errorCount', - { - defaultMessage: '{count} {count, plural, one {error} other {errors}}', - values: { count: errors.length }, - } - )} -

- - } - ownFocus={false} - isOpen={isPopoverOpen} - closePopover={() => setIsPopoverOpen(false)} - > -
- - {i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.errorsTitle', - { - defaultMessage: 'Errors', - } - )} - - - {errors.map((error, index) => { - return ( - onErrorClick(error)} - > - - - - - - - - {i18n.translate( - 'textBasedEditor.query.textBasedLanguagesEditor.lineNumber', - { - defaultMessage: 'Line {lineNumber}', - values: { lineNumber: error.startLineNumber }, - } - )} - - - - - {error.message} - - - - ); - })} - -
-
-
-
-
+ + )} + {warning && warning.length > 0 && ( + )} diff --git a/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx b/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx new file mode 100644 index 0000000000000..a3b4ef893a771 --- /dev/null +++ b/packages/kbn-text-based-editor/src/esql_documentation_sections.tsx @@ -0,0 +1,2318 @@ +/* + * Copyright 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 { i18n } from '@kbn/i18n'; +import { Markdown } from '@kbn/kibana-react-plugin/public'; + +export const initialSection = ( + +); + +export const sourceCommands = { + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.sourceCommands', { + defaultMessage: 'Source commands', + }), + description: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.commandsDescription', + { + defaultMessage: `A source command produces a table, typically with data from Elasticsearch. ES|QL supports the following source commands.`, + } + ), + items: [ + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.from', + { + defaultMessage: 'FROM', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.row', + { + defaultMessage: 'ROW', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.show', + { + defaultMessage: 'SHOW', + } + ), + description: ( + \` source command returns information about the deployment and its capabilities: + +* Use \`SHOW INFO\` to return the deployment's version, build date and hash. +* Use \`SHOW FUNCTIONS\` to return a list of all supported functions and a synopsis of each function. + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + } + )} + /> + ), + }, + ], +}; + +export const processingCommands = { + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.processingCommands', { + defaultMessage: 'Processing commands', + }), + description: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.processingCommandsDescription', + { + defaultMessage: `Processing commands change an input table by adding, removing, or changing rows and columns. ES|QL supports the following processing commands.`, + } + ), + items: [ + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.dissect', + { + defaultMessage: 'DISSECT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.drop', + { + defaultMessage: 'DROP', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.enrich', + { + defaultMessage: 'ENRICH', + } + ), + description: ( + \`; if it’s not specified, the match will be performed on a field with the same name as the match field defined in the enrich policy. + +\`\`\` +ROW a = "1" +| ENRICH languages_policy ON a +\`\`\` + +You can specify which attributes (between those defined as enrich fields in the policy) have to be added to the result, using \`WITH , ...\` syntax. + +\`\`\` +ROW a = "1" +| ENRICH languages_policy ON a WITH language_name +\`\`\` + +Attributes can also be renamed using \`WITH new_name=\` + +\`\`\` +ROW a = "1" +| ENRICH languages_policy ON a WITH name = language_name +\`\`\` + +By default (if no \`WITH\` is defined), \`ENRICH\` will add all the enrich fields defined in the enrich policy to the result. + +In case of name collisions, the newly created fields will override the existing fields. + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + } + )} + /> + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.eval', + { + defaultMessage: 'EVAL', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.grok', + { + defaultMessage: 'GROK', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.keep', + { + defaultMessage: 'KEEP', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.limit', + { + defaultMessage: 'LIMIT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvExpand', + { + defaultMessage: 'MV_EXPAND', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.rename', + { + defaultMessage: 'RENAME', + } + ), + description: ( + = +\`\`\` + +For example: + +\`\`\` +FROM employees +| KEEP first_name, last_name, still_hired +| RENAME employed = still_hired +\`\`\` + +If a column with the new name already exists, it will be replaced by the new column. + +Multiple columns can be renamed with a single \`RENAME\` command: + +\`\`\` +FROM employees +| KEEP first_name, last_name +| RENAME fn = first_name, ln = last_name +\`\`\` + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + } + )} + /> + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.sort', + { + defaultMessage: 'SORT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.statsby', + { + defaultMessage: 'STATS ... BY', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.where', + { + defaultMessage: 'WHERE', + } + ), + description: ( + \` +* larger than or equal: \`>=\` + +The \`IN\` operator allows testing whether a field or expression equals an element in a list of literals, fields or expressions: + +\`\`\` +ROW a = 1, b = 4, c = 3 +| WHERE c-a IN (3, b / 2, a) +\`\`\` + +For string comparison using wildcards or regular expressions, use \`LIKE\` or \`RLIKE\`: + +* Use \`LIKE\` to match strings using wildcards. The following wildcard characters are supported: + * \`*\` matches zero or more characters. + * \`?\` matches one character. + + \`\`\` + FROM employees + | WHERE first_name LIKE "?b*" + | KEEP first_name, last_name + \`\`\` + +* Use \`RLIKE\` to match strings using [regular expressions](https://www.elastic.co/guide/en/elasticsearch/reference/current/regexp-syntax.html): + + \`\`\` + FROM employees + | WHERE first_name RLIKE ".leja.*" + | KEEP first_name, last_name + \`\`\` + +You can use the following boolean operators: + +* \`AND\` +* \`OR\` +* \`NOT\` + +\`\`\` +FROM employees +| KEEP first_name, last_name, height, still_hired +| WHERE height > 2 AND NOT still_hired +\`\`\` + +#### Functions +\`WHERE\` supports various functions for calculating values. Refer to Functions for more information. + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + } + )} + /> + ), + }, + ], +}; + +export const functions = { + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.functions', { + defaultMessage: 'Functions', + }), + description: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.functionsDocumentationESQLDescription', + { + defaultMessage: `Functions are supported by ROW, EVAL and WHERE.`, + } + ), + items: [ + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.absFunction', + { + defaultMessage: 'ABS', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.autoBucketFunction', + { + defaultMessage: 'AUTO_BUCKET', + } + ), + description: ( + = "1985-01-01T00:00:00Z" AND hire_date < "1986-01-01T00:00:00Z" +| EVAL bucket = AUTO_BUCKET(hire_date, 20, "1985-01-01T00:00:00Z", "1986-01-01T00:00:00Z") +| STATS AVG(salary) BY bucket +| SORT bucket +\`\`\` + +Returning: +\`\`\` +46305.0 | 1985-02-01T00:00:00.000Z +44817.0 | 1985-05-01T00:00:00.000Z +62405.0 | 1985-07-01T00:00:00.000Z +49095.0 | 1985-09-01T00:00:00.000Z +51532.0 | 1985-10-01T00:00:00.000Z +54539.75 | 1985-11-01T00:00:00.000 +\`\`\` + +NOTE: \`AUTO_BUCKET\` does not create buckets that don’t match any documents. That’s why the example above is missing 1985-03-01 and other dates. + `, + description: + 'Text is in markdown. Do not translate function names, special characters, or field names like sum(bytes)', + } + )} + /> + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.caseFunction', + { + defaultMessage: 'CASE', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.cidrMatchFunction', + { + defaultMessage: 'CIDR_MATCH', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.concatFunction', + { + defaultMessage: 'CONCAT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.dateFormatFunction', + { + defaultMessage: 'DATE_FORMAT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.dateTruncFunction', + { + defaultMessage: 'DATE_TRUNC', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.eFunction', + { + defaultMessage: 'E', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.isFiniteFunction', + { + defaultMessage: 'IS_FINITE', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.isInfiniteFunction', + { + defaultMessage: 'IS_INFINITE', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.isNanFunction', + { + defaultMessage: 'IS_NAN', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.isNullFunction', + { + defaultMessage: 'IS_NULL', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.lengthFunction', + { + defaultMessage: 'LENGTH', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.log10Function', + { + defaultMessage: 'LOG10', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvAvgFunction', + { + defaultMessage: 'MV_AVG', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvConcatFunction', + { + defaultMessage: 'MV_CONCAT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvCountFunction', + { + defaultMessage: 'MV_COUNT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvDedupeFunction', + { + defaultMessage: 'MV_DEDUPE', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvMaxFunction', + { + defaultMessage: 'MV_MAX', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvMedianFunction', + { + defaultMessage: 'MV_MEDIAN', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvMinFunction', + { + defaultMessage: 'MV_MIN', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.mvSumFunction', + { + defaultMessage: 'MV_SUM', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.piFunction', + { + defaultMessage: 'PI', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.powFunction', + { + defaultMessage: 'POW', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.roundFunction', + { + defaultMessage: 'ROUND', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.splitFunction', + { + defaultMessage: 'SPLIT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.startsWithFunction', + { + defaultMessage: 'STARTS_WITH', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.substringFunction', + { + defaultMessage: 'SUBSTRING', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.tauFunction', + { + defaultMessage: 'TAU', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toBooleanFunction', + { + defaultMessage: 'TO_BOOLEAN', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toDatetimeFunction', + { + defaultMessage: 'TO_DATETIME', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toDoubleFunction', + { + defaultMessage: 'TO_DOUBLE', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toIntegerFunction', + { + defaultMessage: 'TO_INTEGER', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toIpFunction', + { + defaultMessage: 'TO_IP', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toLongFunction', + { + defaultMessage: 'TO_LONG', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toStringFunction', + { + defaultMessage: 'TO_STRING', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.toVersionFunction', + { + defaultMessage: 'TO_VERSION', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.trimFunction', + { + defaultMessage: 'TRIM', + } + ), + description: ( + + ), + }, + ], +}; + +export const aggregationFunctions = { + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.aggregationFunctions', { + defaultMessage: 'Aggregation functions', + }), + description: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.aggregationFunctionsDocumentationESQLDescription', + { + defaultMessage: `These functions can by used with STATS...BY:`, + } + ), + items: [ + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.avgFunction', + { + defaultMessage: 'AVG', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.countFunction', + { + defaultMessage: 'COUNT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.countDistinctFunction', + { + defaultMessage: 'COUNT_DISTINCT', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.maxFunction', + { + defaultMessage: 'MAX', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.medianFunction', + { + defaultMessage: 'MEDIAN', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.medianAbsoluteDeviationFunction', + { + defaultMessage: 'MEDIAN_ABSOLUTE_DEVIATION', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.minFunction', + { + defaultMessage: 'MIN', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.percentileFunction', + { + defaultMessage: 'PERCENTILE', + } + ), + description: ( + + ), + }, + { + label: i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationESQL.sumFunction', + { + defaultMessage: 'SUM', + } + ), + description: ( + + ), + }, + ], +}; diff --git a/packages/kbn-text-based-editor/src/fetch_fields_from_esql.ts b/packages/kbn-text-based-editor/src/fetch_fields_from_esql.ts new file mode 100644 index 0000000000000..b847e4cb0bb43 --- /dev/null +++ b/packages/kbn-text-based-editor/src/fetch_fields_from_esql.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 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 { pluck } from 'rxjs/operators'; +import { lastValueFrom } from 'rxjs'; +import { Query, AggregateQuery } from '@kbn/es-query'; +import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import type { Datatable } from '@kbn/expressions-plugin/public'; +import { textBasedQueryStateToAstWithValidation } from '@kbn/data-plugin/common'; + +interface TextBasedLanguagesErrorResponse { + error: { + message: string; + }; + type: 'error'; +} + +export function fetchFieldsFromESQL(query: Query | AggregateQuery, expressions: ExpressionsStart) { + return textBasedQueryStateToAstWithValidation({ + query, + }) + .then((ast) => { + if (ast) { + const execution = expressions.run(ast, null); + let finalData: Datatable; + let error: string | undefined; + execution.pipe(pluck('result')).subscribe((resp) => { + const response = resp as Datatable | TextBasedLanguagesErrorResponse; + if (response.type === 'error') { + error = response.error.message; + } else { + finalData = response; + } + }); + return lastValueFrom(execution).then(() => { + if (error) { + throw new Error(error); + } else { + return finalData; + } + }); + } + return undefined; + }) + .catch((err) => { + throw new Error(err.message); + }); +} diff --git a/packages/kbn-text-based-editor/src/helpers.test.ts b/packages/kbn-text-based-editor/src/helpers.test.ts index a56d0ecee141c..74c2387fde2fa 100644 --- a/packages/kbn-text-based-editor/src/helpers.test.ts +++ b/packages/kbn-text-based-editor/src/helpers.test.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import { parseErrors, getInlineEditorText } from './helpers'; +import { parseErrors, parseWarning, getInlineEditorText } from './helpers'; describe('helpers', function () { describe('parseErrors', function () { - it('should return the correct error object from SQL ES response for an one liner query', function () { + it('should return the correct error object from ESQL ES response for an one liner query', function () { const error = new Error( '[essql] > Unexpected error from Elasticsearch: verification_exception - Found 1 problem\nline 1:8: Unknown column [miaou]' ); @@ -27,7 +27,7 @@ describe('helpers', function () { ]); }); - it('should return the correct error object from SQL ES response for an multi liner query', function () { + it('should return the correct error object from ESQL ES response for an multi liner query', function () { const error = new Error( '[essql] > Unexpected error from Elasticsearch: verification_exception - Found 1 problem line 3:7: Condition expression needs to be boolean, found [TEXT]' ); @@ -54,7 +54,7 @@ describe('helpers', function () { it('should return the generic error object for an error of unknown format', function () { const error = new Error('I am an unknown error'); const errors = [error]; - expect(parseErrors(errors, `SELECT * FROM "kibana_sample_data_ecommerce"`)).toEqual([ + expect(parseErrors(errors, `FROM "kibana_sample_data_ecommerce"`)).toEqual([ { endColumn: 10, endLineNumber: 1, @@ -67,29 +67,73 @@ describe('helpers', function () { }); }); + describe('parseWarning', function () { + it('should return the correct warning object from ESQL ES response for an one liner query', function () { + const warning = + '299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Line 1:52: evaluation of [date_parse(geo.dest)] failed, treating result as null. Only first 20 failures recorded."'; + expect(parseWarning(warning)).toEqual([ + { + endColumn: 138, + endLineNumber: 1, + message: + 'evaluation of [date_parse(geo.dest)] failed, treating result as null. Only first 20 failures recorded.', + severity: 8, + startColumn: 52, + startLineNumber: 1, + }, + ]); + }); + + it('should return the correct array of warnings if multiple warnins are detected', function () { + const warning = + '299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Line 1:52: evaluation of [date_parse(geo.dest)] failed, treating result as null. Only first 20 failures recorded.", 299 Elasticsearch-8.10.0-SNAPSHOT-adb9fce96079b421c2575f0d2d445f492eb5f075 "Line 1:84: evaluation of [date_parse(geo.src)] failed, treating result as null. Only first 20 failures recorded."'; + expect(parseWarning(warning)).toEqual([ + { + endColumn: 138, + endLineNumber: 1, + message: + 'evaluation of [date_parse(geo.dest)] failed, treating result as null. Only first 20 failures recorded.', + severity: 8, + startColumn: 52, + startLineNumber: 1, + }, + { + endColumn: 169, + endLineNumber: 1, + message: + 'evaluation of [date_parse(geo.src)] failed, treating result as null. Only first 20 failures recorded.', + severity: 8, + startColumn: 84, + startLineNumber: 1, + }, + ]); + }); + }); + describe('getInlineEditorText', function () { it('should return the entire query if it is one liner', function () { - const text = getInlineEditorText( - 'SELECT field1, count(*) FROM index1 ORDER BY field1', - false - ); + const text = getInlineEditorText('FROM index1 | keep field1, field2 | order field1', false); expect(text).toEqual(text); }); it('should return the query on one line with extra space if is multiliner', function () { const text = getInlineEditorText( - 'SELECT field1, count(*)\nFROM index1 ORDER BY field1', + 'FROM index1 | keep field1, field2\n| keep field1, field2 | order field1', true ); - expect(text).toEqual('SELECT field1, count(*) FROM index1 ORDER BY field1'); + expect(text).toEqual( + 'FROM index1 | keep field1, field2 | keep field1, field2 | order field1' + ); }); it('should return the query on one line with extra spaces removed if is multiliner', function () { const text = getInlineEditorText( - 'SELECT field1, count(*)\nFROM index1 \n ORDER BY field1', + 'FROM index1 | keep field1, field2\n| keep field1, field2 \n | order field1', true ); - expect(text).toEqual('SELECT field1, count(*) FROM index1 ORDER BY field1'); + expect(text).toEqual( + 'FROM index1 | keep field1, field2 | keep field1, field2 | order field1' + ); }); }); }); diff --git a/packages/kbn-text-based-editor/src/helpers.ts b/packages/kbn-text-based-editor/src/helpers.ts index d1deae5bf0d80..ca5e3d2fca663 100644 --- a/packages/kbn-text-based-editor/src/helpers.ts +++ b/packages/kbn-text-based-editor/src/helpers.ts @@ -42,6 +42,43 @@ export const useDebounceWithOptions = ( ); }; +export const parseWarning = (warning: string): MonacoError[] => { + if (warning.includes('Line')) { + const splitByLine = warning.split('Line'); + splitByLine.shift(); + return splitByLine.map((item) => { + const [lineNumber, startPosition, warningMessage] = item.split(':'); + const [trimmedMessage] = warningMessage.split('"'); + // initialize the length to 10 in case no error word found + let errorLength = 10; + const [_, wordWithError] = trimmedMessage.split('['); + if (wordWithError) { + errorLength = wordWithError.length - 1; + } + return { + message: trimmedMessage.trimStart(), + startColumn: Number(startPosition), + startLineNumber: Number(lineNumber), + endColumn: Number(startPosition) + errorLength, + endLineNumber: Number(lineNumber), + severity: monaco.MarkerSeverity.Error, + }; + }); + } else { + // unknown warning message + return [ + { + message: warning, + startColumn: 1, + startLineNumber: 1, + endColumn: 10, + endLineNumber: 1, + severity: monaco.MarkerSeverity.Error, + }, + ]; + } +}; + export const parseErrors = (errors: Error[], code: string): MonacoError[] => { return errors.map((error) => { if (error.message.includes('line')) { @@ -101,6 +138,21 @@ export const getDocumentationSections = async (language: string) => { initialSection, }; } + if (language === 'esql') { + const { sourceCommands, processingCommands, initialSection, functions, aggregationFunctions } = + await import('./esql_documentation_sections'); + groups.push({ + label: i18n.translate('textBasedEditor.query.textBasedLanguagesEditor.esql', { + defaultMessage: 'ES|QL', + }), + items: [], + }); + groups.push(sourceCommands, processingCommands, functions, aggregationFunctions); + return { + groups, + initialSection, + }; + } }; export const getInlineEditorText = (queryString: string, isMultiLine: boolean) => { diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts b/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts index 86a68b5ba342b..f7d57a6d60213 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts @@ -18,7 +18,9 @@ export const textBasedLanguagedEditorStyles = ( editorHeight: number, isCodeEditorExpanded: boolean, hasErrors: boolean, - isCodeEditorExpandedFocused: boolean + hasWarning: boolean, + isCodeEditorExpandedFocused: boolean, + hasReference: boolean ) => { let position = isCompactFocused ? ('absolute' as 'absolute') : ('relative' as 'relative'); // cast string to type 'relative' | 'absolute' if (isCodeEditorExpanded) { @@ -40,7 +42,7 @@ export const textBasedLanguagedEditorStyles = ( }, resizableContainer: { display: 'flex', - width: isCodeEditorExpanded ? '100%' : 'calc(100% - 80px)', + width: isCodeEditorExpanded ? '100%' : `calc(100% - ${hasReference ? 80 : 40}px)`, alignItems: isCompactFocused ? 'flex-start' : 'center', border: !isCompactFocused ? euiTheme.border.thin : 'none', borderTopLeftRadius: '6px', @@ -51,7 +53,7 @@ export const textBasedLanguagedEditorStyles = ( linesBadge: { position: 'absolute' as 'absolute', // cast string to type 'absolute', zIndex: 1, - right: hasErrors ? '60px' : '12px', + right: hasErrors || hasWarning ? '60px' : '12px', top: '50%', transform: 'translate(0, -50%)', }, diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx index 90c973a609874..4e3853970d7a2 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.test.tsx @@ -16,6 +16,22 @@ import { TextBasedLanguagesEditor, TextBasedLanguagesEditorProps, } from './text_based_languages_editor'; +import { ReactWrapper } from 'enzyme'; + +jest.mock('./helpers', () => { + const module = jest.requireActual('./helpers'); + return { + ...module, + getDocumentationSections: () => ({ + groups: [ + { + label: 'How it works', + items: [], + }, + ], + }), + }; +}); import { of } from 'rxjs'; describe('TextBasedLanguagesEditor', () => { @@ -45,7 +61,7 @@ describe('TextBasedLanguagesEditor', () => { let props: TextBasedLanguagesEditorProps; beforeEach(() => { props = { - query: { sql: 'SELECT * FROM test' }, + query: { esql: 'from test' }, isCodeEditorExpanded: false, onTextLangQueryChange: jest.fn(), onTextLangQuerySubmit: jest.fn(), @@ -108,16 +124,32 @@ describe('TextBasedLanguagesEditor', () => { }); }); - it('should render the correct buttons for the inline code editor mode', async () => { + it('should render the warnings badge for the inline mode by default if warning are provides', async () => { + const newProps = { + ...props, + warning: 'Line 1: 20: Warning', + }; await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); - expect(component.find('[data-test-subj="TextBasedLangEditor-expand"]').length).not.toBe(0); + const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); expect( - component.find('[data-test-subj="TextBasedLangEditor-inline-documentation"]').length + component.find('[data-test-subj="TextBasedLangEditor-inline-warning-badge"]').length ).not.toBe(0); }); }); + it('should render the correct buttons for the inline code editor mode', async () => { + let component: ReactWrapper; + + await act(async () => { + component = mount(renderTextBasedLanguagesEditorComponent({ ...props })); + }); + component!.update(); + expect(component!.find('[data-test-subj="TextBasedLangEditor-expand"]').length).not.toBe(0); + expect( + component!.find('[data-test-subj="TextBasedLangEditor-inline-documentation"]').length + ).not.toBe(0); + }); + it('should call the expand editor function when expand button is clicked', async () => { const expandCodeEditorSpy = jest.fn(); const newProps = { @@ -136,12 +168,36 @@ describe('TextBasedLanguagesEditor', () => { ...props, isCodeEditorExpanded: true, }; + let component: ReactWrapper; + await act(async () => { + component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + }); + component!.update(); + expect( + component!.find('[data-test-subj="TextBasedLangEditor-toggleWordWrap"]').length + ).not.toBe(0); + expect(component!.find('[data-test-subj="TextBasedLangEditor-minimize"]').length).not.toBe(0); + expect(component!.find('[data-test-subj="TextBasedLangEditor-documentation"]').length).not.toBe( + 0 + ); + }); + + it('should not render the minimize button for the expanded code editor mode if the prop is set to true', async () => { + const newProps = { + ...props, + isCodeEditorExpanded: true, + hideMinimizeButton: true, + }; + let component: ReactWrapper; + await act(async () => { + component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); + }); + component!.update(); await act(async () => { - const component = mount(renderTextBasedLanguagesEditorComponent({ ...newProps })); expect( component.find('[data-test-subj="TextBasedLangEditor-toggleWordWrap"]').length ).not.toBe(0); - expect(component.find('[data-test-subj="TextBasedLangEditor-minimize"]').length).not.toBe(0); + expect(component.find('[data-test-subj="TextBasedLangEditor-minimize"]').length).toBe(0); expect( component.find('[data-test-subj="TextBasedLangEditor-documentation"]').length ).not.toBe(0); diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index 5f432c090eb8c..5eb83f625493a 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -6,16 +6,27 @@ * Side Public License, v 1. */ -import React, { useRef, useEffect, useState, useCallback, memo } from 'react'; +import React, { useRef, memo, useEffect, useState, useCallback } from 'react'; import classNames from 'classnames'; -import { SQLLang, monaco } from '@kbn/monaco'; +import { + SQLLang, + monaco, + ESQL_LANG_ID, + ESQL_THEME_ID, + ESQLLang, + ESQLCustomAutocompleteCallbacks, +} from '@kbn/monaco'; import type { AggregateQuery } from '@kbn/es-query'; -import { getAggregateQueryMode } from '@kbn/es-query'; +import { getAggregateQueryMode, getLanguageDisplayName } from '@kbn/es-query'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import type { IndexManagementPluginSetup } from '@kbn/index-management-plugin/public'; +import type { SerializedEnrichPolicy } from '@kbn/index-management-plugin/common'; import { type LanguageDocumentationSections, LanguageDocumentationPopover, } from '@kbn/language-documentation-popover'; - +import { useKibana } from '@kbn/kibana-react-plugin/public'; import { i18n } from '@kbn/i18n'; import { EuiBadge, @@ -40,12 +51,14 @@ import { import { useDebounceWithOptions, parseErrors, + parseWarning, getInlineEditorText, getDocumentationSections, MonacoError, } from './helpers'; import { EditorFooter } from './editor_footer'; import { ResizableButton } from './resizable_button'; +import { fetchFieldsFromESQL } from './fetch_fields_from_esql'; import './overwrite.scss'; @@ -57,9 +70,17 @@ export interface TextBasedLanguagesEditorProps { isCodeEditorExpanded: boolean; detectTimestamp?: boolean; errors?: Error[]; + warning?: string; isDisabled?: boolean; isDarkMode?: boolean; dataTestSubj?: string; + hideMinimizeButton?: boolean; +} + +interface TextBasedEditorDeps { + dataViews: DataViewsPublicPluginStart; + expressions: ExpressionsStart; + indexManagementApiService?: IndexManagementPluginSetup['apiService']; } const MAX_COMPACT_VIEW_LENGTH = 250; @@ -72,6 +93,9 @@ const KEYCODE_ARROW_DOWN = 40; const languageId = (language: string) => { switch (language) { + case 'esql': { + return ESQL_LANG_ID; + } case 'sql': default: { return SQLLang.ID; @@ -82,6 +106,8 @@ const languageId = (language: string) => { let clickedOutside = false; let initialRender = true; let updateLinesFromModel = false; +let currentCursorContent = ''; + export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ query, onTextLangQueryChange, @@ -90,13 +116,17 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ isCodeEditorExpanded, detectTimestamp = false, errors, + warning, isDisabled, isDarkMode, + hideMinimizeButton, dataTestSubj, }: TextBasedLanguagesEditorProps) { const { euiTheme } = useEuiTheme(); const language = getAggregateQueryMode(query); const queryString: string = query[language] ?? ''; + const kibana = useKibana(); + const { dataViews, expressions, indexManagementApiService } = kibana.services; const [lines, setLines] = useState(1); const [code, setCode] = useState(queryString ?? ''); const [codeOneLiner, setCodeOneLiner] = useState(''); @@ -108,16 +138,21 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const [isCodeEditorExpandedFocused, setIsCodeEditorExpandedFocused] = useState(false); const [isWordWrapped, setIsWordWrapped] = useState(true); const [editorErrors, setEditorErrors] = useState([]); + const [editorWarning, setEditorWarning] = useState([]); + const [documentationSections, setDocumentationSections] = useState(); + const policiesRef = useRef([]); const styles = textBasedLanguagedEditorStyles( euiTheme, isCompactFocused, editorHeight, isCodeEditorExpanded, Boolean(errors?.length), - isCodeEditorExpandedFocused + Boolean(warning), + isCodeEditorExpandedFocused, + Boolean(documentationSections) ); const isDark = isDarkMode; const editorModel = useRef(); @@ -209,6 +244,18 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ if (updateLinesFromModel) { setLines(editorModel.current?.getLineCount() || 1); } + if (editor1?.current) { + const currentPosition = editor1.current?.getPosition(); + const content = editorModel.current?.getValueInRange({ + startLineNumber: 0, + startColumn: 0, + endLineNumber: currentPosition?.lineNumber ?? 1, + endColumn: currentPosition?.column ?? 1, + }); + if (content) { + currentCursorContent = content || editor1.current?.getValue(); + } + } }); editor1.current?.onDidFocusEditorText(() => { setIsCompactFocused(true); @@ -227,6 +274,12 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ if (!isCodeEditorExpanded) { editor1.current?.onDidContentSizeChange(updateHeight); } + if (warning && (!errors || !errors.length)) { + const parsedWarning = parseWarning(warning); + setEditorWarning(parsedWarning); + } else { + setEditorWarning([]); + } if (errors && errors.length) { const parsedErrors = parseErrors(errors, code); setEditorErrors(parsedErrors); @@ -238,7 +291,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ }, { skipFirstRender: false }, 256, - [errors] + [errors, warning] ); const onErrorClick = useCallback(({ startLineNumber, startColumn }: MonacoError) => { @@ -275,7 +328,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const text = getInlineEditorText(queryString, Boolean(hasLines)); const queryLength = text.length; const unusedSpace = - errors && errors.length + (errors && errors.length) || warning ? EDITOR_ONE_LINER_UNUSED_SPACE_WITH_ERRORS : EDITOR_ONE_LINER_UNUSED_SPACE; const charactersAlowed = Math.floor((width - unusedSpace) / FONT_WIDTH); @@ -288,7 +341,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ } } }, - [queryString, errors, isCompactFocused] + [isCompactFocused, queryString, errors, warning] ); useEffect(() => { @@ -329,6 +382,78 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ } }, [language, documentationSections]); + const getSourceIdentifiers: ESQLCustomAutocompleteCallbacks['getSourceIdentifiers'] = + useCallback(async () => { + const indices = await dataViews.getIndices({ + showAllIndices: false, + pattern: '*', + isRollupIndex: () => false, + }); + return indices.map((i) => i.name); + }, [dataViews]); + + const getFieldsIdentifiers: ESQLCustomAutocompleteCallbacks['getFieldsIdentifiers'] = useCallback( + async (ctx) => { + const pipes = currentCursorContent?.split('|'); + pipes?.pop(); + const validContent = pipes?.join('|'); + if (validContent) { + // ES|QL with limit 0 returns only the columns and is more performant + const esqlQuery = { + esql: `${validContent} | limit 0`, + }; + try { + const table = await fetchFieldsFromESQL(esqlQuery, expressions); + return table?.columns.map((c) => c.name) || []; + } catch (e) { + // no action yet + } + } + return []; + }, + [expressions] + ); + + const getPoliciesIdentifiers: ESQLCustomAutocompleteCallbacks['getPoliciesIdentifiers'] = + useCallback( + async (ctx) => { + const { data: policies, error } = + (await indexManagementApiService?.getAllEnrichPolicies()) || {}; + policiesRef.current = policies || []; + if (error || !policies) { + return []; + } + return policies.map(({ name, sourceIndices }) => ({ name, indices: sourceIndices })); + }, + [indexManagementApiService] + ); + + const getPolicyFieldsIdentifiers: ESQLCustomAutocompleteCallbacks['getPolicyFieldsIdentifiers'] = + useCallback( + async (ctx) => + policiesRef.current + .filter(({ name }) => ctx.userDefinedVariables.policyIdentifiers.includes(name)) + .flatMap(({ enrichFields }) => enrichFields), + [] + ); + + const getPolicyMatchingFieldIdentifiers: ESQLCustomAutocompleteCallbacks['getPolicyMatchingFieldIdentifiers'] = + useCallback( + async (ctx) => { + // try to load the list if none is present yet but + // at least one policy is declared in the userDefinedVariables + // (this happens if the user pastes an ESQL statement with the policy name in it) + if (!policiesRef.current.length && ctx.userDefinedVariables.policyIdentifiers.length) { + await getPoliciesIdentifiers(ctx); + } + const matchingField = policiesRef.current.find(({ name }) => + ctx.userDefinedVariables.policyIdentifiers.includes(name) + )?.matchField; + return matchingField ? [matchingField] : []; + }, + [getPoliciesIdentifiers] + ); + const codeEditorOptions: CodeEditorProps['options'] = { automaticLayout: false, accessibilitySupport: 'off', @@ -343,7 +468,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ minimap: { enabled: false }, wordWrap: isWordWrapped ? 'on' : 'off', lineNumbers: showLineNumbers ? 'on' : 'off', - theme: isDark ? 'vs-dark' : 'vs', + theme: language === 'esql' ? ESQL_THEME_ID : isDark ? 'vs-dark' : 'vs', lineDecorationsWidth: 12, autoIndent: 'none', wrappingIndent: 'none', @@ -355,7 +480,8 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ vertical: 'auto', }, overviewRulerBorder: false, - readOnly: isDisabled, + readOnly: + isDisabled || Boolean(!isCompactFocused && codeOneLiner && codeOneLiner.includes('...')), }; if (isCompactFocused) { @@ -423,48 +549,54 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ - - - + { - expandCodeEditor(false); - updateLinesFromModel = false; - }} - /> - - + > + { + expandCodeEditor(false); + updateLinesFromModel = false; + }} + /> + + + )} - + {documentationSections && ( + + + + )}
@@ -515,11 +647,33 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ {errors.length} )} + {!isCompactFocused && warning && (!errors || errors.length === 0) && ( + + {editorWarning.length} + + )} { editor1.current = editor; @@ -537,6 +691,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ lines={lines} containerCSS={styles.bottomContainer} errors={editorErrors} + warning={editorWarning} onErrorClick={onErrorClick} refreshErrors={onTextLangQuerySubmit} detectTimestamp={detectTimestamp} @@ -569,7 +724,14 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ onClick={() => expandCodeEditor(true)} data-test-subj="TextBasedLangEditor-expand" css={{ - borderRadius: 0, + ...(documentationSections + ? { + borderRadius: 0, + } + : { + borderTopLeftRadius: 0, + borderBottomLeftRadius: 0, + }), backgroundColor: isDark ? euiTheme.colors.lightestShade : '#e9edf3', border: '1px solid rgb(17 43 134 / 10%) !important', }} @@ -577,28 +739,34 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ - + + sections={documentationSections} + buttonProps={{ + display: 'empty', + 'data-test-subj': 'TextBasedLangEditor-inline-documentation', + 'aria-label': i18n.translate( + 'textBasedEditor.query.textBasedLanguagesEditor.documentationLabel', + { + defaultMessage: 'Documentation', + } + ), + size: 'm', + css: { + borderTopLeftRadius: 0, + borderBottomLeftRadius: 0, + backgroundColor: isDark ? euiTheme.colors.lightestShade : '#e9edf3', + border: '1px solid rgb(17 43 134 / 10%) !important', + borderLeft: 'transparent !important', + }, + }} + /> + + )} @@ -609,6 +777,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ lines={lines} containerCSS={styles.bottomContainer} errors={editorErrors} + warning={editorWarning} onErrorClick={onErrorClick} refreshErrors={onTextLangQuerySubmit} detectTimestamp={detectTimestamp} diff --git a/packages/kbn-text-based-editor/tsconfig.json b/packages/kbn-text-based-editor/tsconfig.json index cefbe0335575b..63222d0d6026b 100644 --- a/packages/kbn-text-based-editor/tsconfig.json +++ b/packages/kbn-text-based-editor/tsconfig.json @@ -19,7 +19,11 @@ "@kbn/core", "@kbn/kibana-react-plugin", "@kbn/language-documentation-popover", - "@kbn/test-jest-helpers" + "@kbn/test-jest-helpers", + "@kbn/data-plugin", + "@kbn/expressions-plugin", + "@kbn/data-views-plugin", + "@kbn/index-management-plugin" ], "exclude": [ "target/**/*", diff --git a/packages/kbn-unified-data-table/README.md b/packages/kbn-unified-data-table/README.md new file mode 100644 index 0000000000000..576a676289d7a --- /dev/null +++ b/packages/kbn-unified-data-table/README.md @@ -0,0 +1,241 @@ +# @kbn/unified-data-table + +This package contains components and services for the unified data table UI (as used in Discover). + +## UnifiedDataTable Component +Props description: +| Property | Type | Description | +| :--- | :--- | :--- | +| **ariaLabelledBy** | string | Determines which element labels the grid for ARIA. | +| **className** | (optional) string | Optional class name to apply. | +| **columns** | string[] | Determines ids of the columns which are displayed. | +| **expandedDoc** | (optional) DataTableRecord | If set, the given document is displayed in a flyout. | +| **dataView** | DataView | The used data view. | +| **loadingState** | DataLoadingState | Determines if data is currently loaded. | +| **onFilter** | DocViewFilterFn | Function to add a filter in the grid cell or document flyout. | +| **onResize** | (optional)(colSettings: { columnId: string; width: number }) => void; | Function triggered when a column is resized by the user. | +| **onSetColumns** | (columns: string[], hideTimeColumn: boolean) => void; | Function to set all columns. | +| **onSort** | (optional)(sort: string[][]) => void; | Function to change sorting of the documents, skipped when isSortEnabled is set to false. | +| **rows** | (optional)DataTableRecord[] | Array of documents provided by Elasticsearch. | +| **sampleSize** | number | The max size of the documents returned by Elasticsearch. | +| **setExpandedDoc** | (optional)(doc?: DataTableRecord) => void; | Function to set the expanded document, which is displayed in a flyout. | +| **settings** | (optional)UnifiedDataTableSettings | Grid display settings persisted in Elasticsearch (e.g. column width). | +| **searchDescription** | (optional)string | Search description. | +| **searchTitle** | (optional)string | Search title. | +| **showTimeCol** | boolean | Determines whether the time columns should be displayed (legacy settings). | +| **showFullScreenButton** | (optional)boolean | Determines whether the full screen button should be displayed. | +| **isSortEnabled** | (optional)boolean | Manage user sorting control. | +| **sort** | SortOrder[] | Current sort setting. | +| **useNewFieldsApi** | boolean | How the data is fetched. | +| **isPaginationEnabled** | (optional)boolean | Manage pagination control. | +| **controlColumnIds** | (optional)string[] | List of used control columns (available: 'openDetails', 'select'). | +| **rowHeightState** | (optional)number | Row height from state. | +| **onUpdateRowHeight** | (optional)(rowHeight: number) => void; | Update row height state. | +| **isPlainRecord** | (optional)boolean | Is text base lang mode enabled. | +| **rowsPerPageState** | (optional)number | Current state value for rowsPerPage. | +| **onUpdateRowsPerPage** | (optional)(rowsPerPage: number) => void; | Update rows per page state. | +| **onFieldEdited** | (optional)() => void; | Callback to execute on edit runtime field. | +| **cellActionsTriggerId** | (optional)string | Optional triggerId to retrieve the column cell actions that will override the default ones. | +| **services** | See Required **services** list below | Service dependencies. | +| **renderDocumentView** | (optional)(hit: DataTableRecord,displayedRows: DataTableRecord[],displayedColumns: string[]) => JSX.Element | undefined; | Callback to render DocumentView when the document is expanded. | +| **configRowHeight** | (optional)number | Optional value for providing configuration setting for UnifiedDataTable rows height. | +| **showMultiFields** | (optional)boolean | Optional value for providing configuration setting for enabling to display the complex fields in the table. Default is true. | +| **maxDocFieldsDisplayed** | (optional)number | Optional value for providing configuration setting for maximum number of document fields to display in the table. Default is 50. | +| **externalControlColumns** | (optional)EuiDataGridControlColumn[] | Optional value for providing EuiDataGridControlColumn list of the additional leading control columns. UnifiedDataTable includes two control columns: Open Details and Select. | +| **totalHits** | (optional)number | Number total hits from ES. | +| **onFetchMoreRecords** | (optional)() => void | To fetch more. | +| **externalAdditionalControls** | (optional)React.ReactNode | Optional value for providing the additional controls available in the UnifiedDataTable toolbar to manage it's records or state. UnifiedDataTable includes Columns, Sorting and Bulk Actions. | +| **rowsPerPageOptions** | (optional)number[] | Optional list of number type values to set custom UnifiedDataTable paging options to display the records per page. | +| **renderCustomGridBody** | (optional)(args: EuiDataGridCustomBodyProps) => React.ReactNode; | An optional function called to completely customize and control the rendering of EuiDataGrid's body and cell placement. | +| **trailingControlColumns** | (optional)EuiDataGridControlColumn[] | An optional list of the EuiDataGridControlColumn type for setting trailing control columns standard for EuiDataGrid. | +| **visibleCellActions** | (optional)number | An optional value for a custom number of the visible cell actions in the table. By default is up to 3. | +| **externalCustomRenderers** | (optional)Record React.ReactNode>; | An optional settings for a specified fields rendering like links. Applied only for the listed fields rendering. | +| **consumer** | (optional)string | Name of the UnifiedDataTable consumer component or application. | +| **componentsTourSteps** | (optional)Record | Optional key/value pairs to set guided onboarding steps ids for a data table components included to guided tour. | + +*Required **services** list: +``` + theme: ThemeServiceStart; + fieldFormats: FieldFormatsStart; + uiSettings: IUiSettingsClient; + dataViewFieldEditor: DataViewFieldEditorStart; + toastNotifications: ToastsStart; + storage: Storage; + data: DataPublicPluginStart; +``` + +Usage example: + +``` + // Memoize unified data table to avoid the unnecessary re-renderings + const DataTableMemoized = React.memo(UnifiedDataTable); + + // Add memoized component with all needed props + { + // Add logic to refetch the data when the filter by field was added/removed. Refetch data. + }} + onResize={(colSettings: { columnId: string; width: number }) => { + // Update the table state with the new width for the column + }} + onSetColumns={(columns: string[], hideTimeColumn: boolean) => { + // Update table state with the new columns. Refetch data. + }} + onSort={!isTextBasedQuery ? onSort : undefined + // Update table state with the new sorting settings. Refetch data. + } + rows={searchResultRows} + sampleSize={500} + setExpandedDoc={() => { + // Callback function to do the logic when the document is expanded + }} + settings={tableSettings} + showTimeCol={true} + isSortEnabled={true} + sort={sortingColumns} + rowHeightState={3} + onUpdateRowHeight={(rowHeight: number) => { + // Do the state update with the new setting of the row height + }} + isPlainRecord={isTextBasedQuery} + rowsPerPageState={50} + onUpdateRowsPerPage={(rowHeight: number) => { + // Do the state update with the new number of the rows per page + } + onFieldEdited={() => + // Callback to execute on edit runtime field. Refetch data. + } + cellActionsTriggerId={SecurityCellActionsTrigger.DEFAULT} + services={{ + theme, + fieldFormats, + storage, + toastNotifications: toastsService, + uiSettings, + dataViewFieldEditor, + data: dataPluginContract, + }} + visibleCellActions={3} + externalCustomRenderers={{ + // Set the record style definition for the specific fields rendering Record React.ReactNode> + }} + renderDocumentView={() => + // Implement similar callback to render the Document flyout + const renderDetailsPanel = useCallback( + () => ( + + ), + [browserFields, handleOnPanelClosed, runtimeMappings, timelineId] + ); + } + externalControlColumns={leadingControlColumns} + externalAdditionalControls={additionalControls} + trailingControlColumns={trailingControlColumns} + renderCustomGridBody={renderCustomGridBody} + rowsPerPageOptions={[10, 30, 40, 100]} + showFullScreenButton={false} + useNewFieldsApi={true} + maxDocFieldsDisplayed={50} + consumer="timeline" + totalHits={ + // total number of the documents in the search query result. For example: 1200 + } + onFetchMoreRecords={() => { + // Do some data fetch to get more data + }} + configRowHeight={3} + showMultiFields={true} + componentsTourSteps={'expandButton': DISCOVER_TOUR_STEP_ANCHOR_IDS.expandDocument} + /> +``` + +## JsonCodeEditorCommon Component +Props description: +| Property | Type | Description | +| :--- | :--- | :--- | +| **width** | (optional) string or number | Editor component width. | +| **height** | (optional) string or number | Editor component height. | +| **hasLineNumbers** | (optional) boolean | Define if the editor component has line numbers style. | +| **hideCopyButton** | (optional) boolean | Show/hide setting for Copy button. | +| **onEditorDidMount** | (editor: monaco.editor.IStandaloneCodeEditor) => void | Do some logic to update the state with the edotor component value. | + +Usage example: + +``` + setEditor(editorNode)} +/> + +``` + +## Utils + +* `getRowsPerPageOptions(currentRowsPerPage)` - gets list of the table defaults for perPage options. + +* `getDisplayedColumns(currentRowsPerPage)` - gets list of the table columns with the logic to define the empty list with _source column. + +* `popularizeField(...)` - helper function to define the dataView persistance and save indexPattern update capabilities. + +## Hooks + +* `useColumns(...)` - this hook define the state update for the columns event handlers and allows to use them for external components outside the UnifiedDataTable. + +An example of using hooks for defining event handlers for columns management with setting the consumer specific setAppState: + +``` +const { + columns: currentColumns, + onAddColumn, + onRemoveColumn, + onMoveColumn, + onSetColumns, + } = useColumns({ + capabilities, + defaultOrder: uiSettings.get(SORT_DEFAULT_ORDER_SETTING), + dataView, + dataViews, + setAppState: stateContainer.appState.update, + useNewFieldsApi, + columns, + sort, + }); + +// Use onAddColumn, onRemoveColumn handlers in the DocumentView + +const renderDocumentView = useCallback( + (hit: DataTableRecord, displayedRows: DataTableRecord[], displayedColumns: string[]) => ( + setExpandedDoc(undefined)} + setExpandedDoc={setExpandedDoc} + query={query} + /> + ), + [dataView, onAddColumn, onAddFilter, onRemoveColumn, query, savedSearch.id, setExpandedDoc] + ); +``` \ No newline at end of file diff --git a/packages/kbn-unified-data-table/__mocks__/config.ts b/packages/kbn-unified-data-table/__mocks__/config.ts new file mode 100644 index 0000000000000..b8ae4a531038c --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/config.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { Config } from '@kbn/config'; + +export type ConfigMock = jest.Mocked; + +const createConfigMock = (): ConfigMock => ({ + has: jest.fn(), + get: jest.fn(), + set: jest.fn(), + getFlattenedPaths: jest.fn(), + toRaw: jest.fn(), +}); + +export const configMock = { + create: createConfigMock, +}; diff --git a/packages/kbn-unified-data-table/__mocks__/data_view_complex.ts b/packages/kbn-unified-data-table/__mocks__/data_view_complex.ts new file mode 100644 index 0000000000000..8122103c9f4d7 --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/data_view_complex.ts @@ -0,0 +1,419 @@ +/* + * Copyright 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 { DataView } from '@kbn/data-views-plugin/public'; +import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__'; + +const fields = [ + { + count: 0, + name: '_id', + type: 'string', + esTypes: ['_id'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: '_index', + type: 'string', + esTypes: ['_index'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + count: 0, + name: '_score', + type: 'number', + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: '_source', + type: '_source', + esTypes: ['_source'], + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: '_type', + type: 'string', + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 2, + name: 'array_objects.description', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'array_objects.description.keyword', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: { + multi: { + parent: 'array_objects.description', + }, + }, + }, + { + count: 0, + name: 'array_objects.name', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'array_objects.name.keyword', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: { + multi: { + parent: 'array_objects.name', + }, + }, + }, + { + count: 0, + name: 'array_tags', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'array_tags.keyword', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: { + multi: { + parent: 'array_tags', + }, + }, + }, + { + count: 0, + name: 'binary_blob', + type: 'unknown', + esTypes: ['binary'], + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'bool_enabled', + type: 'boolean', + esTypes: ['boolean'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 0, + name: 'date', + type: 'date', + esTypes: ['date'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 1, + name: 'date_nanos', + type: 'date', + esTypes: ['date_nanos'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 0, + name: 'flattened_labels', + type: 'unknown', + esTypes: ['flattened'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 0, + name: 'geo_point', + type: 'geo_point', + esTypes: ['geo_point'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 1, + name: 'geometry', + type: 'unknown', + esTypes: ['shape'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 1, + name: 'histogram', + type: 'histogram', + esTypes: ['histogram'], + scripted: false, + searchable: false, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 0, + name: 'ip_addr', + type: 'ip', + esTypes: ['ip'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 4, + name: 'keyword_key', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 0, + name: 'nested_user.first', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + subType: { + nested: { + path: 'nested_user', + }, + }, + }, + { + count: 0, + name: 'nested_user.first.keyword', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: { + multi: { + parent: 'nested_user.first', + }, + nested: { + path: 'nested_user', + }, + }, + }, + { + count: 0, + name: 'nested_user.last', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + subType: { + nested: { + path: 'nested_user', + }, + }, + }, + { + count: 0, + name: 'nested_user.last.keyword', + type: 'string', + esTypes: ['keyword'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + subType: { + multi: { + parent: 'nested_user.last', + }, + nested: { + path: 'nested_user', + }, + }, + }, + { + count: 3, + name: 'number_amount', + type: 'number', + esTypes: ['long'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 3, + name: 'number_price', + type: 'number', + esTypes: ['float'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 0, + name: 'object_user.first', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'object_user.last', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'range_time_frame', + type: 'date_range', + esTypes: ['date_range'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 1, + name: 'rank_features', + type: 'unknown', + esTypes: ['rank_features'], + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 5, + name: 'text_message', + type: 'string', + esTypes: ['text'], + scripted: false, + searchable: true, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'vector', + type: 'unknown', + esTypes: ['dense_vector'], + scripted: false, + searchable: false, + aggregatable: false, + readFromDocValues: false, + }, + { + count: 0, + name: 'version', + type: 'string', + esTypes: ['version'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: true, + }, + { + count: 1, + script: 'return "hi there"', + lang: 'painless', + name: 'scripted_string', + type: 'string', + scripted: true, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, + { + count: 0, + name: 'runtime_number', + type: 'number', + esTypes: ['double'], + scripted: false, + searchable: true, + aggregatable: true, + readFromDocValues: false, + }, +] as DataView['fields']; + +export const dataViewComplexMock = buildDataViewMock({ + name: 'data-view-with-various-field-types', + fields, + timeFieldName: 'data', +}); diff --git a/packages/kbn-unified-data-table/__mocks__/data_view_with_timefield.ts b/packages/kbn-unified-data-table/__mocks__/data_view_with_timefield.ts new file mode 100644 index 0000000000000..374b6b23f837b --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/data_view_with_timefield.ts @@ -0,0 +1,64 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { DataView } from '@kbn/data-views-plugin/public'; +import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__'; + +const fields = [ + { + name: '_index', + type: 'string', + scripted: false, + filterable: true, + }, + { + name: 'timestamp', + displayName: 'timestamp', + type: 'date', + scripted: false, + filterable: true, + aggregatable: true, + sortable: true, + }, + { + name: 'message', + displayName: 'message', + type: 'string', + scripted: false, + filterable: false, + }, + { + name: 'extension', + displayName: 'extension', + type: 'string', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'bytes', + displayName: 'bytes', + type: 'number', + scripted: false, + filterable: true, + aggregatable: true, + }, + { + name: 'scripted', + displayName: 'scripted', + type: 'number', + scripted: true, + filterable: false, + }, +] as DataView['fields']; + +export const dataViewWithTimefieldMock = buildDataViewMock({ + name: 'index-pattern-with-timefield', + fields, + timeFieldName: 'timestamp', +}); diff --git a/packages/kbn-unified-data-table/__mocks__/data_views.ts b/packages/kbn-unified-data-table/__mocks__/data_views.ts new file mode 100644 index 0000000000000..bdbf63ecfbfbe --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/data_views.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 { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; +import { dataViewComplexMock } from './data_view_complex'; +import { dataViewWithTimefieldMock } from './data_view_with_timefield'; + +export const dataViewMockList = [dataViewMock, dataViewComplexMock, dataViewWithTimefieldMock]; + +export function createDataViewsMock() { + return { + getCache: async () => { + return [dataViewMock]; + }, + get: async (id: string) => { + if (id === 'invalid-data-view-id') { + return Promise.reject('Invalid'); + } + const dataView = dataViewMockList.find((dv) => dv.id === id); + if (dataView) { + return Promise.resolve(dataView); + } else { + return Promise.reject(`DataView ${id} not found`); + } + }, + getDefaultDataView: jest.fn(() => dataViewMock), + updateSavedObject: jest.fn(), + getIdsWithTitle: jest.fn(() => { + return Promise.resolve(dataViewMockList); + }), + createFilter: jest.fn(), + create: jest.fn(), + clearInstanceCache: jest.fn(), + getFieldsForIndexPattern: jest.fn((dataView) => dataView.fields), + refreshFields: jest.fn(), + } as unknown as jest.Mocked; +} + +export const dataViewsMock = createDataViewsMock(); diff --git a/src/plugins/discover/public/__mocks__/es_hits_complex.ts b/packages/kbn-unified-data-table/__mocks__/es_hits_complex.ts similarity index 100% rename from src/plugins/discover/public/__mocks__/es_hits_complex.ts rename to packages/kbn-unified-data-table/__mocks__/es_hits_complex.ts diff --git a/packages/kbn-unified-data-table/__mocks__/external_control_columns.tsx b/packages/kbn-unified-data-table/__mocks__/external_control_columns.tsx new file mode 100644 index 0000000000000..d67afccc01559 --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/external_control_columns.tsx @@ -0,0 +1,118 @@ +/* + * Copyright 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, { useState } from 'react'; +import { + EuiCheckbox, + EuiButtonIcon, + EuiPopover, + EuiFlexGroup, + EuiFlexItem, + EuiPopoverTitle, + EuiSpacer, + EuiDataGridControlColumn, +} from '@elastic/eui'; + +const SelectionHeaderCell = () => { + return ( +
+ null} /> +
+ ); +}; + +const SimpleHeaderCell = () => { + return ( +
+ {'Additional Actions'} +
+ ); +}; + +const SelectionRowCell = ({ rowIndex }: { rowIndex: number }) => { + return ( +
+ null} + /> +
+ ); +}; + +const TestTrailingColumn = () => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + return ( + setIsPopoverOpen(!isPopoverOpen)} + /> + } + data-test-subj="test-trailing-column-popover-button" + closePopover={() => setIsPopoverOpen(false)} + > + {'Actions'} +
+ + + +
+
+ ); +}; + +export const testTrailingControlColumns = [ + { + id: 'actions', + width: 96, + headerCellRender: SimpleHeaderCell, + rowCellRender: TestTrailingColumn, + }, +]; + +export const testLeadingControlColumn: EuiDataGridControlColumn = { + id: 'test-leading-control', + headerCellRender: SelectionHeaderCell, + rowCellRender: SelectionRowCell, + width: 100, +}; diff --git a/packages/kbn-unified-data-table/__mocks__/local_storage_mock.ts b/packages/kbn-unified-data-table/__mocks__/local_storage_mock.ts new file mode 100644 index 0000000000000..42cd33d2eb699 --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/local_storage_mock.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 class LocalStorageMock { + private store: Record; + constructor(defaultStore: Record) { + this.store = defaultStore; + } + clear() { + this.store = {}; + } + get(key: string) { + return this.store[key] || null; + } + set(key: string, value: unknown) { + this.store[key] = String(value); + } + remove(key: string) { + delete this.store[key]; + } +} diff --git a/packages/kbn-unified-data-table/__mocks__/services.ts b/packages/kbn-unified-data-table/__mocks__/services.ts new file mode 100644 index 0000000000000..2c74668644497 --- /dev/null +++ b/packages/kbn-unified-data-table/__mocks__/services.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { of } from 'rxjs'; +import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; +import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks'; +import { chromeServiceMock, coreMock } from '@kbn/core/public/mocks'; +import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; +import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; +import { IUiSettingsClient, ToastsStart } from '@kbn/core/public'; +import { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; + +export function createServicesMock() { + const expressionsPlugin = expressionsPluginMock.createStartContract(); + + expressionsPlugin.run = jest.fn(() => + of({ + partial: false, + result: { + rows: [], + }, + }) + ) as unknown as typeof expressionsPlugin.run; + + const corePluginMock = coreMock.createStart(); + + const uiSettingsMock: Partial = { + get: jest.fn(), + isDefault: jest.fn((key: string) => { + return true; + }), + }; + + corePluginMock.uiSettings = { + ...corePluginMock.uiSettings, + ...uiSettingsMock, + }; + + const theme = { + theme$: of({ darkMode: false }), + }; + + corePluginMock.theme = theme; + + const dataPlugin = dataPluginMock.createStartContract(); + + return { + core: corePluginMock, + charts: chartPluginMock.createSetupContract(), + chrome: chromeServiceMock.createStartContract(), + history: () => ({ + location: { + search: '', + }, + listen: jest.fn(), + }), + fieldFormats: fieldFormatsMock, + filterManager: jest.fn(), + inspector: { + open: jest.fn(), + }, + uiActions: uiActionsPluginMock.createStartContract(), + uiSettings: uiSettingsMock as IUiSettingsClient, + http: { + basePath: '/', + }, + dataViewEditor: { + openEditor: jest.fn(), + userPermissions: { + editDataView: jest.fn(() => true), + }, + }, + dataViewFieldEditor: { + openEditor: jest.fn(), + userPermissions: { + editIndexPattern: jest.fn(() => true), + }, + } as unknown as DataViewFieldEditorStart, + theme, + storage: { + clear: jest.fn(), + get: jest.fn(), + set: jest.fn(), + remove: jest.fn(), + }, + toastNotifications: { + addInfo: jest.fn(), + addWarning: jest.fn(), + addDanger: jest.fn(), + addSuccess: jest.fn(), + } as unknown as ToastsStart, + expressions: expressionsPlugin, + savedObjectsTagging: { + ui: { + getTagIdsFromReferences: jest.fn().mockResolvedValue([]), + updateTagsReferences: jest.fn(), + }, + }, + dataViews: jest.fn(), + locator: { + useUrl: jest.fn(() => ''), + navigate: jest.fn(), + getUrl: jest.fn(() => Promise.resolve('')), + }, + contextLocator: { getRedirectUrl: jest.fn(() => '') }, + singleDocLocator: { getRedirectUrl: jest.fn(() => '') }, + data: dataPlugin, + }; +} + +export const servicesMock = createServicesMock(); diff --git a/src/plugins/discover/public/__mocks__/grid_context.ts b/packages/kbn-unified-data-table/__mocks__/table_context.ts similarity index 69% rename from src/plugins/discover/public/__mocks__/grid_context.ts rename to packages/kbn-unified-data-table/__mocks__/table_context.ts index 8949945c2b0d8..4a4a75b0fa9e5 100644 --- a/src/plugins/discover/public/__mocks__/grid_context.ts +++ b/packages/kbn-unified-data-table/__mocks__/table_context.ts @@ -10,13 +10,13 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import { dataViewMock, esHitsMock } from '@kbn/discover-utils/src/__mocks__'; import { dataViewComplexMock } from './data_view_complex'; import { esHitsComplex } from './es_hits_complex'; -import { discoverServiceMock } from './services'; -import { GridContext } from '../components/discover_grid/discover_grid_context'; -import { convertValueToString } from '../utils/convert_value_to_string'; +import { servicesMock } from './services'; +import { DataTableContext } from '../src/table_context'; +import { convertValueToString } from '../src/utils/convert_value_to_string'; import { buildDataTableRecord } from '@kbn/discover-utils'; import type { EsHitRecord } from '@kbn/discover-utils/types'; -const buildGridContext = (dataView: DataView, rows: EsHitRecord[]): GridContext => { +const buildTableContext = (dataView: DataView, rows: EsHitRecord[]): DataTableContext => { const usedRows = rows.map((row) => { return buildDataTableRecord(row, dataView); }); @@ -34,7 +34,7 @@ const buildGridContext = (dataView: DataView, rows: EsHitRecord[]): GridContext convertValueToString({ rowIndex, columnId, - fieldFormats: discoverServiceMock.fieldFormats, + fieldFormats: servicesMock.fieldFormats, rows: usedRows, dataView, options, @@ -42,6 +42,6 @@ const buildGridContext = (dataView: DataView, rows: EsHitRecord[]): GridContext }; }; -export const discoverGridContextMock = buildGridContext(dataViewMock, esHitsMock); +export const dataTableContextMock = buildTableContext(dataViewMock, esHitsMock); -export const discoverGridContextComplexMock = buildGridContext(dataViewComplexMock, esHitsComplex); +export const dataTableContextComplexMock = buildTableContext(dataViewComplexMock, esHitsComplex); diff --git a/packages/kbn-unified-data-table/index.ts b/packages/kbn-unified-data-table/index.ts new file mode 100644 index 0000000000000..2c5e995619436 --- /dev/null +++ b/packages/kbn-unified-data-table/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { UnifiedDataTable, DataLoadingState } from './src/components/data_table'; +export type { UnifiedDataTableProps } from './src/components/data_table'; +export { getDisplayedColumns } from './src/utils/columns'; + +export { JSONCodeEditorCommonMemoized } from './src/components/json_code_editor/json_code_editor_common'; + +export * from './src/types'; +export * as columnActions from './src/components/actions/columns'; + +export { getRowsPerPageOptions } from './src/utils/rows_per_page'; +export { popularizeField } from './src/utils/popularize_field'; + +export { useColumns } from './src/hooks/use_data_grid_columns'; diff --git a/packages/kbn-unified-data-table/jest.config.js b/packages/kbn-unified-data-table/jest.config.js new file mode 100644 index 0000000000000..5256221baacf4 --- /dev/null +++ b/packages/kbn-unified-data-table/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-unified-data-table'], +}; diff --git a/packages/kbn-unified-data-table/kibana.jsonc b/packages/kbn-unified-data-table/kibana.jsonc new file mode 100644 index 0000000000000..de49c4caff1e5 --- /dev/null +++ b/packages/kbn-unified-data-table/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "type": "shared-common", + "id": "@kbn/unified-data-table", + "description": "Contains functionality for the unified data table which can be integrated into apps", + "owner": "@elastic/kibana-data-discovery" +} diff --git a/packages/kbn-unified-data-table/package.json b/packages/kbn-unified-data-table/package.json new file mode 100644 index 0000000000000..79d4157293c05 --- /dev/null +++ b/packages/kbn-unified-data-table/package.json @@ -0,0 +1,10 @@ +{ + "name": "@kbn/unified-data-table", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0", + "sideEffects": [ + "*.css", + "*.scss" + ] +} diff --git a/src/plugins/discover/public/components/doc_table/actions/columns.test.ts b/packages/kbn-unified-data-table/src/components/actions/columns.test.ts similarity index 90% rename from src/plugins/discover/public/components/doc_table/actions/columns.test.ts rename to packages/kbn-unified-data-table/src/components/actions/columns.test.ts index c95ff0d8d7252..d8480cf2067b4 100644 --- a/src/plugins/discover/public/components/doc_table/actions/columns.test.ts +++ b/packages/kbn-unified-data-table/src/components/actions/columns.test.ts @@ -7,15 +7,13 @@ */ import { getStateColumnActions } from './columns'; -import { configMock } from '../../../__mocks__/config'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { dataViewsMock } from '../../../__mocks__/data_views'; import { Capabilities } from '@kbn/core/types'; -import { DiscoverAppState } from '../../../application/main/services/discover_app_state_container'; +import { dataViewsMock } from '../../../__mocks__/data_views'; function getStateColumnAction( - state: DiscoverAppState, - setAppState: (state: Partial) => void + state: { columns?: string[]; sort?: string[][] }, + setAppState: (state: { columns: string[]; sort?: string[][] }) => void ) { return getStateColumnActions({ capabilities: { @@ -23,13 +21,13 @@ function getStateColumnAction( save: false, }, } as unknown as Capabilities, - config: configMock, dataView: dataViewMock, dataViews: dataViewsMock, useNewFieldsApi: true, setAppState, columns: state.columns, sort: state.sort, + defaultOrder: 'desc', }); } diff --git a/src/plugins/discover/public/components/doc_table/actions/columns.ts b/packages/kbn-unified-data-table/src/components/actions/columns.ts similarity index 83% rename from src/plugins/discover/public/components/doc_table/actions/columns.ts rename to packages/kbn-unified-data-table/src/components/actions/columns.ts index b45d95433165a..3355902ece86e 100644 --- a/src/plugins/discover/public/components/doc_table/actions/columns.ts +++ b/packages/kbn-unified-data-table/src/components/actions/columns.ts @@ -5,13 +5,10 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { Capabilities, IUiSettingsClient } from '@kbn/core/public'; -import { DataViewsContract } from '@kbn/data-plugin/public'; -import { DataView } from '@kbn/data-views-plugin/public'; -import { SORT_DEFAULT_ORDER_SETTING } from '@kbn/discover-utils'; -import { DiscoverAppStateContainer } from '../../../application/main/services/discover_app_state_container'; -import { GetStateReturn as ContextGetStateReturn } from '../../../application/context/services/context_state'; -import { popularizeField } from '../../../utils/popularize_field'; +import { Capabilities } from '@kbn/core/public'; +import type { DataViewsContract } from '@kbn/data-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; +import { popularizeField } from '../../utils/popularize_field'; /** * Helper function to provide a fallback to a single _source column if the given array of columns @@ -57,27 +54,26 @@ export function moveColumn(columns: string[], columnName: string, newIndex: numb export function getStateColumnActions({ capabilities, - config, dataView, dataViews, useNewFieldsApi, setAppState, columns, sort, + defaultOrder, }: { capabilities: Capabilities; - config: IUiSettingsClient; dataView: DataView; dataViews: DataViewsContract; useNewFieldsApi: boolean; - setAppState: DiscoverAppStateContainer['update'] | ContextGetStateReturn['setAppState']; + setAppState: (state: { columns: string[]; sort?: string[][] }) => void; columns?: string[]; sort: string[][] | undefined; + defaultOrder: string; }) { function onAddColumn(columnName: string) { popularizeField(dataView, columnName, dataViews, capabilities); const nextColumns = addColumn(columns || [], columnName, useNewFieldsApi); - const defaultOrder = config.get(SORT_DEFAULT_ORDER_SETTING); const nextSort = columnName === '_score' && !sort?.length ? [['_score', defaultOrder]] : sort; setAppState({ columns: nextColumns, sort: nextSort }); } diff --git a/src/plugins/discover/public/components/discover_grid/build_copy_column_button.test.tsx b/packages/kbn-unified-data-table/src/components/build_copy_column_button.test.tsx similarity index 86% rename from src/plugins/discover/public/components/discover_grid/build_copy_column_button.test.tsx rename to packages/kbn-unified-data-table/src/components/build_copy_column_button.test.tsx index dda3a904bda3f..02a3c6e7e425e 100644 --- a/src/plugins/discover/public/components/discover_grid/build_copy_column_button.test.tsx +++ b/packages/kbn-unified-data-table/src/components/build_copy_column_button.test.tsx @@ -9,8 +9,8 @@ import React from 'react'; import { EuiButton } from '@elastic/eui'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { discoverServiceMock } from '../../__mocks__/services'; -import { discoverGridContextMock } from '../../__mocks__/grid_context'; +import { servicesMock } from '../../__mocks__/services'; +import { dataTableContextMock } from '../../__mocks__/table_context'; import { buildCopyColumnNameButton, buildCopyColumnValuesButton } from './build_copy_column_button'; const execCommandMock = (global.document.execCommand = jest.fn()); @@ -20,7 +20,7 @@ describe('Build a column button to copy to clipboard', () => { it('should copy a column name to clipboard on click', () => { const { label, iconType, onClick } = buildCopyColumnNameButton({ columnDisplayName: 'test-field-name', - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, }); execCommandMock.mockImplementationOnce(() => true); @@ -49,9 +49,9 @@ describe('Build a column button to copy to clipboard', () => { const { label, iconType, onClick } = buildCopyColumnValuesButton({ columnId: 'extension', columnDisplayName: 'custom_extension', - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, rowsCount: 3, - valueToStringConverter: discoverGridContextMock.valueToStringConverter, + valueToStringConverter: dataTableContextMock.valueToStringConverter, }); const wrapper = mountWithIntl( @@ -72,8 +72,8 @@ describe('Build a column button to copy to clipboard', () => { } = buildCopyColumnValuesButton({ columnId: '_source', columnDisplayName: 'Document', - toastNotifications: discoverServiceMock.toastNotifications, - valueToStringConverter: discoverGridContextMock.valueToStringConverter, + toastNotifications: servicesMock.toastNotifications, + valueToStringConverter: dataTableContextMock.valueToStringConverter, rowsCount: 3, }); @@ -101,7 +101,7 @@ describe('Build a column button to copy to clipboard', () => { it('should not copy to clipboard on click', () => { const { label, iconType, onClick } = buildCopyColumnNameButton({ columnDisplayName: 'test-field-name', - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, }); execCommandMock.mockImplementationOnce(() => false); diff --git a/src/plugins/discover/public/components/discover_grid/build_copy_column_button.tsx b/packages/kbn-unified-data-table/src/components/build_copy_column_button.tsx similarity index 90% rename from src/plugins/discover/public/components/discover_grid/build_copy_column_button.tsx rename to packages/kbn-unified-data-table/src/components/build_copy_column_button.tsx index 111e80dd62e95..d1bfff1f1da41 100644 --- a/src/plugins/discover/public/components/discover_grid/build_copy_column_button.tsx +++ b/packages/kbn-unified-data-table/src/components/build_copy_column_button.tsx @@ -13,8 +13,8 @@ import type { ToastsStart } from '@kbn/core/public'; import { copyColumnValuesToClipboard, copyColumnNameToClipboard, -} from '../../utils/copy_value_to_clipboard'; -import type { ValueToStringConverter } from '../../types'; +} from '../utils/copy_value_to_clipboard'; +import type { ValueToStringConverter } from '../types'; function buildCopyColumnButton({ label, @@ -47,7 +47,7 @@ export function buildCopyColumnNameButton({ return buildCopyColumnButton({ label: ( ), @@ -72,7 +72,7 @@ export function buildCopyColumnValuesButton({ return buildCopyColumnButton({ label: ( ), diff --git a/src/plugins/discover/public/components/discover_grid/build_edit_field_button.test.tsx b/packages/kbn-unified-data-table/src/components/build_edit_field_button.test.tsx similarity index 81% rename from src/plugins/discover/public/components/discover_grid/build_edit_field_button.test.tsx rename to packages/kbn-unified-data-table/src/components/build_edit_field_button.test.tsx index c78918976e88d..a9d1a37ab6eda 100644 --- a/src/plugins/discover/public/components/discover_grid/build_edit_field_button.test.tsx +++ b/packages/kbn-unified-data-table/src/components/build_edit_field_button.test.tsx @@ -11,7 +11,7 @@ import { DataView, DataViewField } from '@kbn/data-views-plugin/common'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import React from 'react'; import { buildDataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { discoverServiceMock } from '../../__mocks__/services'; +import { servicesMock } from '../../__mocks__/services'; import { buildEditFieldButton } from './build_edit_field_button'; const dataView = buildDataViewMock({ @@ -50,8 +50,7 @@ describe('buildEditFieldButton', () => { it('should return null if the field is not editable', () => { const field = dataView.getFieldByName('unknown_field') as DataViewField; const button = buildEditFieldButton({ - hasEditDataViewPermission: () => - discoverServiceMock.dataViewEditor.userPermissions.editDataView(), + hasEditDataViewPermission: () => servicesMock.dataViewEditor.userPermissions.editDataView(), dataView, field, editField: jest.fn(), @@ -61,12 +60,11 @@ describe('buildEditFieldButton', () => { it('should return null if the data view is not editable', () => { jest - .spyOn(discoverServiceMock.dataViewEditor.userPermissions, 'editDataView') + .spyOn(servicesMock.dataViewEditor.userPermissions, 'editDataView') .mockReturnValueOnce(false); const field = dataView.getFieldByName('bytes') as DataViewField; const button = buildEditFieldButton({ - hasEditDataViewPermission: () => - discoverServiceMock.dataViewEditor.userPermissions.editDataView(), + hasEditDataViewPermission: () => servicesMock.dataViewEditor.userPermissions.editDataView(), dataView, field, editField: jest.fn(), @@ -77,8 +75,7 @@ describe('buildEditFieldButton', () => { it('should return null if passed the _source field', () => { const field = dataView.getFieldByName('_source') as DataViewField; const button = buildEditFieldButton({ - hasEditDataViewPermission: () => - discoverServiceMock.dataViewEditor.userPermissions.editDataView(), + hasEditDataViewPermission: () => servicesMock.dataViewEditor.userPermissions.editDataView(), dataView, field, editField: jest.fn(), @@ -89,8 +86,7 @@ describe('buildEditFieldButton', () => { it('should return EuiListGroupItemProps if the field and data view are editable', () => { const field = dataView.getFieldByName('bytes') as DataViewField; const button = buildEditFieldButton({ - hasEditDataViewPermission: () => - discoverServiceMock.dataViewEditor.userPermissions.editDataView(), + hasEditDataViewPermission: () => servicesMock.dataViewEditor.userPermissions.editDataView(), dataView, field, editField: jest.fn(), @@ -105,7 +101,7 @@ describe('buildEditFieldButton', () => { "iconType": "pencil", "label": , "onClick": [Function], @@ -118,8 +114,7 @@ describe('buildEditFieldButton', () => { const field = dataView.getFieldByName('bytes') as DataViewField; const editField = jest.fn(); const buttonProps = buildEditFieldButton({ - hasEditDataViewPermission: () => - discoverServiceMock.dataViewEditor.userPermissions.editDataView(), + hasEditDataViewPermission: () => servicesMock.dataViewEditor.userPermissions.editDataView(), dataView, field, editField, diff --git a/src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx b/packages/kbn-unified-data-table/src/components/build_edit_field_button.tsx similarity index 87% rename from src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx rename to packages/kbn-unified-data-table/src/components/build_edit_field_button.tsx index 71da6ca691f93..87d405f608c8c 100644 --- a/src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx +++ b/packages/kbn-unified-data-table/src/components/build_edit_field_button.tsx @@ -10,7 +10,7 @@ import { EuiListGroupItemProps } from '@elastic/eui'; import { DataView, DataViewField } from '@kbn/data-views-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; -import { getFieldCapabilities } from '../../utils/get_field_capabilities'; +import { getFieldCapabilities } from '../utils/get_field_capabilities'; export const buildEditFieldButton = ({ hasEditDataViewPermission, @@ -37,7 +37,10 @@ export const buildEditFieldButton = ({ const editFieldButton: EuiListGroupItemProps = { size: 'xs', label: ( - + ), iconType: 'pencil', iconProps: { size: 'm' }, diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.scss b/packages/kbn-unified-data-table/src/components/data_table.scss similarity index 78% rename from src/plugins/discover/public/components/discover_grid/discover_grid.scss rename to packages/kbn-unified-data-table/src/components/data_table.scss index 0e870d366b609..8b0f8719a450f 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.scss +++ b/packages/kbn-unified-data-table/src/components/data_table.scss @@ -1,4 +1,4 @@ -.dscDiscoverGrid { +.unifiedDataTable { width: 100%; max-width: 100%; height: 100%; @@ -19,8 +19,8 @@ border-right: none; } - .dscDiscoverGrid__table .euiDataGridRowCell:first-of-type, - .dscDiscoverGrid__table .euiDataGrid--headerShade.euiDataGrid--bordersAll .euiDataGridHeaderCell:first-of-type { + .unifiedDataTable__table .euiDataGridRowCell:first-of-type, + .unifiedDataTable__table .euiDataGrid--headerShade.euiDataGrid--bordersAll .euiDataGridHeaderCell:first-of-type { border-left: none; border-right: none; } @@ -31,11 +31,11 @@ } } -.dscDiscoverGrid__cellValue { +.unifiedDataTable__cellValue { font-family: $euiCodeFontFamily; } -.dscDiscoverGrid__cellPopover { +.unifiedDataTable__cellPopover { // Fixes https://github.com/elastic/kibana/issues/145216 in Chrome .lines-content.monaco-editor-background { overflow: unset !important; @@ -43,7 +43,7 @@ } } -.dscDiscoverGrid__cellPopoverValue { +.unifiedDataTable__cellPopoverValue { font-family: $euiCodeFontFamily; font-size: $euiFontSizeS; } @@ -52,24 +52,32 @@ white-space: pre-wrap; } -.dscDiscoverGrid__inner { +.unifiedDataTable__inner { display: flex; flex-direction: column; flex-wrap: nowrap; height: 100%; } -.dscDiscoverGrid__table { +.unifiedDataTable__table { flex-grow: 1; flex-shrink: 1; min-height: 0; } -.dscTable__flyoutHeader { +.unifiedDataTable__footer { + flex-shrink: 0; + background-color: $euiColorLightShade; + padding: $euiSize / 2 $euiSize; + margin-top: $euiSize / 4; + text-align: center; +} + +.unifiedDataTable__flyoutHeader { white-space: nowrap; } -.dscTable__flyoutDocumentNavigation { +.unifiedDataTable__flyoutDocumentNavigation { justify-content: flex-end; } @@ -106,11 +114,11 @@ width: 100%; } -.dscFormatSource { +.unifiedDataTableFormatSource { @include euiTextTruncate; } -.dscDiscoverGrid__descriptionListDescription { +.unifiedDataTable__descriptionListDescription { word-break: break-all; white-space: normal; @@ -132,7 +140,7 @@ @include euiBreakpoint('xs', 's', 'm') { // EUI issue to hide 'of' text https://github.com/elastic/eui/issues/4654 - .dscTable__flyoutDocumentNavigation .euiPagination__compressedText { + .unifiedDataTable__flyoutDocumentNavigation .euiPagination__compressedText { display: none; } } diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx b/packages/kbn-unified-data-table/src/components/data_table.test.tsx similarity index 61% rename from src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx rename to packages/kbn-unified-data-table/src/components/data_table.test.tsx index 153126b4d471c..7ca0888230749 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.test.tsx @@ -7,16 +7,23 @@ */ import React from 'react'; import { ReactWrapper } from 'enzyme'; -import { EuiCopy } from '@elastic/eui'; +import { + EuiButton, + EuiCopy, + EuiDataGridCellValueElementProps, + EuiDataGridCustomBodyProps, +} from '@elastic/eui'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; import { act } from 'react-dom/test-utils'; import { findTestSubject } from '@elastic/eui/lib/test'; import { buildDataViewMock, deepMockedFields, esHitsMock } from '@kbn/discover-utils/src/__mocks__'; import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { DiscoverGrid, DiscoverGridProps, DataLoadingState } from './discover_grid'; +import { DataLoadingState, UnifiedDataTable, UnifiedDataTableProps } from './data_table'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { discoverServiceMock } from '../../__mocks__/services'; +import { servicesMock } from '../../__mocks__/services'; import { buildDataTableRecord, getDocId } from '@kbn/discover-utils'; -import type { EsHitRecord } from '@kbn/discover-utils/types'; +import type { DataTableRecord, EsHitRecord } from '@kbn/discover-utils/types'; +import { testLeadingControlColumn } from '../../__mocks__/external_control_columns'; const mockUseDataGridColumnsCellActions = jest.fn((prop: unknown) => []); jest.mock('@kbn/cell-actions', () => ({ @@ -30,8 +37,8 @@ export const dataViewMock = buildDataViewMock({ timeFieldName: '@timestamp', }); -function getProps() { - const services = discoverServiceMock; +function getProps(): UnifiedDataTableProps { + const services = servicesMock; services.dataViewFieldEditor.userPermissions.editIndexPattern = jest.fn().mockReturnValue(true); return { @@ -40,9 +47,7 @@ function getProps() { dataView: dataViewMock, loadingState: DataLoadingState.loaded, expandedDoc: undefined, - onAddColumn: jest.fn(), onFilter: jest.fn(), - onRemoveColumn: jest.fn(), onResize: jest.fn(), onSetColumns: jest.fn(), onSort: jest.fn(), @@ -55,14 +60,22 @@ function getProps() { showTimeCol: true, sort: [], useNewFieldsApi: true, - services, + services: { + fieldFormats: services.fieldFormats, + uiSettings: services.uiSettings, + dataViewFieldEditor: services.dataViewFieldEditor, + toastNotifications: services.toastNotifications, + storage: services.storage as unknown as Storage, + data: services.data, + theme: services.theme, + }, }; } -async function getComponent(props: DiscoverGridProps = getProps()) { - const Proxy = (innerProps: DiscoverGridProps) => ( - - +async function getComponent(props: UnifiedDataTableProps = getProps()) { + const Proxy = (innerProps: UnifiedDataTableProps) => ( + + ); @@ -74,7 +87,7 @@ async function getComponent(props: DiscoverGridProps = getProps()) { return component; } -function getSelectedDocNr(component: ReactWrapper) { +function getSelectedDocNr(component: ReactWrapper) { const gridSelectionBtn = findTestSubject(component, 'dscGridSelectionBtn'); if (!gridSelectionBtn.length) { return 0; @@ -83,7 +96,7 @@ function getSelectedDocNr(component: ReactWrapper) { return Number(selectedNr); } -function getDisplayedDocNr(component: ReactWrapper) { +function getDisplayedDocNr(component: ReactWrapper) { const gridSelectionBtn = findTestSubject(component, 'discoverDocTable'); if (!gridSelectionBtn.length) { return 0; @@ -93,7 +106,7 @@ function getDisplayedDocNr(component: ReactWrapper) { } async function toggleDocSelection( - component: ReactWrapper, + component: ReactWrapper, document: EsHitRecord ) { act(() => { @@ -103,13 +116,13 @@ async function toggleDocSelection( component.update(); } -describe('DiscoverGrid', () => { +describe('UnifiedDataTable', () => { afterEach(async () => { jest.clearAllMocks(); }); describe('Document selection', () => { - let component: ReactWrapper; + let component: ReactWrapper; beforeEach(async () => { component = await getComponent(); }); @@ -287,4 +300,136 @@ describe('DiscoverGrid', () => { `); }); }); + + describe('externalControlColumns', () => { + it('should render external leading control columns', async () => { + const component = await getComponent({ + ...getProps(), + expandedDoc: { + id: 'test', + raw: { + _index: 'test_i', + _id: 'test', + }, + flattened: { test: jest.fn() }, + }, + setExpandedDoc: jest.fn(), + renderDocumentView: jest.fn(), + externalControlColumns: [testLeadingControlColumn], + }); + + expect(findTestSubject(component, 'docTableExpandToggleColumn').exists()).toBeTruthy(); + expect(findTestSubject(component, 'test-body-control-column-cell').exists()).toBeTruthy(); + }); + }); + + it('should render provided in renderDocumentView DocumentView on expand clicked', async () => { + const component = await getComponent({ + ...getProps(), + expandedDoc: { + id: 'test', + raw: { + _index: 'test_i', + _id: 'test', + }, + flattened: { test: jest.fn() }, + }, + setExpandedDoc: jest.fn(), + renderDocumentView: ( + hit: DataTableRecord, + displayedRows: DataTableRecord[], + displayedColumns: string[] + ) =>
{hit.id}
, + externalControlColumns: [testLeadingControlColumn], + }); + + findTestSubject(component, 'docTableExpandToggleColumn').first().simulate('click'); + expect(findTestSubject(component, 'test-document-view').exists()).toBeTruthy(); + }); + + describe('externalAdditionalControls', () => { + it('should render external additional toolbar controls', async () => { + const component = await getComponent({ + ...getProps(), + columns: ['message'], + externalAdditionalControls: , + }); + + expect(findTestSubject(component, 'test-additional-control').exists()).toBeTruthy(); + expect(findTestSubject(component, 'dataGridColumnSelectorButton').exists()).toBeTruthy(); + }); + }); + + describe('externalCustomRenderers', () => { + it('should render only host column with the custom renderer, message should be rendered with the default cell renderer', async () => { + const component = await getComponent({ + ...getProps(), + columns: ['message', 'host'], + externalCustomRenderers: { + host: (props: EuiDataGridCellValueElementProps) => ( +
{props.columnId}
+ ), + }, + }); + + expect(findTestSubject(component, 'test-renderer-host').exists()).toBeTruthy(); + expect(findTestSubject(component, 'test-renderer-message').exists()).toBeFalsy(); + }); + }); + + describe('renderCustomGridBody', () => { + it('should render custom grid body for each row', async () => { + const component = await getComponent({ + ...getProps(), + columns: ['message', 'host'], + trailingControlColumns: [ + { + id: 'row-details', + + // The header cell should be visually hidden, but available to screen readers + width: 0, + headerCellRender: () => <>, + headerCellProps: { className: 'euiScreenReaderOnly' }, + + // The footer cell can be hidden to both visual & SR users, as it does not contain meaningful information + footerCellProps: { style: { display: 'none' } }, + + // When rendering this custom cell, we'll want to override + // the automatic width/heights calculated by EuiDataGrid + rowCellRender: jest.fn(), + }, + ], + renderCustomGridBody: (props: EuiDataGridCustomBodyProps) => ( +
+ +
+ ), + }); + + expect(findTestSubject(component, 'test-renderer-custom-grid-body').exists()).toBeTruthy(); + }); + }); + + describe('componentsTourSteps', () => { + it('should render tour step for the first row of leading control column expandButton', async () => { + const component = await getComponent({ + ...getProps(), + expandedDoc: { + id: 'test', + raw: { + _index: 'test_i', + _id: 'test', + }, + flattened: { test: jest.fn() }, + }, + setExpandedDoc: jest.fn(), + renderDocumentView: jest.fn(), + componentsTourSteps: { expandButton: 'test-expand' }, + }); + + const gridExpandBtn = findTestSubject(component, 'docTableExpandToggleColumn').first(); + const tourStep = gridExpandBtn.getDOMNode().getAttribute('id'); + expect(tourStep).toEqual('test-expand'); + }); + }); }); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx b/packages/kbn-unified-data-table/src/components/data_table.tsx similarity index 64% rename from src/plugins/discover/public/components/discover_grid/discover_grid.tsx rename to packages/kbn-unified-data-table/src/components/data_table.tsx index 662c5eb670d49..e5f5e5dbbba39 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.tsx @@ -11,7 +11,8 @@ import classnames from 'classnames'; import { FormattedMessage } from '@kbn/i18n-react'; import { of } from 'rxjs'; import useObservable from 'react-use/lib/useObservable'; -import './discover_grid.scss'; +import './data_table.scss'; +import type { Storage } from '@kbn/kibana-utils-plugin/public'; import { EuiDataGridSorting, EuiDataGrid, @@ -23,44 +24,42 @@ import { EuiIcon, EuiDataGridRefProps, EuiDataGridInMemory, + EuiDataGridControlColumn, + EuiDataGridCustomBodyProps, + EuiDataGridCellValueElementProps, } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { useDataGridColumnsCellActions, type UseDataGridColumnsCellActionsProps, } from '@kbn/cell-actions'; -import type { AggregateQuery, Filter, Query } from '@kbn/es-query'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { ToastsStart, IUiSettingsClient, HttpStart, CoreStart } from '@kbn/core/public'; -import { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; -import { Serializable } from '@kbn/utility-types'; +import type { ToastsStart, IUiSettingsClient } from '@kbn/core/public'; +import type { Serializable } from '@kbn/utility-types'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { getShouldShowFieldHandler } from '@kbn/discover-utils'; -import { - DOC_HIDE_TIME_COLUMN_SETTING, - MAX_DOC_FIELDS_DISPLAYED, - SHOW_MULTIFIELDS, -} from '@kbn/discover-utils'; +import { getShouldShowFieldHandler, DOC_HIDE_TIME_COLUMN_SETTING } from '@kbn/discover-utils'; +import type { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { ThemeServiceStart } from '@kbn/react-kibana-context-common'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { getSchemaDetectors } from './discover_grid_schema'; -import { DiscoverGridFlyout } from './discover_grid_flyout'; -import { DiscoverGridContext } from './discover_grid_context'; -import { getRenderCellValueFn } from './get_render_cell_value'; -import { DiscoverGridSettings } from './types'; +import { UnifiedDataTableSettings, ValueToStringConverter } from '../types'; +import { getDisplayedColumns } from '../utils/columns'; +import { convertValueToString } from '../utils/convert_value_to_string'; +import { getRowsPerPageOptions } from '../utils/rows_per_page'; +import { getRenderCellValueFn } from '../utils/get_render_cell_value'; +import { getEuiGridColumns, getLeadControlColumns, getVisibleColumns } from './data_table_columns'; +import { UnifiedDataTableContext } from '../table_context'; +import { getSchemaDetectors } from './data_table_schema'; +import { DataTableDocumentToolbarBtn } from './data_table_document_selection'; +import { useRowHeightsOptions } from '../hooks/use_row_heights_options'; import { - getEuiGridColumns, - getLeadControlColumns, - getVisibleColumns, -} from './discover_grid_columns'; -import { GRID_STYLE, toolbarVisibility as toolbarVisibilityDefaults } from './constants'; -import { getDisplayedColumns } from '../../utils/columns'; -import { DiscoverGridDocumentToolbarBtn } from './discover_grid_document_selection'; -import { DiscoverGridFooter } from './discover_grid_footer'; -import type { ValueToStringConverter } from '../../types'; -import { useRowHeightsOptions } from '../../hooks/use_row_heights_options'; -import { convertValueToString } from '../../utils/convert_value_to_string'; -import { getRowsPerPageOptions, getDefaultRowsPerPage } from '../../utils/rows_per_page'; + DEFAULT_ROWS_PER_PAGE, + GRID_STYLE, + toolbarVisibility as toolbarVisibilityDefaults, +} from '../constants'; +import { UnifiedDataTableFooter } from './data_table_footer'; + +export type SortOrder = [string, string]; export enum DataLoadingState { loading = 'loading', @@ -75,7 +74,7 @@ interface SortObj { direction: string; } -export interface DiscoverGridProps { +export interface UnifiedDataTableProps { /** * Determines which element labels the grid for ARIA */ @@ -85,7 +84,7 @@ export interface DiscoverGridProps { */ className?: string; /** - * Determines which columns are displayed + * Determines ids of the columns which are displayed */ columns: string[]; /** @@ -100,19 +99,10 @@ export interface DiscoverGridProps { * Determines if data is currently loaded */ loadingState: DataLoadingState; - /** - * Function used to add a column in the document flyout - */ - onAddColumn: (column: string) => void; /** * Function to add a filter in the grid cell or document flyout */ onFilter: DocViewFilterFn; - /** - * Function used in the grid header and flyout to remove a column - * @param column - */ - onRemoveColumn: (column: string) => void; /** * Function triggered when a column is resized by the user */ @@ -140,13 +130,13 @@ export interface DiscoverGridProps { /** * Grid display settings persisted in Elasticsearch (e.g. column width) */ - settings?: DiscoverGridSettings; + settings?: UnifiedDataTableSettings; /** - * Saved search description + * Search description */ searchDescription?: string; /** - * Saved search title + * Search title */ searchTitle?: string; /** @@ -201,22 +191,6 @@ export interface DiscoverGridProps { * Callback to execute on edit runtime field */ onFieldEdited?: () => void; - /** - * Filters applied by saved search embeddable - */ - filters?: Filter[]; - /** - * Query applied by KQL bar or text based editor - */ - query?: Query | AggregateQuery; - /** - * Saved search id used for links to single doc and surrounding docs in the flyout - */ - savedSearchId?: string; - /** - * Document detail view component - */ - DocumentView?: typeof DiscoverGridFlyout; /** * Optional triggerId to retrieve the column cell actions that will override the default ones */ @@ -225,13 +199,38 @@ export interface DiscoverGridProps { * Service dependencies */ services: { - core: CoreStart; + theme: ThemeServiceStart; fieldFormats: FieldFormatsStart; - addBasePath: HttpStart['basePath']['prepend']; uiSettings: IUiSettingsClient; dataViewFieldEditor: DataViewFieldEditorStart; toastNotifications: ToastsStart; + storage: Storage; + data: DataPublicPluginStart; }; + /** + * Callback to render DocumentView when the document is expanded + */ + renderDocumentView?: ( + hit: DataTableRecord, + displayedRows: DataTableRecord[], + displayedColumns: string[] + ) => JSX.Element | undefined; + /** + * Optional value for providing configuration setting for UnifiedDataTable rows height + */ + configRowHeight?: number; + /** + * Optional value for providing configuration setting for enabling to display the complex fields in the table. Default is true. + */ + showMultiFields?: boolean; + /** + * Optional value for providing configuration setting for maximum number of document fields to display in the table. Default is 50. + */ + maxDocFieldsDisplayed?: number; + /** + * Optional value for providing EuiDataGridControlColumn list of the additional leading control columns. UnifiedDataTable includes two control columns: Open Details and Select. + */ + externalControlColumns?: EuiDataGridControlColumn[]; /** * Number total hits from ES */ @@ -240,24 +239,62 @@ export interface DiscoverGridProps { * To fetch more */ onFetchMoreRecords?: () => void; + /** + * Optional value for providing the additional controls available in the UnifiedDataTable toolbar to manage it's records or state. UnifiedDataTable includes Columns, Sorting and Bulk Actions. + */ + externalAdditionalControls?: React.ReactNode; + /** + * Optional list of number type values to set custom UnifiedDataTable paging options to display the records per page. + */ + rowsPerPageOptions?: number[]; + /** + * An optional function called to completely customize and control the rendering of + * EuiDataGrid's body and cell placement. This can be used to, e.g. remove EuiDataGrid's + * virtualization library, or roll your own. + * + * This component is **only** meant as an escape hatch for extremely custom use cases. + * + * Behind the scenes, this function is treated as a React component, + * allowing hooks, context, and other React concepts to be used. + * It receives #EuiDataGridCustomBodyProps as its only argument. + */ + renderCustomGridBody?: (args: EuiDataGridCustomBodyProps) => React.ReactNode; + /** + * An optional list of the EuiDataGridControlColumn type for setting trailing control columns standard for EuiDataGrid. + */ + trailingControlColumns?: EuiDataGridControlColumn[]; + /** + * An optional value for a custom number of the visible cell actions in the table. By default is up to 3. + **/ + visibleCellActions?: number; + /** + * An optional settings for a specified fields rendering like links. Applied only for the listed fields rendering. + */ + externalCustomRenderers?: Record< + string, + (props: EuiDataGridCellValueElementProps) => React.ReactNode + >; + /** + * Name of the UnifiedDataTable consumer component or application + */ + consumer?: string; + /** + * Optional key/value pairs to set guided onboarding steps ids for a data table components included to guided tour. + */ + componentsTourSteps?: Record; } export const EuiDataGridMemoized = React.memo(EuiDataGrid); const CONTROL_COLUMN_IDS_DEFAULT = ['openDetails', 'select']; -export const DiscoverGrid = ({ +export const UnifiedDataTable = ({ ariaLabelledBy, columns, + controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT, dataView, loadingState, - expandedDoc, - onAddColumn, - filters, - query, - savedSearchId, onFilter, - onRemoveColumn, onResize, onSetColumns, onSort, @@ -265,7 +302,6 @@ export const DiscoverGrid = ({ sampleSize, searchDescription, searchTitle, - setExpandedDoc, settings, showTimeCol, showFullScreenButton = true, @@ -273,7 +309,6 @@ export const DiscoverGrid = ({ useNewFieldsApi, isSortEnabled = true, isPaginationEnabled = true, - controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT, cellActionsTriggerId, className, rowHeightState, @@ -282,13 +317,28 @@ export const DiscoverGrid = ({ rowsPerPageState, onUpdateRowsPerPage, onFieldEdited, - DocumentView, services, + renderCustomGridBody, + trailingControlColumns, totalHits, onFetchMoreRecords, -}: DiscoverGridProps) => { - const { fieldFormats, toastNotifications, dataViewFieldEditor, uiSettings } = services; - const { darkMode } = useObservable(services.core.theme?.theme$ ?? of(themeDefault), themeDefault); + renderDocumentView, + setExpandedDoc, + expandedDoc, + configRowHeight, + showMultiFields = true, + maxDocFieldsDisplayed = 50, + externalControlColumns, + externalAdditionalControls, + rowsPerPageOptions, + visibleCellActions, + externalCustomRenderers, + consumer = 'discover', + componentsTourSteps, +}: UnifiedDataTableProps) => { + const { fieldFormats, toastNotifications, dataViewFieldEditor, uiSettings, storage, data } = + services; + const { darkMode } = useObservable(services.theme?.theme$ ?? of(themeDefault), themeDefault); const dataGridRef = useRef(null); const [selectedDocs, setSelectedDocs] = useState([]); const [isFilterActive, setIsFilterActive] = useState(false); @@ -300,7 +350,7 @@ export const DiscoverGrid = ({ } const idMap = rows.reduce((map, row) => map.set(row.id, true), new Map()); // filter out selected docs that are no longer part of the current data - const result = selectedDocs.filter((docId) => idMap.get(docId)); + const result = selectedDocs.filter((docId) => !!idMap.get(docId)); if (result.length === 0 && isFilterActive) { setIsFilterActive(false); } @@ -336,17 +386,45 @@ export const DiscoverGrid = ({ [displayedRows, dataView, fieldFormats] ); + const unifiedDataTableContextValue = useMemo( + () => ({ + expanded: expandedDoc, + setExpanded: setExpandedDoc, + rows: displayedRows, + onFilter, + dataView, + isDarkMode: darkMode, + selectedDocs: usedSelectedDocs, + setSelectedDocs: (newSelectedDocs: React.SetStateAction) => { + setSelectedDocs(newSelectedDocs); + if (isFilterActive && newSelectedDocs.length === 0) { + setIsFilterActive(false); + } + }, + valueToStringConverter, + componentsTourSteps, + }), + [ + componentsTourSteps, + darkMode, + dataView, + displayedRows, + expandedDoc, + isFilterActive, + onFilter, + setExpandedDoc, + usedSelectedDocs, + valueToStringConverter, + ] + ); + /** * Pagination */ - const defaultRowsPerPage = useMemo( - () => getDefaultRowsPerPage(services.uiSettings), - [services.uiSettings] - ); const currentPageSize = typeof rowsPerPageState === 'number' && rowsPerPageState > 0 ? rowsPerPageState - : defaultRowsPerPage; + : DEFAULT_ROWS_PER_PAGE; const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: currentPageSize, @@ -371,10 +449,17 @@ export const DiscoverGrid = ({ onChangePage, pageIndex: pagination.pageIndex > pageCount - 1 ? 0 : pagination.pageIndex, pageSize: pagination.pageSize, - pageSizeOptions: getRowsPerPageOptions(pagination.pageSize), + pageSizeOptions: rowsPerPageOptions ?? getRowsPerPageOptions(pagination.pageSize), } : undefined; - }, [pagination, pageCount, isPaginationEnabled, onUpdateRowsPerPage]); + }, [ + isPaginationEnabled, + pagination.pageIndex, + pagination.pageSize, + pageCount, + rowsPerPageOptions, + onUpdateRowsPerPage, + ]); useEffect(() => { setPagination((paginationData) => @@ -403,8 +488,6 @@ export const DiscoverGrid = ({ [onSort, isSortEnabled, isPlainRecord, setInmemorySortingColumns] ); - const showMultiFields = services.uiSettings.get(SHOW_MULTIFIELDS); - const shouldShowFieldHandler = useMemo(() => { const dataViewFields = dataView.fields.getAll().map((fld) => fld.name); return getShouldShowFieldHandler(dataViewFields, dataView, showMultiFields); @@ -420,10 +503,20 @@ export const DiscoverGrid = ({ displayedRows, useNewFieldsApi, shouldShowFieldHandler, - services.uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), - () => dataGridRef.current?.closeCellPopover() + () => dataGridRef.current?.closeCellPopover(), + services.fieldFormats, + maxDocFieldsDisplayed, + externalCustomRenderers ), - [dataView, displayedRows, useNewFieldsApi, shouldShowFieldHandler, services.uiSettings] + [ + dataView, + displayedRows, + useNewFieldsApi, + shouldShowFieldHandler, + maxDocFieldsDisplayed, + services.fieldFormats, + externalCustomRenderers, + ] ); /** @@ -459,7 +552,7 @@ export const DiscoverGrid = ({ ); const visibleColumns = useMemo( - () => getVisibleColumns(displayedColumns, dataView, showTimeCol) as string[], + () => getVisibleColumns(displayedColumns, dataView, showTimeCol), [dataView, displayedColumns, showTimeCol] ); @@ -511,6 +604,7 @@ export const DiscoverGrid = ({ valueToStringConverter, onFilter, editField, + visibleCellActions, }), [ onFilter, @@ -527,6 +621,7 @@ export const DiscoverGrid = ({ dataViewFieldEditor, valueToStringConverter, editField, + visibleCellActions, ] ); @@ -554,26 +649,33 @@ export const DiscoverGrid = ({ return { columns: sortingColumns, onSort: () => {} }; }, [isSortEnabled, sortingColumns, isPlainRecord, inmemorySortingColumns, onTableSort]); - const canSetExpandedDoc = Boolean(setExpandedDoc && DocumentView); + const canSetExpandedDoc = Boolean(setExpandedDoc && !!renderDocumentView); - const lead = useMemo( - () => - getLeadControlColumns(canSetExpandedDoc).filter(({ id }) => controlColumnIds.includes(id)), - [controlColumnIds, canSetExpandedDoc] - ); + const leadingControlColumns = useMemo(() => { + const internalControlColumns = getLeadControlColumns(canSetExpandedDoc).filter(({ id }) => + controlColumnIds.includes(id) + ); + return externalControlColumns + ? [...internalControlColumns, ...externalControlColumns] + : internalControlColumns; + }, [canSetExpandedDoc, externalControlColumns, controlColumnIds]); const additionalControls = useMemo( - () => - usedSelectedDocs.length ? ( - - ) : null, - [usedSelectedDocs, isFilterActive, rows, setIsFilterActive] + () => ( + <> + {usedSelectedDocs.length ? ( + + ) : null} + {externalAdditionalControls} + + ), + [usedSelectedDocs, isFilterActive, rows, externalAdditionalControls] ); const showDisplaySelector = useMemo( @@ -588,8 +690,10 @@ export const DiscoverGrid = ({ ); const inMemory = useMemo(() => { - return isPlainRecord ? ({ level: 'sorting' } as EuiDataGridInMemory) : undefined; - }, [isPlainRecord]); + return isPlainRecord && columns.length + ? ({ level: 'sorting' } as EuiDataGridInMemory) + : undefined; + }, [columns.length, isPlainRecord]); const toolbarVisibility = useMemo( () => @@ -615,17 +719,20 @@ export const DiscoverGrid = ({ const rowHeightsOptions = useRowHeightsOptions({ rowHeightState, onUpdateRowHeight, + storage, + configRowHeight, + consumer, }); const isRenderComplete = loadingState !== DataLoadingState.loading; if (!rowCount && loadingState === DataLoadingState.loading) { return ( -
+
- +
); @@ -644,32 +751,18 @@ export const DiscoverGrid = ({ - +
); } return ( - { - setSelectedDocs(newSelectedDocs); - if (isFilterActive && newSelectedDocs.length === 0) { - setIsFilterActive(false); - } - }, - valueToStringConverter, - }} - > - + +
{loadingState !== DataLoadingState.loading && isPaginationEnabled && ( // we hide the footer for Surrounding Documents page - )} {searchTitle && ( @@ -716,13 +813,13 @@ export const DiscoverGrid = ({

{searchDescription ? ( ) : ( @@ -730,24 +827,10 @@ export const DiscoverGrid = ({

)} - {setExpandedDoc && expandedDoc && DocumentView && ( - setExpandedDoc(undefined)} - setExpandedDoc={setExpandedDoc} - query={query} - /> - )} + {canSetExpandedDoc && + expandedDoc && + renderDocumentView!(expandedDoc, displayedRows, displayedColumns)}
-
+ ); }; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_columns.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx similarity index 86% rename from src/plugins/discover/public/components/discover_grid/discover_grid_columns.test.tsx rename to packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx index cea7f6c3505c9..01246603643fd 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_columns.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_columns.test.tsx @@ -7,10 +7,10 @@ */ import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { getEuiGridColumns, getVisibleColumns } from './discover_grid_columns'; +import { getEuiGridColumns, getVisibleColumns } from './data_table_columns'; import { dataViewWithTimefieldMock } from '../../__mocks__/data_view_with_timefield'; -import { discoverGridContextMock } from '../../__mocks__/grid_context'; -import { discoverServiceMock } from '../../__mocks__/services'; +import { dataTableContextMock } from '../../__mocks__/table_context'; +import { servicesMock } from '../../__mocks__/services'; const columns = ['extension', 'message']; const columnsWithTimeCol = getVisibleColumns( @@ -19,7 +19,7 @@ const columnsWithTimeCol = getVisibleColumns( true ) as string[]; -describe('Discover grid columns', function () { +describe('Data table columns', function () { describe('getEuiGridColumns', () => { it('returns eui grid columns showing default columns', async () => { const actual = getEuiGridColumns({ @@ -29,14 +29,14 @@ describe('Discover grid columns', function () { defaultColumns: true, isSortEnabled: true, isPlainRecord: false, - valueToStringConverter: discoverGridContextMock.valueToStringConverter, + valueToStringConverter: dataTableContextMock.valueToStringConverter, rowsCount: 100, services: { - uiSettings: discoverServiceMock.uiSettings, - toastNotifications: discoverServiceMock.toastNotifications, + uiSettings: servicesMock.uiSettings, + toastNotifications: servicesMock.toastNotifications, }, hasEditDataViewPermission: () => - discoverServiceMock.dataViewFieldEditor.userPermissions.editIndexPattern(), + servicesMock.dataViewFieldEditor.userPermissions.editIndexPattern(), onFilter: () => {}, }); expect(actual).toMatchInlineSnapshot(` @@ -52,7 +52,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -66,7 +66,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -86,6 +86,7 @@ describe('Discover grid columns', function () { "id": "extension", "isSortable": false, "schema": "string", + "visibleCellActions": undefined, }, Object { "actions": Object { @@ -98,7 +99,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -112,7 +113,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -130,6 +131,7 @@ describe('Discover grid columns', function () { "id": "message", "isSortable": false, "schema": "string", + "visibleCellActions": undefined, }, ] `); @@ -143,14 +145,14 @@ describe('Discover grid columns', function () { defaultColumns: false, isSortEnabled: true, isPlainRecord: false, - valueToStringConverter: discoverGridContextMock.valueToStringConverter, + valueToStringConverter: dataTableContextMock.valueToStringConverter, rowsCount: 100, services: { - uiSettings: discoverServiceMock.uiSettings, - toastNotifications: discoverServiceMock.toastNotifications, + uiSettings: servicesMock.uiSettings, + toastNotifications: servicesMock.toastNotifications, }, hasEditDataViewPermission: () => - discoverServiceMock.dataViewFieldEditor.userPermissions.editIndexPattern(), + servicesMock.dataViewFieldEditor.userPermissions.editIndexPattern(), onFilter: () => {}, }); expect(actual).toMatchInlineSnapshot(` @@ -166,7 +168,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -180,7 +182,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -219,6 +221,7 @@ describe('Discover grid columns', function () { "initialWidth": 210, "isSortable": true, "schema": "datetime", + "visibleCellActions": undefined, }, Object { "actions": Object { @@ -231,7 +234,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -245,7 +248,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -268,6 +271,7 @@ describe('Discover grid columns', function () { "id": "extension", "isSortable": false, "schema": "string", + "visibleCellActions": undefined, }, Object { "actions": Object { @@ -280,7 +284,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -294,7 +298,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -315,6 +319,7 @@ describe('Discover grid columns', function () { "id": "message", "isSortable": false, "schema": "string", + "visibleCellActions": undefined, }, ] `); @@ -328,14 +333,14 @@ describe('Discover grid columns', function () { defaultColumns: false, isSortEnabled: true, isPlainRecord: true, - valueToStringConverter: discoverGridContextMock.valueToStringConverter, + valueToStringConverter: dataTableContextMock.valueToStringConverter, rowsCount: 100, services: { - uiSettings: discoverServiceMock.uiSettings, - toastNotifications: discoverServiceMock.toastNotifications, + uiSettings: servicesMock.uiSettings, + toastNotifications: servicesMock.toastNotifications, }, hasEditDataViewPermission: () => - discoverServiceMock.dataViewFieldEditor.userPermissions.editIndexPattern(), + servicesMock.dataViewFieldEditor.userPermissions.editIndexPattern(), onFilter: () => {}, }); expect(actual).toMatchInlineSnapshot(` @@ -351,7 +356,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -365,7 +370,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -404,6 +409,7 @@ describe('Discover grid columns', function () { "initialWidth": 210, "isSortable": true, "schema": "datetime", + "visibleCellActions": undefined, }, Object { "actions": Object { @@ -416,7 +422,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -430,7 +436,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -453,6 +459,7 @@ describe('Discover grid columns', function () { "id": "extension", "isSortable": true, "schema": "string", + "visibleCellActions": undefined, }, Object { "actions": Object { @@ -465,7 +472,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -479,7 +486,7 @@ describe('Discover grid columns', function () { "iconType": "copyClipboard", "label": , "onClick": [Function], @@ -500,6 +507,7 @@ describe('Discover grid columns', function () { "id": "message", "isSortable": true, "schema": "string", + "visibleCellActions": undefined, }, ] `); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_columns.tsx b/packages/kbn-unified-data-table/src/components/data_table_columns.tsx similarity index 82% rename from src/plugins/discover/public/components/discover_grid/discover_grid_columns.tsx rename to packages/kbn-unified-data-table/src/components/data_table_columns.tsx index 8effacbf9427f..4b66f2a2bd6cf 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_columns.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_columns.tsx @@ -17,14 +17,14 @@ import { } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/public'; import { ToastsStart, IUiSettingsClient } from '@kbn/core/public'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { ExpandButton } from './discover_grid_expand_button'; -import { DiscoverGridSettings } from './types'; -import type { ValueToStringConverter } from '../../types'; -import { buildCellActions } from './discover_grid_cell_actions'; -import { getSchemaByKbnType } from './discover_grid_schema'; -import { SelectButton } from './discover_grid_document_selection'; -import { defaultTimeColumnWidth } from './constants'; +import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { ExpandButton } from './data_table_expand_button'; +import { UnifiedDataTableSettings } from '../types'; +import type { ValueToStringConverter } from '../types'; +import { buildCellActions } from './default_cell_actions'; +import { getSchemaByKbnType } from './data_table_schema'; +import { SelectButton } from './data_table_document_selection'; +import { defaultTimeColumnWidth } from '../constants'; import { buildCopyColumnNameButton, buildCopyColumnValuesButton } from './build_copy_column_button'; import { buildEditFieldButton } from './build_edit_field_button'; @@ -34,7 +34,7 @@ const openDetails = { headerCellRender: () => ( - {i18n.translate('discover.controlColumnHeader', { + {i18n.translate('unifiedDataTable.controlColumnHeader', { defaultMessage: 'Control column', })} @@ -50,7 +50,7 @@ const select = { headerCellRender: () => ( - {i18n.translate('discover.selectColumnHeader', { + {i18n.translate('unifiedDataTable.selectColumnHeader', { defaultMessage: 'Select column', })} @@ -79,6 +79,7 @@ function buildEuiGridColumn({ onFilter, editField, columnCellActions, + visibleCellActions, }: { columnName: string; columnWidth: number | undefined; @@ -93,6 +94,7 @@ function buildEuiGridColumn({ onFilter?: DocViewFilterFn; editField?: (fieldName: string) => void; columnCellActions?: EuiDataGridColumnCellAction[]; + visibleCellActions?: number; }) { const dataViewField = dataView.getFieldByName(columnName); const editFieldButton = @@ -101,16 +103,19 @@ function buildEuiGridColumn({ buildEditFieldButton({ hasEditDataViewPermission, dataView, field: dataViewField, editField }); const columnDisplayName = columnName === '_source' - ? i18n.translate('discover.grid.documentHeader', { + ? i18n.translate('unifiedDataTable.grid.documentHeader', { defaultMessage: 'Document', }) : dataViewField?.displayName || columnName; let cellActions: EuiDataGridColumnCellAction[]; + if (columnCellActions?.length) { cellActions = columnCellActions; } else { - cellActions = dataViewField ? buildCellActions(dataViewField, onFilter) : []; + cellActions = dataViewField + ? buildCellActions(dataViewField, toastNotifications, valueToStringConverter, onFilter) + : []; } const column: EuiDataGridColumn = { @@ -123,7 +128,7 @@ function buildEuiGridColumn({ defaultColumns || columnName === dataView.timeFieldName ? false : { - label: i18n.translate('discover.removeColumnLabel', { + label: i18n.translate('unifiedDataTable.removeColumnLabel', { defaultMessage: 'Remove column', }), iconType: 'cross', @@ -150,23 +155,21 @@ function buildEuiGridColumn({ ], }, cellActions, + visibleCellActions, }; if (column.id === dataView.timeFieldName) { const timeFieldName = dataViewField?.customLabel ?? dataView.timeFieldName; const primaryTimeAriaLabel = i18n.translate( - 'discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel', + 'unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel', { defaultMessage: '{timeFieldName} - this field represents the time that events occurred.', values: { timeFieldName }, } ); - const primaryTimeTooltip = i18n.translate( - 'discover.docTable.tableHeader.timeFieldIconTooltip', - { - defaultMessage: 'This field represents the time that events occurred.', - } - ); + const primaryTimeTooltip = i18n.translate('unifiedDataTable.tableHeader.timeFieldIconTooltip', { + defaultMessage: 'This field represents the time that events occurred.', + }); column.display = (
@@ -199,11 +202,12 @@ export function getEuiGridColumns({ valueToStringConverter, onFilter, editField, + visibleCellActions, }: { columns: string[]; columnsCellActions?: EuiDataGridColumnCellAction[][]; rowsCount: number; - settings: DiscoverGridSettings | undefined; + settings: UnifiedDataTableSettings | undefined; dataView: DataView; defaultColumns: boolean; isSortEnabled: boolean; @@ -216,6 +220,7 @@ export function getEuiGridColumns({ valueToStringConverter: ValueToStringConverter; onFilter: DocViewFilterFn; editField?: (fieldName: string) => void; + visibleCellActions?: number; }) { const getColWidth = (column: string) => settings?.columns?.[column]?.width ?? 0; @@ -234,6 +239,7 @@ export function getEuiGridColumns({ rowsCount, onFilter, editField, + visibleCellActions, }) ); } diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx similarity index 79% rename from src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx rename to packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx index 7fda5b74ce550..ca0d422948416 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_document_selection.test.tsx @@ -8,9 +8,9 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { findTestSubject } from '@elastic/eui/lib/test'; -import { DiscoverGridDocumentToolbarBtn, SelectButton } from './discover_grid_document_selection'; -import { discoverGridContextMock } from '../../__mocks__/grid_context'; -import { DiscoverGridContext } from './discover_grid_context'; +import { DataTableDocumentToolbarBtn, SelectButton } from './data_table_document_selection'; +import { dataTableContextMock } from '../../__mocks__/table_context'; +import { UnifiedDataTableContext } from '../table_context'; import { getDocId } from '@kbn/discover-utils'; describe('document selection', () => { @@ -35,11 +35,11 @@ describe('document selection', () => { describe('SelectButton', () => { test('is not checked', () => { const contextMock = { - ...discoverGridContextMock, + ...dataTableContextMock, }; const component = mountWithIntl( - + { isDetails={false} isExpandable={false} /> - + ); const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::'); @@ -58,12 +58,12 @@ describe('document selection', () => { test('is checked', () => { const contextMock = { - ...discoverGridContextMock, + ...dataTableContextMock, selectedDocs: ['i::1::'], }; const component = mountWithIntl( - + { isDetails={false} isExpandable={false} /> - + ); const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::'); @@ -82,11 +82,11 @@ describe('document selection', () => { test('adding a selection', () => { const contextMock = { - ...discoverGridContextMock, + ...dataTableContextMock, }; const component = mountWithIntl( - + { isDetails={false} isExpandable={false} /> - + ); const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::'); @@ -105,12 +105,12 @@ describe('document selection', () => { }); test('removing a selection', () => { const contextMock = { - ...discoverGridContextMock, + ...dataTableContextMock, selectedDocs: ['i::1::'], }; const component = mountWithIntl( - + { isDetails={false} isExpandable={false} /> - + ); const checkBox = findTestSubject(component, 'dscGridSelectDoc-i::1::'); @@ -128,16 +128,16 @@ describe('document selection', () => { expect(contextMock.setSelectedDocs).toHaveBeenCalledWith([]); }); }); - describe('DiscoverGridDocumentToolbarBtn', () => { + describe('DataTableDocumentToolbarBtn', () => { test('it renders a button clickable button', () => { const props = { isFilterActive: false, - rows: discoverGridContextMock.rows, + rows: dataTableContextMock.rows, selectedDocs: ['i::1::'], setIsFilterActive: jest.fn(), setSelectedDocs: jest.fn(), }; - const component = mountWithIntl(); + const component = mountWithIntl(); const button = findTestSubject(component, 'dscGridSelectionBtn'); expect(button.length).toBe(1); }); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx b/packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx similarity index 89% rename from src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx rename to packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx index f14ec323f8ca2..213e24790e840 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_document_selection.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_document_selection.tsx @@ -20,15 +20,15 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { euiDarkVars as themeDark, euiLightVars as themeLight } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { DiscoverGridContext } from './discover_grid_context'; +import { UnifiedDataTableContext } from '../table_context'; export const SelectButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueElementProps) => { const { selectedDocs, expanded, rows, isDarkMode, setSelectedDocs } = - useContext(DiscoverGridContext); + useContext(UnifiedDataTableContext); const doc = useMemo(() => rows[rowIndex], [rows, rowIndex]); const checked = useMemo(() => selectedDocs.includes(doc.id), [selectedDocs, doc.id]); - const toggleDocumentSelectionLabel = i18n.translate('discover.grid.selectDoc', { + const toggleDocumentSelectionLabel = i18n.translate('unifiedDataTable.grid.selectDoc', { defaultMessage: `Select document '{rowNumber}'`, values: { rowNumber: rowIndex + 1 }, }); @@ -63,7 +63,7 @@ export const SelectButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle ); }; -export function DiscoverGridDocumentToolbarBtn({ +export function DataTableDocumentToolbarBtn({ isFilterActive, rows, selectedDocs, @@ -90,7 +90,10 @@ export function DiscoverGridDocumentToolbarBtn({ setIsFilterActive(false); }} > - + ) : ( @@ -122,7 +125,7 @@ export function DiscoverGridDocumentToolbarBtn({ {(copy) => ( @@ -138,7 +141,7 @@ export function DiscoverGridDocumentToolbarBtn({ setIsFilterActive(false); }} > - + , ]; }, [ @@ -176,7 +179,7 @@ export function DiscoverGridDocumentToolbarBtn({ })} > diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.test.tsx b/packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx similarity index 70% rename from src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.test.tsx rename to packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx index e95853b99b7b7..56d6d3ae3ce0e 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_expand_button.test.tsx @@ -9,18 +9,18 @@ import React from 'react'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { findTestSubject } from '@elastic/eui/lib/test'; -import { ExpandButton } from './discover_grid_expand_button'; -import { DiscoverGridContext } from './discover_grid_context'; -import { discoverGridContextMock } from '../../__mocks__/grid_context'; +import { ExpandButton } from './data_table_expand_button'; +import { UnifiedDataTableContext } from '../table_context'; +import { dataTableContextMock } from '../../__mocks__/table_context'; -describe('Discover grid view button ', function () { +describe('Data table view button ', function () { it('when no document is expanded, setExpanded is called with current document', async () => { const contextMock = { - ...discoverGridContextMock, + ...dataTableContextMock, }; const component = mountWithIntl( - + - + ); const button = findTestSubject(component, 'docTableExpandToggleColumn'); await button.simulate('click'); - expect(contextMock.setExpanded).toHaveBeenCalledWith(discoverGridContextMock.rows[0]); + expect(contextMock.setExpanded).toHaveBeenCalledWith(dataTableContextMock.rows[0]); }); it('when the current document is expanded, setExpanded is called with undefined', async () => { const contextMock = { - ...discoverGridContextMock, - expanded: discoverGridContextMock.rows[0], + ...dataTableContextMock, + expanded: dataTableContextMock.rows[0], }; const component = mountWithIntl( - + - + ); const button = findTestSubject(component, 'docTableExpandToggleColumn'); await button.simulate('click'); @@ -61,12 +61,12 @@ describe('Discover grid view button ', function () { }); it('when another document is expanded, setExpanded is called with the current document', async () => { const contextMock = { - ...discoverGridContextMock, - expanded: discoverGridContextMock.rows[0], + ...dataTableContextMock, + expanded: dataTableContextMock.rows[0], }; const component = mountWithIntl( - + - + ); const button = findTestSubject(component, 'docTableExpandToggleColumn'); await button.simulate('click'); - expect(contextMock.setExpanded).toHaveBeenCalledWith(discoverGridContextMock.rows[1]); + expect(contextMock.setExpanded).toHaveBeenCalledWith(dataTableContextMock.rows[1]); }); }); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx b/packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx similarity index 86% rename from src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx rename to packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx index 1a127f3639432..108ffaa4ec5fe 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_expand_button.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_expand_button.tsx @@ -10,8 +10,7 @@ import React, { useContext, useEffect, useRef, useState } from 'react'; import { EuiButtonIcon, EuiDataGridCellValueElementProps, EuiToolTip } from '@elastic/eui'; import { euiLightVars as themeLight, euiDarkVars as themeDark } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; -import { DiscoverGridContext } from './discover_grid_context'; -import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../discover_tour'; +import { UnifiedDataTableContext } from '../table_context'; /** * Button to expand a given row @@ -19,9 +18,11 @@ import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../discover_tour'; export const ExpandButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueElementProps) => { const toolTipRef = useRef(null); const [pressed, setPressed] = useState(false); - const { expanded, setExpanded, rows, isDarkMode } = useContext(DiscoverGridContext); + const { expanded, setExpanded, rows, isDarkMode, componentsTourSteps } = + useContext(UnifiedDataTableContext); const current = rows[rowIndex]; + const tourStep = componentsTourSteps ? componentsTourSteps.expandButton : undefined; useEffect(() => { if (current.isAnchor) { setCellProps({ @@ -39,7 +40,7 @@ export const ExpandButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle }, [expanded, current, setCellProps, isDarkMode]); const isCurrentRowExpanded = current === expanded; - const buttonLabel = i18n.translate('discover.grid.viewDoc', { + const buttonLabel = i18n.translate('unifiedDataTable.grid.viewDoc', { defaultMessage: 'Toggle dialog with details', }); @@ -63,7 +64,7 @@ export const ExpandButton = ({ rowIndex, setCellProps }: EuiDataGridCellValueEle return ( { const component = mountWithIntl( - - + ); @@ -31,32 +33,32 @@ describe('DiscoverGridFooter', function () { it('should not render anything yet when all rows shown', async () => { const component = mountWithIntl( - - - + ); expect(component.isEmptyRender()).toBe(true); }); it('should render a message for the last page', async () => { const component = mountWithIntl( - - - + ); - expect(findTestSubject(component, 'discoverTableFooter').text()).toBe( + expect(findTestSubject(component, 'unifiedDataTableFooter').text()).toBe( 'Search results are limited to 500 documents. Add more search terms to narrow your search.' ); expect(findTestSubject(component, 'dscGridSampleSizeFetchMoreLink').exists()).toBe(false); @@ -66,19 +68,19 @@ describe('DiscoverGridFooter', function () { const mockLoadMore = jest.fn(); const component = mountWithIntl( - - - + ); - expect(findTestSubject(component, 'discoverTableFooter').text()).toBe( + expect(findTestSubject(component, 'unifiedDataTableFooter').text()).toBe( 'Search results are limited to 500 documents.Load more' ); @@ -94,19 +96,19 @@ describe('DiscoverGridFooter', function () { const mockLoadMore = jest.fn(); const component = mountWithIntl( - - - + ); - expect(findTestSubject(component, 'discoverTableFooter').text()).toBe( + expect(findTestSubject(component, 'unifiedDataTableFooter').text()).toBe( 'Search results are limited to 500 documents.Load more' ); @@ -121,17 +123,17 @@ describe('DiscoverGridFooter', function () { it('should render a message when max total limit is reached', async () => { const component = mountWithIntl( - - - + ); - expect(findTestSubject(component, 'discoverTableFooter').text()).toBe( + expect(findTestSubject(component, 'unifiedDataTableFooter').text()).toBe( 'Search results are limited to 10000 documents. Add more search terms to narrow your search.' ); }); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_footer.tsx b/packages/kbn-unified-data-table/src/components/data_table_footer.tsx similarity index 75% rename from src/plugins/discover/public/components/discover_grid/discover_grid_footer.tsx rename to packages/kbn-unified-data-table/src/components/data_table_footer.tsx index 540c7102bd424..21819a023afed 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_footer.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table_footer.tsx @@ -12,10 +12,11 @@ import { EuiButtonEmpty, EuiToolTip, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; -import { MAX_LOADED_GRID_ROWS } from '../../../common/constants'; -import { useDiscoverServices } from '../../hooks/use_discover_services'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { MAX_LOADED_GRID_ROWS } from '../constants'; -export interface DiscoverGridFooterProps { +export interface UnifiedDataTableFooterProps { isLoadingMore?: boolean; rowCount: number; sampleSize: number; @@ -23,9 +24,11 @@ export interface DiscoverGridFooterProps { pageCount: number; totalHits?: number; onFetchMoreRecords?: () => void; + data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; } -export const DiscoverGridFooter: React.FC = (props) => { +export const UnifiedDataTableFooter: React.FC = (props) => { const { isLoadingMore, rowCount, @@ -34,8 +37,8 @@ export const DiscoverGridFooter: React.FC = (props) => pageCount, totalHits = 0, onFetchMoreRecords, + data, } = props; - const { data } = useDiscoverServices(); const timefilter = data.query.timefilter.timefilter; const [refreshInterval, setRefreshInterval] = useState(timefilter.getRefreshInterval()); @@ -58,15 +61,15 @@ export const DiscoverGridFooter: React.FC = (props) => return null; } - // allow to fetch more records on Discover page + // allow to fetch more records for UnifiedDataTable if (onFetchMoreRecords && typeof isLoadingMore === 'boolean') { if (rowCount <= MAX_LOADED_GRID_ROWS - sampleSize) { return ( - + = (props) => `} > - + ); } - return ; + return ; } if (rowCount < totalHits) { // show only a message for embeddable - return ; + return ; } return null; }; -interface DiscoverGridFooterContainerProps extends DiscoverGridFooterProps { +interface UnifiedDataTableFooterContainerProps extends UnifiedDataTableFooterProps { hasButton: boolean; } -const DiscoverGridFooterContainer: React.FC = ({ +const UnifiedDataTableFooterContainer: React.FC = ({ hasButton, rowCount, children, + fieldFormats, }) => { const { euiTheme } = useEuiTheme(); - const { fieldFormats } = useDiscoverServices(); const formattedRowCount = fieldFormats .getDefaultInstance(KBN_FIELD_TYPES.NUMBER, [ES_FIELD_TYPES.INTEGER]) @@ -121,7 +124,7 @@ const DiscoverGridFooterContainer: React.FC = return (

= {hasButton ? ( = /> ) : ( true); +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + return { + ...original, + copyToClipboard: (value: string) => mockCopyToClipboard(value), + }; +}); + +import React from 'react'; +import { mountWithIntl } from '@kbn/test-jest-helpers'; +import { findTestSubject } from '@elastic/eui/lib/test'; +import { + FilterInBtn, + FilterOutBtn, + buildCellActions, + buildCopyValueButton, +} from './default_cell_actions'; +import { servicesMock } from '../../__mocks__/services'; +import { UnifiedDataTableContext } from '../table_context'; +import { EuiButton, EuiDataGridColumnCellActionProps } from '@elastic/eui'; +import { dataTableContextMock } from '../../__mocks__/table_context'; +import { DataViewField } from '@kbn/data-views-plugin/public'; + +describe('Default cell actions ', function () { + const CopyBtn = buildCopyValueButton( + { + Component: () => <>, + colIndex: 0, + columnId: 'extension', + } as unknown as EuiDataGridColumnCellActionProps, + servicesMock.toastNotifications, + dataTableContextMock.valueToStringConverter + ); + + it('should not show cell actions for unfilterable fields', async () => { + const cellActions = buildCellActions( + { name: 'foo', filterable: false } as DataViewField, + servicesMock.toastNotifications, + dataTableContextMock.valueToStringConverter + ); + expect(cellActions.length).toEqual(1); + expect( + cellActions[0]({ + Component: () => <>, + colIndex: 1, + columnId: 'extension', + } as unknown as EuiDataGridColumnCellActionProps).props['aria-label'] + ).toEqual(CopyBtn.props['aria-label']); + }); + + it('should show filter actions for filterable fields', async () => { + const cellActions = buildCellActions( + { name: 'foo', filterable: true } as DataViewField, + servicesMock.toastNotifications, + dataTableContextMock.valueToStringConverter, + jest.fn() + ); + expect(cellActions).toContain(FilterInBtn); + expect(cellActions).toContain(FilterOutBtn); + }); + + it('should show Copy action for _source field', async () => { + const cellActions = buildCellActions( + { name: '_source', type: '_source', filterable: false } as DataViewField, + servicesMock.toastNotifications, + dataTableContextMock.valueToStringConverter + ); + expect( + cellActions[0]({ + Component: () => <>, + colIndex: 1, + columnId: 'extension', + } as unknown as EuiDataGridColumnCellActionProps).props['aria-label'] + ).toEqual(CopyBtn.props['aria-label']); + }); + + it('triggers filter function when FilterInBtn is clicked', async () => { + const component = mountWithIntl( + + } + rowIndex={1} + colIndex={1} + columnId="extension" + isExpanded={false} + /> + + ); + const button = findTestSubject(component, 'filterForButton'); + await button.simulate('click'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + dataTableContextMock.dataView.fields.getByName('extension'), + 'jpg', + '+' + ); + }); + it('triggers filter function when FilterInBtn is clicked for a non-provided value', async () => { + const component = mountWithIntl( + + } + rowIndex={0} + colIndex={1} + columnId="extension" + isExpanded={false} + /> + + ); + const button = findTestSubject(component, 'filterForButton'); + await button.simulate('click'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + dataTableContextMock.dataView.fields.getByName('extension'), + undefined, + '+' + ); + }); + it('triggers filter function when FilterInBtn is clicked for an empty string value', async () => { + const component = mountWithIntl( + + } + rowIndex={4} + colIndex={1} + columnId="message" + isExpanded={false} + /> + + ); + const button = findTestSubject(component, 'filterForButton'); + await button.simulate('click'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + dataTableContextMock.dataView.fields.getByName('message'), + '', + '+' + ); + }); + it('triggers filter function when FilterOutBtn is clicked', async () => { + const component = mountWithIntl( + + } + rowIndex={1} + colIndex={1} + columnId="extension" + isExpanded={false} + /> + + ); + const button = findTestSubject(component, 'filterOutButton'); + await button.simulate('click'); + expect(dataTableContextMock.onFilter).toHaveBeenCalledWith( + dataTableContextMock.dataView.fields.getByName('extension'), + 'jpg', + '-' + ); + }); + it('triggers clipboard copy when CopyBtn is clicked', async () => { + const component = mountWithIntl( + + {buildCopyValueButton( + { + Component: (props: any) => , + colIndex: 1, + rowIndex: 1, + columnId: 'extension', + } as unknown as EuiDataGridColumnCellActionProps, + servicesMock.toastNotifications, + dataTableContextMock.valueToStringConverter + )} + + ); + const button = findTestSubject(component, 'copyClipboardButton'); + await button.simulate('click'); + expect(mockCopyToClipboard).toHaveBeenCalledWith('jpg'); + }); +}); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx b/packages/kbn-unified-data-table/src/components/default_cell_actions.tsx similarity index 60% rename from src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx rename to packages/kbn-unified-data-table/src/components/default_cell_actions.tsx index 32779230e1b7f..6005d75ea6632 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.tsx +++ b/packages/kbn-unified-data-table/src/components/default_cell_actions.tsx @@ -9,14 +9,15 @@ import React, { useContext } from 'react'; import { EuiDataGridColumnCellActionProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { DataViewField } from '@kbn/data-views-plugin/public'; +import type { DataViewField } from '@kbn/data-views-plugin/public'; +import { ToastsStart } from '@kbn/core/public'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { DiscoverGridContext, GridContext } from './discover_grid_context'; -import { useDiscoverServices } from '../../hooks/use_discover_services'; -import { copyValueToClipboard } from '../../utils/copy_value_to_clipboard'; +import { UnifiedDataTableContext, DataTableContext } from '../table_context'; +import { copyValueToClipboard } from '../utils/copy_value_to_clipboard'; +import { ValueToStringConverter } from '../types'; function onFilterCell( - context: GridContext, + context: DataTableContext, rowIndex: EuiDataGridColumnCellActionProps['rowIndex'], columnId: EuiDataGridColumnCellActionProps['columnId'], mode: '+' | '-' @@ -35,8 +36,8 @@ export const FilterInBtn = ({ rowIndex, columnId, }: EuiDataGridColumnCellActionProps) => { - const context = useContext(DiscoverGridContext); - const buttonTitle = i18n.translate('discover.grid.filterForAria', { + const context = useContext(UnifiedDataTableContext); + const buttonTitle = i18n.translate('unifiedDataTable.grid.filterForAria', { defaultMessage: 'Filter for this {value}', values: { value: columnId }, }); @@ -51,7 +52,7 @@ export const FilterInBtn = ({ title={buttonTitle} data-test-subj="filterForButton" > - {i18n.translate('discover.grid.filterFor', { + {i18n.translate('unifiedDataTable.grid.filterFor', { defaultMessage: 'Filter for', })} @@ -63,8 +64,8 @@ export const FilterOutBtn = ({ rowIndex, columnId, }: EuiDataGridColumnCellActionProps) => { - const context = useContext(DiscoverGridContext); - const buttonTitle = i18n.translate('discover.grid.filterOutAria', { + const context = useContext(UnifiedDataTableContext); + const buttonTitle = i18n.translate('unifiedDataTable.grid.filterOutAria', { defaultMessage: 'Filter out this {value}', values: { value: columnId }, }); @@ -79,18 +80,19 @@ export const FilterOutBtn = ({ title={buttonTitle} data-test-subj="filterOutButton" > - {i18n.translate('discover.grid.filterOut', { + {i18n.translate('unifiedDataTable.grid.filterOut', { defaultMessage: 'Filter out', })} ); }; -export const CopyBtn = ({ Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps) => { - const { valueToStringConverter } = useContext(DiscoverGridContext); - const { toastNotifications } = useDiscoverServices(); - - const buttonTitle = i18n.translate('discover.grid.copyClipboardButtonTitle', { +export function buildCopyValueButton( + { Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps, + toastNotifications: ToastsStart, + valueToStringConverter: ValueToStringConverter +) { + const buttonTitle = i18n.translate('unifiedDataTable.grid.copyClipboardButtonTitle', { defaultMessage: 'Copy value of {column}', values: { column: columnId }, }); @@ -101,8 +103,8 @@ export const CopyBtn = ({ Component, rowIndex, columnId }: EuiDataGridColumnCell copyValueToClipboard({ rowIndex, columnId, - toastNotifications, valueToStringConverter, + toastNotifications, }); }} iconType="copyClipboard" @@ -110,13 +112,26 @@ export const CopyBtn = ({ Component, rowIndex, columnId }: EuiDataGridColumnCell title={buttonTitle} data-test-subj="copyClipboardButton" > - {i18n.translate('discover.grid.copyCellValueButton', { + {i18n.translate('unifiedDataTable.grid.copyCellValueButton', { defaultMessage: 'Copy value', })} ); -}; +} -export function buildCellActions(field: DataViewField, onFilter?: DocViewFilterFn) { - return [...(onFilter && field.filterable ? [FilterInBtn, FilterOutBtn] : []), CopyBtn]; +export function buildCellActions( + field: DataViewField, + toastNotifications: ToastsStart, + valueToStringConverter: ValueToStringConverter, + onFilter?: DocViewFilterFn +) { + return [ + ...(onFilter && field.filterable ? [FilterInBtn, FilterOutBtn] : []), + ({ Component, rowIndex, columnId }: EuiDataGridColumnCellActionProps) => + buildCopyValueButton( + { Component, rowIndex, columnId } as EuiDataGridColumnCellActionProps, + toastNotifications, + valueToStringConverter + ), + ]; } diff --git a/packages/kbn-unified-data-table/src/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap b/packages/kbn-unified-data-table/src/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap new file mode 100644 index 0000000000000..7af546298e0d8 --- /dev/null +++ b/packages/kbn-unified-data-table/src/components/json_code_editor/__snapshots__/json_code_editor.test.tsx.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`returns the \`JsonCodeEditor\` component 1`] = ` + +`; diff --git a/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.scss b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.scss new file mode 100644 index 0000000000000..a07f7ccac408d --- /dev/null +++ b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.scss @@ -0,0 +1,3 @@ +.unifiedDataTableJsonEditor { + width: 100%; +} diff --git a/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.test.tsx b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.test.tsx new file mode 100644 index 0000000000000..e1ec1373f8657 --- /dev/null +++ b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.test.tsx @@ -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 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 { shallow } from 'enzyme'; +import JsonCodeEditor from './json_code_editor'; + +it('returns the `JsonCodeEditor` component', () => { + const value = { + _index: 'test', + _type: 'doc', + _id: 'foo', + _score: 1, + _source: { test: 123 }, + }; + expect(shallow()).toMatchSnapshot(); +}); diff --git a/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.tsx b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.tsx new file mode 100644 index 0000000000000..d08e35eb6d4bf --- /dev/null +++ b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 './json_code_editor.scss'; + +import React from 'react'; +import { JsonCodeEditorCommon } from './json_code_editor_common'; + +export interface JsonCodeEditorProps { + json: Record; + width?: string | number; + height?: string | number; + hasLineNumbers?: boolean; +} + +// Required for usage in React.lazy +// eslint-disable-next-line import/no-default-export +export default function JsonCodeEditor({ + json, + width, + height, + hasLineNumbers, +}: JsonCodeEditorProps) { + const jsonValue = JSON.stringify(json, null, 2); + + return ( + void 0} + hideCopyButton={true} + /> + ); +} diff --git a/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor_common.tsx b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor_common.tsx new file mode 100644 index 0000000000000..079a98c305459 --- /dev/null +++ b/packages/kbn-unified-data-table/src/components/json_code_editor/json_code_editor_common.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 './json_code_editor.scss'; + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { monaco, XJsonLang } from '@kbn/monaco'; +import { EuiButtonEmpty, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { CodeEditor } from '@kbn/code-editor'; +const codeEditorAriaLabel = i18n.translate('unifiedDataTable.json.codeEditorAriaLabel', { + defaultMessage: 'Read only JSON view of an elasticsearch document', +}); +const copyToClipboardLabel = i18n.translate('unifiedDataTable.json.copyToClipboardLabel', { + defaultMessage: 'Copy to clipboard', +}); + +interface JsonCodeEditorCommonProps { + jsonValue: string; + onEditorDidMount: (editor: monaco.editor.IStandaloneCodeEditor) => void; + width?: string | number; + height?: string | number; + hasLineNumbers?: boolean; + hideCopyButton?: boolean; +} + +export const JsonCodeEditorCommon = ({ + jsonValue, + width, + height, + hasLineNumbers, + onEditorDidMount, + hideCopyButton, +}: JsonCodeEditorCommonProps) => { + if (jsonValue === '') { + return null; + } + + const codeEditor = ( + + ); + if (hideCopyButton) { + return codeEditor; + } + return ( + + + +

+ + {(copy) => ( + + {copyToClipboardLabel} + + )} + +
+ + {codeEditor} + + ); +}; + +export const JSONCodeEditorCommonMemoized = React.memo((props: JsonCodeEditorCommonProps) => { + return ; +}); diff --git a/src/plugins/discover/public/components/discover_grid/constants.ts b/packages/kbn-unified-data-table/src/constants.ts similarity index 81% rename from src/plugins/discover/public/components/discover_grid/constants.ts rename to packages/kbn-unified-data-table/src/constants.ts index 8f7c40e33b957..1fb391ddc7f70 100644 --- a/src/plugins/discover/public/components/discover_grid/constants.ts +++ b/packages/kbn-unified-data-table/src/constants.ts @@ -5,11 +5,17 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - import { EuiDataGridStyle } from '@elastic/eui'; -// data types +export const DEFAULT_ROWS_PER_PAGE = 100; +export const MAX_LOADED_GRID_ROWS = 10000; + +export const ROWS_PER_PAGE_OPTIONS = [10, 25, 50, DEFAULT_ROWS_PER_PAGE, 250, 500]; + +export const defaultMonacoEditorWidth = 370; +export const defaultTimeColumnWidth = 210; export const kibanaJSON = 'kibana-json'; + export const GRID_STYLE = { border: 'all', fontSize: 's', @@ -17,12 +23,9 @@ export const GRID_STYLE = { rowHover: 'none', } as EuiDataGridStyle; -export const defaultTimeColumnWidth = 210; export const toolbarVisibility = { showColumnSelector: { allowHide: false, allowReorder: true, }, }; - -export const defaultMonacoEditorWidth = 370; diff --git a/src/plugins/discover/public/hooks/use_data_grid_columns.test.tsx b/packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.test.tsx similarity index 94% rename from src/plugins/discover/public/hooks/use_data_grid_columns.test.tsx rename to packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.test.tsx index 4a1874ec8e940..e0afdab4ff043 100644 --- a/src/plugins/discover/public/hooks/use_data_grid_columns.test.tsx +++ b/packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.test.tsx @@ -9,8 +9,8 @@ import { renderHook } from '@testing-library/react-hooks'; import { useColumns } from './use_data_grid_columns'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { configMock } from '../__mocks__/config'; -import { dataViewsMock } from '../__mocks__/data_views'; +import { configMock } from '../../__mocks__/config'; +import { dataViewsMock } from '../../__mocks__/data_views'; import { Capabilities } from '@kbn/core/types'; describe('useColumns', () => { diff --git a/src/plugins/discover/public/hooks/use_data_grid_columns.ts b/packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.ts similarity index 74% rename from src/plugins/discover/public/hooks/use_data_grid_columns.ts rename to packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.ts index 22fc8e9836888..088f7b0491c69 100644 --- a/src/plugins/discover/public/hooks/use_data_grid_columns.ts +++ b/packages/kbn-unified-data-table/src/hooks/use_data_grid_columns.ts @@ -9,32 +9,30 @@ import { useEffect, useMemo, useState } from 'react'; import type { DataView, DataViewsContract } from '@kbn/data-views-plugin/public'; -import { Capabilities, IUiSettingsClient } from '@kbn/core/public'; +import { Capabilities } from '@kbn/core/public'; import { isEqual } from 'lodash'; -import { DiscoverAppStateContainer } from '../application/main/services/discover_app_state_container'; -import { GetStateReturn as ContextGetStateReturn } from '../application/context/services/context_state'; -import { getStateColumnActions } from '../components/doc_table/actions/columns'; +import { getStateColumnActions } from '../components/actions/columns'; interface UseColumnsProps { capabilities: Capabilities; - config: IUiSettingsClient; dataView: DataView; dataViews: DataViewsContract; useNewFieldsApi: boolean; - setAppState: DiscoverAppStateContainer['update'] | ContextGetStateReturn['setAppState']; + setAppState: (state: { columns: string[]; sort?: string[][] }) => void; columns?: string[]; sort?: string[][]; + defaultOrder?: string; } export const useColumns = ({ capabilities, - config, dataView, dataViews, setAppState, useNewFieldsApi, columns, sort, + defaultOrder = 'desc', }: UseColumnsProps) => { const [usedColumns, setUsedColumns] = useState(getColumns(columns, useNewFieldsApi)); useEffect(() => { @@ -48,15 +46,24 @@ export const useColumns = ({ () => getStateColumnActions({ capabilities, - config, dataView, dataViews, setAppState, useNewFieldsApi, columns: usedColumns, sort, + defaultOrder, }), - [capabilities, config, dataView, dataViews, setAppState, sort, useNewFieldsApi, usedColumns] + [ + capabilities, + dataView, + dataViews, + defaultOrder, + setAppState, + sort, + useNewFieldsApi, + usedColumns, + ] ); return { diff --git a/packages/kbn-unified-data-table/src/hooks/use_row_heights_options.test.tsx b/packages/kbn-unified-data-table/src/hooks/use_row_heights_options.test.tsx new file mode 100644 index 0000000000000..2da08c178720a --- /dev/null +++ b/packages/kbn-unified-data-table/src/hooks/use_row_heights_options.test.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { renderHook } from '@testing-library/react-hooks'; +import { Storage } from '@kbn/kibana-utils-plugin/public'; +import { LocalStorageMock } from '../../__mocks__/local_storage_mock'; +import { useRowHeightsOptions } from './use_row_heights_options'; + +const CONFIG_ROW_HEIGHT = 3; + +describe('useRowHeightsOptions', () => { + test('should apply rowHeight from savedSearch', () => { + const { result } = renderHook(() => { + return useRowHeightsOptions({ + rowHeightState: 2, + storage: new LocalStorageMock({}) as unknown as Storage, + consumer: 'discover', + }); + }); + + expect(result.current.defaultHeight).toEqual({ lineCount: 2 }); + }); + + test('should apply rowHeight from local storage', () => { + const { result } = renderHook(() => { + return useRowHeightsOptions({ + storage: new LocalStorageMock({ + ['discover:dataGridRowHeight']: { + previousRowHeight: 5, + previousConfigRowHeight: 3, + }, + }) as unknown as Storage, + consumer: 'discover', + }); + }); + + expect(result.current.defaultHeight).toEqual({ lineCount: 5 }); + }); + + test('should apply rowHeight from configRowHeight', () => { + const { result } = renderHook(() => { + return useRowHeightsOptions({ + consumer: 'discover', + configRowHeight: 3, + storage: new LocalStorageMock({}) as unknown as Storage, + }); + }); + + expect(result.current.defaultHeight).toEqual({ + lineCount: CONFIG_ROW_HEIGHT, + }); + }); + + test('should apply rowHeight from uiSettings instead of local storage value, since uiSettings has been changed', () => { + const { result } = renderHook(() => { + return useRowHeightsOptions({ + storage: new LocalStorageMock({ + ['discover:dataGridRowHeight']: { + previousRowHeight: 4, + // different from uiSettings (config), now user changed it to 3, but prev was 4 + previousConfigRowHeight: 4, + }, + }) as unknown as Storage, + consumer: 'discover', + }); + }); + + expect(result.current.defaultHeight).toEqual({ + lineCount: CONFIG_ROW_HEIGHT, + }); + }); +}); diff --git a/src/plugins/discover/public/hooks/use_row_heights_options.ts b/packages/kbn-unified-data-table/src/hooks/use_row_heights_options.ts similarity index 84% rename from src/plugins/discover/public/hooks/use_row_heights_options.ts rename to packages/kbn-unified-data-table/src/hooks/use_row_heights_options.ts index a9ef67ace530b..9d460c8ea2ba9 100644 --- a/src/plugins/discover/public/hooks/use_row_heights_options.ts +++ b/packages/kbn-unified-data-table/src/hooks/use_row_heights_options.ts @@ -7,10 +7,9 @@ */ import type { EuiDataGridRowHeightOption, EuiDataGridRowHeightsOptions } from '@elastic/eui'; +import type { Storage } from '@kbn/kibana-utils-plugin/public'; import { useMemo } from 'react'; -import { ROW_HEIGHT_OPTION } from '@kbn/discover-utils'; import { isValidRowHeight } from '../utils/validate_row_height'; -import { useDiscoverServices } from './use_discover_services'; import { DataGridOptionsRecord, getStoredRowHeight, @@ -20,6 +19,9 @@ import { interface UseRowHeightProps { rowHeightState?: number; onUpdateRowHeight?: (rowHeight: number) => void; + storage: Storage; + configRowHeight?: number; + consumer: string; } /** @@ -30,6 +32,7 @@ interface UseRowHeightProps { */ const SINGLE_ROW_HEIGHT_OPTION = 0; const AUTO_ROW_HEIGHT_OPTION = -1; +const DEFAULT_ROW_HEIGHT_OPTION = 3; /** * Converts rowHeight of EuiDataGrid to rowHeight number (-1 to 20) @@ -57,12 +60,15 @@ const deserializeRowHeight = (number: number): EuiDataGridRowHeightOption | unde return { lineCount: number }; // custom }; -export const useRowHeightsOptions = ({ rowHeightState, onUpdateRowHeight }: UseRowHeightProps) => { - const { storage, uiSettings } = useDiscoverServices(); - +export const useRowHeightsOptions = ({ + rowHeightState, + onUpdateRowHeight, + storage, + configRowHeight = DEFAULT_ROW_HEIGHT_OPTION, + consumer, +}: UseRowHeightProps) => { return useMemo((): EuiDataGridRowHeightsOptions => { - const rowHeightFromLS = getStoredRowHeight(storage); - const configRowHeight = uiSettings.get(ROW_HEIGHT_OPTION); + const rowHeightFromLS = getStoredRowHeight(storage, consumer); const configHasNotChanged = ( localStorageRecord: DataGridOptionsRecord | null @@ -83,9 +89,9 @@ export const useRowHeightsOptions = ({ rowHeightState, onUpdateRowHeight }: UseR lineHeight: '1.6em', onChange: ({ defaultHeight: newRowHeight }: EuiDataGridRowHeightsOptions) => { const newSerializedRowHeight = serializeRowHeight(newRowHeight); - updateStoredRowHeight(newSerializedRowHeight, configRowHeight, storage); + updateStoredRowHeight(newSerializedRowHeight, configRowHeight, storage, consumer); onUpdateRowHeight?.(newSerializedRowHeight); }, }; - }, [rowHeightState, uiSettings, storage, onUpdateRowHeight]); + }, [storage, consumer, rowHeightState, configRowHeight, onUpdateRowHeight]); }; diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx b/packages/kbn-unified-data-table/src/table_context.tsx similarity index 70% rename from src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx rename to packages/kbn-unified-data-table/src/table_context.tsx index f2dfd540c7d05..2a1d4656d4a65 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_context.tsx +++ b/packages/kbn-unified-data-table/src/table_context.tsx @@ -9,10 +9,10 @@ import React from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import type { ValueToStringConverter } from '../../types'; +import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import type { ValueToStringConverter } from './types'; -export interface GridContext { +export interface DataTableContext { expanded?: DataTableRecord | undefined; setExpanded?: (hit?: DataTableRecord) => void; rows: DataTableRecord[]; @@ -22,8 +22,9 @@ export interface GridContext { selectedDocs: string[]; setSelectedDocs: (selected: string[]) => void; valueToStringConverter: ValueToStringConverter; + componentsTourSteps?: Record; } -const defaultContext = {} as unknown as GridContext; +const defaultContext = {} as unknown as DataTableContext; -export const DiscoverGridContext = React.createContext(defaultContext); +export const UnifiedDataTableContext = React.createContext(defaultContext); diff --git a/src/plugins/discover/public/types.ts b/packages/kbn-unified-data-table/src/types.ts similarity index 57% rename from src/plugins/discover/public/types.ts rename to packages/kbn-unified-data-table/src/types.ts index 051892902239d..79ca4e721e910 100644 --- a/src/plugins/discover/public/types.ts +++ b/packages/kbn-unified-data-table/src/types.ts @@ -6,18 +6,19 @@ * Side Public License, v 1. */ -import type { DatatableColumn } from '@kbn/expressions-plugin/common'; -import type { DataTableRecord } from '@kbn/discover-utils/types'; -import type { SearchResponseInterceptedWarning } from '@kbn/search-response-warnings'; +/** + * User configurable state of data grid, persisted in saved search + */ +export interface UnifiedDataTableSettings { + columns?: Record; +} + +export interface UnifiedDataTableSettingsColumn { + width?: number; +} export type ValueToStringConverter = ( rowIndex: number, columnId: string, options?: { compatibleWithCSV?: boolean } ) => { formattedString: string; withFormula: boolean }; - -export interface RecordsFetchResponse { - records: DataTableRecord[]; - textBasedQueryColumns?: DatatableColumn[]; - interceptedWarnings?: SearchResponseInterceptedWarning[]; -} diff --git a/src/plugins/discover/public/utils/columns.test.ts b/packages/kbn-unified-data-table/src/utils/columns.test.ts similarity index 95% rename from src/plugins/discover/public/utils/columns.test.ts rename to packages/kbn-unified-data-table/src/utils/columns.test.ts index 5ef7d8fea450f..36a8b60a6bc68 100644 --- a/src/plugins/discover/public/utils/columns.test.ts +++ b/packages/kbn-unified-data-table/src/utils/columns.test.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { dataViewWithTimefieldMock } from '../../__mocks__/data_view_with_timefield'; import { getDisplayedColumns } from './columns'; -import { dataViewWithTimefieldMock } from '../__mocks__/data_view_with_timefield'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; describe('getDisplayedColumns', () => { diff --git a/src/plugins/discover/public/utils/columns.ts b/packages/kbn-unified-data-table/src/utils/columns.ts similarity index 94% rename from src/plugins/discover/public/utils/columns.ts rename to packages/kbn-unified-data-table/src/utils/columns.ts index 49e234b11decc..f2a72f0a8b650 100644 --- a/src/plugins/discover/public/utils/columns.ts +++ b/packages/kbn-unified-data-table/src/utils/columns.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { DataView } from '@kbn/data-views-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; // We store this outside the function as a constant, so we're not creating a new array every time // the function is returning this. A changing array might cause the data grid to think it got diff --git a/src/plugins/discover/public/utils/convert_value_to_string.test.tsx b/packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx similarity index 67% rename from src/plugins/discover/public/utils/convert_value_to_string.test.tsx rename to packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx index dd81ad621f182..aa8ba719c5ba2 100644 --- a/src/plugins/discover/public/utils/convert_value_to_string.test.tsx +++ b/packages/kbn-unified-data-table/src/utils/convert_value_to_string.test.tsx @@ -6,16 +6,16 @@ * Side Public License, v 1. */ -import { discoverGridContextComplexMock, discoverGridContextMock } from '../__mocks__/grid_context'; -import { discoverServiceMock } from '../__mocks__/services'; +import { dataTableContextComplexMock, dataTableContextMock } from '../../__mocks__/table_context'; +import { servicesMock } from '../../__mocks__/services'; import { convertValueToString, convertNameToString } from './convert_value_to_string'; describe('convertValueToString', () => { it('should convert a keyword value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'keyword_key', rowIndex: 0, options: { @@ -28,9 +28,9 @@ describe('convertValueToString', () => { it('should convert a text value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'text_message', rowIndex: 0, options: { @@ -43,9 +43,9 @@ describe('convertValueToString', () => { it('should convert a text value to text (not for CSV)', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'text_message', rowIndex: 0, options: { @@ -58,9 +58,9 @@ describe('convertValueToString', () => { it('should convert a multiline text value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'text_message', rowIndex: 1, options: { @@ -74,9 +74,9 @@ describe('convertValueToString', () => { it('should convert a number value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'number_price', rowIndex: 0, options: { @@ -89,9 +89,9 @@ describe('convertValueToString', () => { it('should convert a date value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'date', rowIndex: 0, options: { @@ -104,9 +104,9 @@ describe('convertValueToString', () => { it('should convert a date nanos value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'date_nanos', rowIndex: 0, options: { @@ -119,9 +119,9 @@ describe('convertValueToString', () => { it('should convert a date nanos value to text (not for CSV)', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'date_nanos', rowIndex: 0, options: { @@ -134,9 +134,9 @@ describe('convertValueToString', () => { it('should convert a boolean value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'bool_enabled', rowIndex: 0, options: { @@ -149,9 +149,9 @@ describe('convertValueToString', () => { it('should convert a binary value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'binary_blob', rowIndex: 0, options: { @@ -164,9 +164,9 @@ describe('convertValueToString', () => { it('should convert a binary value to text (not for CSV)', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'binary_blob', rowIndex: 0, options: { @@ -179,9 +179,9 @@ describe('convertValueToString', () => { it('should convert an object value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'object_user.first', rowIndex: 0, options: { @@ -194,9 +194,9 @@ describe('convertValueToString', () => { it('should convert a nested value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'nested_user', rowIndex: 0, options: { @@ -211,9 +211,9 @@ describe('convertValueToString', () => { it('should convert a flattened value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'flattened_labels', rowIndex: 0, options: { @@ -226,9 +226,9 @@ describe('convertValueToString', () => { it('should convert a range value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'range_time_frame', rowIndex: 0, options: { @@ -243,9 +243,9 @@ describe('convertValueToString', () => { it('should convert a rank features value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'rank_features', rowIndex: 0, options: { @@ -258,9 +258,9 @@ describe('convertValueToString', () => { it('should convert a histogram value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'histogram', rowIndex: 0, options: { @@ -273,9 +273,9 @@ describe('convertValueToString', () => { it('should convert a IP value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'ip_addr', rowIndex: 0, options: { @@ -288,9 +288,9 @@ describe('convertValueToString', () => { it('should convert a IP value to text (not for CSV)', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'ip_addr', rowIndex: 0, options: { @@ -303,9 +303,9 @@ describe('convertValueToString', () => { it('should convert a version value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'version', rowIndex: 0, options: { @@ -318,9 +318,9 @@ describe('convertValueToString', () => { it('should convert a version value to text (not for CSV)', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'version', rowIndex: 0, options: { @@ -333,9 +333,9 @@ describe('convertValueToString', () => { it('should convert a vector value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'vector', rowIndex: 0, options: { @@ -348,9 +348,9 @@ describe('convertValueToString', () => { it('should convert a geo point value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'geo_point', rowIndex: 0, options: { @@ -363,9 +363,9 @@ describe('convertValueToString', () => { it('should convert a geo point object value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'geo_point', rowIndex: 1, options: { @@ -378,9 +378,9 @@ describe('convertValueToString', () => { it('should convert an array value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'array_tags', rowIndex: 0, options: { @@ -393,9 +393,9 @@ describe('convertValueToString', () => { it('should convert a shape value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'geometry', rowIndex: 0, options: { @@ -410,9 +410,9 @@ describe('convertValueToString', () => { it('should convert a runtime value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'runtime_number', rowIndex: 0, options: { @@ -425,9 +425,9 @@ describe('convertValueToString', () => { it('should convert a scripted value to text', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'scripted_string', rowIndex: 0, options: { @@ -440,9 +440,9 @@ describe('convertValueToString', () => { it('should convert a scripted value to text (not for CSV)', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'scripted_string', rowIndex: 0, options: { @@ -455,9 +455,9 @@ describe('convertValueToString', () => { it('should return an empty string and not fail', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'unknown', rowIndex: 0, options: { @@ -470,9 +470,9 @@ describe('convertValueToString', () => { it('should return an empty string when rowIndex is out of range', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'unknown', rowIndex: -1, options: { @@ -485,9 +485,9 @@ describe('convertValueToString', () => { it('should return _source value', () => { const result = convertValueToString({ - rows: discoverGridContextMock.rows, - dataView: discoverGridContextMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextMock.rows, + dataView: dataTableContextMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: '_source', rowIndex: 0, options: { @@ -508,9 +508,9 @@ describe('convertValueToString', () => { it('should return a formatted _source value', () => { const result = convertValueToString({ - rows: discoverGridContextMock.rows, - dataView: discoverGridContextMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextMock.rows, + dataView: dataTableContextMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: '_source', rowIndex: 0, options: { @@ -525,9 +525,9 @@ describe('convertValueToString', () => { it('should escape formula', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'array_tags', rowIndex: 1, options: { @@ -539,9 +539,9 @@ describe('convertValueToString', () => { expect(result.withFormula).toBe(true); const result2 = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'scripted_string', rowIndex: 1, options: { @@ -555,9 +555,9 @@ describe('convertValueToString', () => { it('should not escape formulas when not for CSV', () => { const result = convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, columnId: 'array_tags', rowIndex: 1, options: { diff --git a/src/plugins/discover/public/utils/convert_value_to_string.ts b/packages/kbn-unified-data-table/src/utils/convert_value_to_string.ts similarity index 95% rename from src/plugins/discover/public/utils/convert_value_to_string.ts rename to packages/kbn-unified-data-table/src/utils/convert_value_to_string.ts index 605c7912b17f1..486ed5574dbf2 100644 --- a/src/plugins/discover/public/utils/convert_value_to_string.ts +++ b/packages/kbn-unified-data-table/src/utils/convert_value_to_string.ts @@ -6,9 +6,9 @@ * Side Public License, v 1. */ -import { DataView } from '@kbn/data-views-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; import { cellHasFormulas, createEscapeValue } from '@kbn/data-plugin/common'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { formatFieldValue } from '@kbn/discover-utils'; diff --git a/src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx b/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx similarity index 77% rename from src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx rename to packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx index 595b7601b6f65..7ff5c9b3f19b6 100644 --- a/src/plugins/discover/public/utils/copy_value_to_clipboard.test.tsx +++ b/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.test.tsx @@ -6,8 +6,8 @@ * Side Public License, v 1. */ -import { discoverGridContextComplexMock } from '../__mocks__/grid_context'; -import { discoverServiceMock } from '../__mocks__/services'; +import { dataTableContextComplexMock } from '../../__mocks__/table_context'; +import { servicesMock } from '../../__mocks__/services'; import { copyValueToClipboard, copyColumnNameToClipboard, @@ -22,9 +22,9 @@ const warn = jest.spyOn(console, 'warn').mockImplementation(() => {}); describe('copyValueToClipboard', () => { const valueToStringConverter: ValueToStringConverter = (rowIndex, columnId, options) => convertValueToString({ - rows: discoverGridContextComplexMock.rows, - dataView: discoverGridContextComplexMock.dataView, - fieldFormats: discoverServiceMock.fieldFormats, + rows: dataTableContextComplexMock.rows, + dataView: dataTableContextComplexMock.dataView, + fieldFormats: servicesMock.fieldFormats, rowIndex, columnId, options, @@ -39,6 +39,10 @@ describe('copyValueToClipboard', () => { }, writable: true, }); + Object.defineProperty(window, 'sessionStorage', { + value: { clear: jest.fn() }, + writable: true, + }); }); afterAll(() => { @@ -50,7 +54,7 @@ describe('copyValueToClipboard', () => { it('should copy a value to clipboard', () => { execCommandMock.mockImplementationOnce(() => true); const result = copyValueToClipboard({ - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, columnId: 'keyword_key', rowIndex: 0, valueToStringConverter, @@ -59,7 +63,7 @@ describe('copyValueToClipboard', () => { expect(result).toBe('abcd1'); expect(execCommandMock).toHaveBeenCalledWith('copy'); expect(warn).not.toHaveBeenCalled(); - expect(discoverServiceMock.toastNotifications.addInfo).toHaveBeenCalledWith({ + expect(servicesMock.toastNotifications.addInfo).toHaveBeenCalledWith({ title: 'Copied to clipboard', }); }); @@ -68,7 +72,7 @@ describe('copyValueToClipboard', () => { execCommandMock.mockImplementationOnce(() => false); const result = copyValueToClipboard({ - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, columnId: 'keyword_key', rowIndex: 0, valueToStringConverter, @@ -77,7 +81,7 @@ describe('copyValueToClipboard', () => { expect(result).toBe(null); expect(execCommandMock).toHaveBeenCalledWith('copy'); expect(warn).toHaveBeenCalledWith('Unable to copy to clipboard.'); - expect(discoverServiceMock.toastNotifications.addWarning).toHaveBeenCalledWith({ + expect(servicesMock.toastNotifications.addWarning).toHaveBeenCalledWith({ title: 'Unable to copy to clipboard in this browser', }); }); @@ -85,13 +89,13 @@ describe('copyValueToClipboard', () => { it('should copy a column name to clipboard', () => { execCommandMock.mockImplementationOnce(() => true); const result = copyColumnNameToClipboard({ - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, columnDisplayName: 'text_message', }); expect(result).toBe('"text_message"'); expect(execCommandMock).toHaveBeenCalledWith('copy'); - expect(discoverServiceMock.toastNotifications.addInfo).toHaveBeenCalledWith({ + expect(servicesMock.toastNotifications.addInfo).toHaveBeenCalledWith({ title: 'Copied to clipboard', }); }); @@ -99,14 +103,14 @@ describe('copyValueToClipboard', () => { it('should inform when copy a column name to clipboard failed', () => { execCommandMock.mockImplementationOnce(() => false); const result = copyColumnNameToClipboard({ - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, columnDisplayName: 'text_message', }); expect(result).toBe(null); expect(execCommandMock).toHaveBeenCalledWith('copy'); expect(warn).toHaveBeenCalledWith('Unable to copy to clipboard.'); - expect(discoverServiceMock.toastNotifications.addWarning).toHaveBeenCalledWith({ + expect(servicesMock.toastNotifications.addWarning).toHaveBeenCalledWith({ title: 'Unable to copy to clipboard in this browser', }); }); @@ -115,7 +119,7 @@ describe('copyValueToClipboard', () => { execCommandMock.mockImplementationOnce(() => true); const result = await copyColumnValuesToClipboard({ - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, columnId: 'bool_enabled', columnDisplayName: 'custom_bool_enabled', rowsCount: 2, @@ -126,7 +130,7 @@ describe('copyValueToClipboard', () => { expect(global.window.navigator.clipboard.writeText).toHaveBeenCalledWith( '"custom_bool_enabled"\nfalse\ntrue' ); - expect(discoverServiceMock.toastNotifications.addInfo).toHaveBeenCalledWith({ + expect(servicesMock.toastNotifications.addInfo).toHaveBeenCalledWith({ title: 'Values of "custom_bool_enabled" column copied to clipboard', }); }); @@ -134,7 +138,7 @@ describe('copyValueToClipboard', () => { it('should copy column values to clipboard with a warning', async () => { execCommandMock.mockImplementationOnce(() => true); const result = await copyColumnValuesToClipboard({ - toastNotifications: discoverServiceMock.toastNotifications, + toastNotifications: servicesMock.toastNotifications, columnId: 'scripted_string', columnDisplayName: 'custom_scripted_string', rowsCount: 2, @@ -142,7 +146,7 @@ describe('copyValueToClipboard', () => { }); expect(result).toBe('"custom_scripted_string"\n"hi there"\n"\'=1+2"";=1+2"'); - expect(discoverServiceMock.toastNotifications.addWarning).toHaveBeenCalledWith({ + expect(servicesMock.toastNotifications.addWarning).toHaveBeenCalledWith({ title: 'Values of "custom_scripted_string" column copied to clipboard', text: 'Values may contain formulas that are escaped.', }); diff --git a/src/plugins/discover/public/utils/copy_value_to_clipboard.ts b/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.ts similarity index 89% rename from src/plugins/discover/public/utils/copy_value_to_clipboard.ts rename to packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.ts index c700fa748f335..2e9620b42728b 100644 --- a/src/plugins/discover/public/utils/copy_value_to_clipboard.ts +++ b/packages/kbn-unified-data-table/src/utils/copy_value_to_clipboard.ts @@ -13,12 +13,12 @@ import type { ValueToStringConverter } from '../types'; import { convertNameToString } from './convert_value_to_string'; const WARNING_FOR_FORMULAS = i18n.translate( - 'discover.grid.copyEscapedValueWithFormulasToClipboardWarningText', + 'unifiedDataTable.copyEscapedValueWithFormulasToClipboardWarningText', { defaultMessage: 'Values may contain formulas that are escaped.', } ); -const COPY_FAILED_ERROR_MESSAGE = i18n.translate('discover.grid.copyFailedErrorText', { +const COPY_FAILED_ERROR_MESSAGE = i18n.translate('unifiedDataTable.copyFailedErrorText', { defaultMessage: 'Unable to copy to clipboard in this browser', }); @@ -46,7 +46,7 @@ export const copyValueToClipboard = ({ return null; } - const toastTitle = i18n.translate('discover.grid.copyValueToClipboard.toastTitle', { + const toastTitle = i18n.translate('unifiedDataTable.copyValueToClipboard.toastTitle', { defaultMessage: 'Copied to clipboard', }); @@ -105,7 +105,7 @@ export const copyColumnValuesToClipboard = async ({ return null; } - const toastTitle = i18n.translate('discover.grid.copyColumnValuesToClipboard.toastTitle', { + const toastTitle = i18n.translate('unifiedDataTable.copyColumnValuesToClipboard.toastTitle', { defaultMessage: 'Values of "{column}" column copied to clipboard', values: { column: columnDisplayName }, }); @@ -143,7 +143,7 @@ export const copyColumnNameToClipboard = ({ return null; } - const toastTitle = i18n.translate('discover.grid.copyColumnNameToClipboard.toastTitle', { + const toastTitle = i18n.translate('unifiedDataTable.copyColumnNameToClipboard.toastTitle', { defaultMessage: 'Copied to clipboard', }); diff --git a/src/plugins/discover/public/utils/get_field_capabilities.test.ts b/packages/kbn-unified-data-table/src/utils/get_field_capabilities.test.ts similarity index 100% rename from src/plugins/discover/public/utils/get_field_capabilities.test.ts rename to packages/kbn-unified-data-table/src/utils/get_field_capabilities.test.ts diff --git a/src/plugins/discover/public/utils/get_field_capabilities.ts b/packages/kbn-unified-data-table/src/utils/get_field_capabilities.ts similarity index 90% rename from src/plugins/discover/public/utils/get_field_capabilities.ts rename to packages/kbn-unified-data-table/src/utils/get_field_capabilities.ts index cd63c1c189e73..8374801ec311e 100644 --- a/src/plugins/discover/public/utils/get_field_capabilities.ts +++ b/packages/kbn-unified-data-table/src/utils/get_field_capabilities.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { DataView, DataViewField } from '@kbn/data-views-plugin/common'; +import type { DataView, DataViewField } from '@kbn/data-views-plugin/common'; export const getFieldCapabilities = (dataView: DataView, field: DataViewField) => { const isRuntimeField = Boolean(dataView.getFieldByName(field.name)?.runtimeField); diff --git a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx similarity index 75% rename from src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx rename to packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx index 536a84172a88c..941dccabf2474 100644 --- a/src/plugins/discover/public/components/discover_grid/get_render_cell_value.test.tsx +++ b/packages/kbn-unified-data-table/src/utils/get_render_cell_value.test.tsx @@ -13,9 +13,38 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { getRenderCellValueFn } from './get_render_cell_value'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { CodeEditorProps, KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { buildDataTableRecord } from '@kbn/discover-utils'; import type { EsHitRecord } from '@kbn/discover-utils/types'; +import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; + +jest.mock('@kbn/code-editor', () => { + const original = jest.requireActual('@kbn/code-editor'); + + const CodeEditorMock = (props: CodeEditorProps) => ( + + ); + + return { + ...original, + CodeEditor: CodeEditorMock, + }; +}); + +window.matchMedia = jest.fn().mockImplementation((query) => { + return { + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), + removeListener: jest.fn(), + }; +}); const mockServices = { settings: { @@ -34,14 +63,6 @@ const mockServices = { }, }; -jest.mock('../../hooks/use_discover_services', () => { - const originalModule = jest.requireActual('../../hooks/use_discover_services'); - return { - ...originalModule, - useDiscoverServices: () => mockServices, - }; -}); - const rowsSource: EsHitRecord[] = [ { _id: '1', @@ -82,18 +103,19 @@ const rowsFieldsWithTopLevelObject: EsHitRecord[] = [ const build = (hit: EsHitRecord) => buildDataTableRecord(hit, dataViewMock); -describe('Discover grid cell rendering', function () { +describe('Unified data table cell rendering', function () { it('renders bytes column correctly', () => { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsSource.map(build), false, () => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - ); expect(component.html()).toMatchInlineSnapshot( - `"100"` + `"100"` ); }); it('renders bytes column correctly using _source when details is true', () => { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsSource.map(build), false, () => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - ); expect(component.html()).toMatchInlineSnapshot( - `"
100
"` + `"
100
"` ); }); it('renders bytes column correctly using fields when details is true', () => { const closePopoverMockFn = jest.fn(); - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFields.map(build), false, () => false, - 100, - closePopoverMockFn + closePopoverMockFn, + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = mountWithIntl( - ); expect(component.html()).toMatchInlineSnapshot( - `"
100
"` + `"
100
"` ); findTestSubject(component, 'docTableClosePopover').simulate('click'); expect(closePopoverMockFn).toHaveBeenCalledTimes(1); }); it('renders _source column correctly', () => { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsSource.map(build), false, (fieldName) => ['extension', 'bytes'].includes(fieldName), - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - @@ -191,7 +216,7 @@ describe('Discover grid cell rendering', function () { extension { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsSource.map(build), false, () => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - - { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFields.map(build), true, (fieldName) => ['extension', 'bytes'].includes(fieldName), - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - @@ -340,7 +367,7 @@ describe('Discover grid cell rendering', function () { extension { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFields.map(build), true, (fieldName) => ['extension', 'bytes'].includes(fieldName), + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, // this is the number of rendered items - 1, - jest.fn() + 1 ); const component = shallow( - @@ -419,7 +447,7 @@ describe('Discover grid cell rendering', function () { extension { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFields.map(build), true, (fieldName) => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - - { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFieldsWithTopLevelObject.map(build), true, (fieldName) => ['object.value', 'extension', 'bytes'].includes(fieldName), - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - @@ -577,7 +607,7 @@ describe('Discover grid cell rendering', function () { object.value { (dataViewMock.getFieldByName as jest.Mock).mockReturnValueOnce(undefined); - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFieldsWithTopLevelObject.map(build), true, (fieldName) => ['extension', 'bytes', 'object.value'].includes(fieldName), - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - @@ -619,7 +650,7 @@ describe('Discover grid cell rendering', function () { object.value { const closePopoverMockFn = jest.fn(); - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFieldsWithTopLevelObject.map(build), true, () => false, - 100, - closePopoverMockFn + closePopoverMockFn, + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - - { const closePopoverMockFn = jest.fn(); - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFieldsWithTopLevelObject.map(build), true, () => false, - 100, - closePopoverMockFn + closePopoverMockFn, + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = mountWithIntl( - { (dataViewMock.getFieldByName as jest.Mock).mockReturnValueOnce(undefined); - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFieldsWithTopLevelObject.map(build), true, () => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsSource.map(build), false, () => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - ); expect(component.html()).toMatchInlineSnapshot( - `"-"` + `"-"` ); }); it('renders correctly when invalid column is given', () => { - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsSource.map(build), false, () => false, - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - ); expect(component.html()).toMatchInlineSnapshot( - `"-"` + `"-"` ); }); @@ -824,16 +860,17 @@ describe('Discover grid cell rendering', function () { }, }, ]; - const DiscoverGridCellValue = getRenderCellValueFn( + const DataTableCellValue = getRenderCellValueFn( dataViewMock, rowsFieldsUnmapped.map(build), true, (fieldName) => ['unmapped'].includes(fieldName), - 100, - jest.fn() + jest.fn(), + mockServices.fieldFormats as unknown as FieldFormatsStart, + 100 ); const component = shallow( - void + closePopover: () => void, + fieldFormats: FieldFormatsStart, + maxEntries: number, + externalCustomRenderers?: Record< + string, + (props: EuiDataGridCellValueElementProps) => React.ReactNode + > ) => - ({ rowIndex, columnId, isDetails, setCellProps }: EuiDataGridCellValueElementProps) => { - const { uiSettings, fieldFormats } = useDiscoverServices(); - - const maxEntries = useMemo(() => uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), [uiSettings]); - + ({ + rowIndex, + columnId, + isDetails, + setCellProps, + colIndex, + isExpandable, + isExpanded, + }: EuiDataGridCellValueElementProps) => { + if (!!externalCustomRenderers && !!externalCustomRenderers[columnId]) { + return ( + <> + {externalCustomRenderers[columnId]({ + rowIndex, + columnId, + isDetails, + setCellProps, + isExpandable, + isExpanded, + colIndex, + })} + + ); + } const row = rows ? rows[rowIndex] : undefined; const field = dataView.fields.getByName(columnId); - const ctx = useContext(DiscoverGridContext); + const ctx = useContext(UnifiedDataTableContext); useEffect(() => { if (row?.isAnchor) { @@ -102,7 +125,7 @@ export const getRenderCellValueFn = const pairs = useTopLevelObjectColumns ? getTopLevelObjectPairs(row.raw, columnId, dataView, shouldShowFieldHandler).slice( 0, - maxDocFieldsDisplayed + maxEntries ) : formatHit(row, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); @@ -110,13 +133,13 @@ export const getRenderCellValueFn = {pairs.map(([key, value]) => ( {key} @@ -144,7 +167,7 @@ export const getRenderCellValueFn = function getInnerColumns(fields: Record, columnId: string) { return Object.fromEntries( Object.entries(fields).filter(([key]) => { - return key.indexOf(`${columnId}.`) === 0; + return key.startsWith(`${columnId}.`); }) ); } @@ -178,7 +201,7 @@ function renderPopoverContent({ }) { const closeButton = ( @@ -216,7 +239,7 @@ function renderPopoverContent({ String(v) }; - const formatted = (values as unknown[]) + const formatted = values .map((val: unknown) => formatter.convert(val, 'html', { field: subField, diff --git a/src/plugins/discover/public/utils/popularize_field.test.ts b/packages/kbn-unified-data-table/src/utils/popularize_field.test.ts similarity index 100% rename from src/plugins/discover/public/utils/popularize_field.test.ts rename to packages/kbn-unified-data-table/src/utils/popularize_field.test.ts diff --git a/src/plugins/discover/public/utils/popularize_field.ts b/packages/kbn-unified-data-table/src/utils/popularize_field.ts similarity index 89% rename from src/plugins/discover/public/utils/popularize_field.ts rename to packages/kbn-unified-data-table/src/utils/popularize_field.ts index 9ab711be49266..3feca3fd3d4e7 100644 --- a/src/plugins/discover/public/utils/popularize_field.ts +++ b/packages/kbn-unified-data-table/src/utils/popularize_field.ts @@ -7,8 +7,8 @@ */ import type { Capabilities } from '@kbn/core/public'; -import { DataViewsContract } from '@kbn/data-plugin/public'; -import { DataView } from '@kbn/data-views-plugin/public'; +import type { DataViewsContract } from '@kbn/data-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; async function popularizeField( dataView: DataView, diff --git a/src/plugins/discover/public/utils/row_heights.ts b/packages/kbn-unified-data-table/src/utils/row_heights.ts similarity index 70% rename from src/plugins/discover/public/utils/row_heights.ts rename to packages/kbn-unified-data-table/src/utils/row_heights.ts index f1e096b76b9f9..45f472286d030 100644 --- a/src/plugins/discover/public/utils/row_heights.ts +++ b/packages/kbn-unified-data-table/src/utils/row_heights.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Storage } from '@kbn/kibana-utils-plugin/public'; +import type { Storage } from '@kbn/kibana-utils-plugin/public'; import { isValidRowHeight } from './validate_row_height'; export interface DataGridOptionsRecord { @@ -14,10 +14,13 @@ export interface DataGridOptionsRecord { previousConfigRowHeight: number; } -const ROW_HEIGHT_KEY = 'discover:dataGridRowHeight'; +const getRowHeightKey = (consumer: string) => `${consumer}:dataGridRowHeight`; -export const getStoredRowHeight = (storage: Storage): DataGridOptionsRecord | null => { - const entry = storage.get(ROW_HEIGHT_KEY); +export const getStoredRowHeight = ( + storage: Storage, + consumer: string +): DataGridOptionsRecord | null => { + const entry = storage.get(getRowHeightKey(consumer)); if ( typeof entry === 'object' && entry !== null && @@ -32,9 +35,10 @@ export const getStoredRowHeight = (storage: Storage): DataGridOptionsRecord | nu export const updateStoredRowHeight = ( newRowHeight: number, configRowHeight: number, - storage: Storage + storage: Storage, + consumer: string ) => { - storage.set(ROW_HEIGHT_KEY, { + storage.set(getRowHeightKey(consumer), { previousRowHeight: newRowHeight, previousConfigRowHeight: configRowHeight, }); diff --git a/src/plugins/discover/public/utils/rows_per_page.test.ts b/packages/kbn-unified-data-table/src/utils/rows_per_page.test.ts similarity index 58% rename from src/plugins/discover/public/utils/rows_per_page.test.ts rename to packages/kbn-unified-data-table/src/utils/rows_per_page.test.ts index 25eddf9a44de2..8da8ea099734b 100644 --- a/src/plugins/discover/public/utils/rows_per_page.test.ts +++ b/packages/kbn-unified-data-table/src/utils/rows_per_page.test.ts @@ -6,9 +6,7 @@ * Side Public License, v 1. */ -import { discoverServiceMock } from '../__mocks__/services'; -import { SAMPLE_ROWS_PER_PAGE_SETTING } from '@kbn/discover-utils'; -import { getRowsPerPageOptions, getDefaultRowsPerPage } from './rows_per_page'; +import { getRowsPerPageOptions } from './rows_per_page'; const SORTED_OPTIONS = [10, 25, 50, 100, 250, 500]; @@ -26,17 +24,4 @@ describe('rows per page', () => { expect(getRowsPerPageOptions(350)).toEqual([10, 25, 50, 100, 250, 350, 500]); }); }); - - describe('getDefaultRowsPerPage', () => { - it('should return a value from settings', () => { - expect(getDefaultRowsPerPage(discoverServiceMock.uiSettings)).toEqual(150); - expect(discoverServiceMock.uiSettings.get).toHaveBeenCalledWith(SAMPLE_ROWS_PER_PAGE_SETTING); - }); - - it('should return a default value', () => { - expect(getDefaultRowsPerPage({ ...discoverServiceMock.uiSettings, get: jest.fn() })).toEqual( - 100 - ); - }); - }); }); diff --git a/src/plugins/discover/public/utils/rows_per_page.ts b/packages/kbn-unified-data-table/src/utils/rows_per_page.ts similarity index 62% rename from src/plugins/discover/public/utils/rows_per_page.ts rename to packages/kbn-unified-data-table/src/utils/rows_per_page.ts index bc5f07f6253d3..2eb547df1a36f 100644 --- a/src/plugins/discover/public/utils/rows_per_page.ts +++ b/packages/kbn-unified-data-table/src/utils/rows_per_page.ts @@ -7,9 +7,8 @@ */ import { sortBy, uniq } from 'lodash'; -import { SAMPLE_ROWS_PER_PAGE_SETTING } from '@kbn/discover-utils'; -import { DEFAULT_ROWS_PER_PAGE, ROWS_PER_PAGE_OPTIONS } from '../../common/constants'; -import { DiscoverServices } from '../build_services'; + +import { ROWS_PER_PAGE_OPTIONS } from '../constants'; export const getRowsPerPageOptions = (currentRowsPerPage?: number): number[] => { return sortBy( @@ -20,7 +19,3 @@ export const getRowsPerPageOptions = (currentRowsPerPage?: number): number[] => ) ); }; - -export const getDefaultRowsPerPage = (uiSettings: DiscoverServices['uiSettings']): number => { - return parseInt(uiSettings.get(SAMPLE_ROWS_PER_PAGE_SETTING), 10) || DEFAULT_ROWS_PER_PAGE; -}; diff --git a/src/plugins/discover/public/utils/validate_row_height.ts b/packages/kbn-unified-data-table/src/utils/validate_row_height.ts similarity index 100% rename from src/plugins/discover/public/utils/validate_row_height.ts rename to packages/kbn-unified-data-table/src/utils/validate_row_height.ts diff --git a/packages/kbn-unified-data-table/tsconfig.json b/packages/kbn-unified-data-table/tsconfig.json new file mode 100644 index 0000000000000..bed8d16a279b1 --- /dev/null +++ b/packages/kbn-unified-data-table/tsconfig.json @@ -0,0 +1,37 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": ["*.ts", "**/*.tsx", "src/**/*", "__mocks__/**/*.ts"], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/i18n", + "@kbn/data-views-plugin", + "@kbn/unified-doc-viewer", + "@kbn/discover-utils", + "@kbn/kibana-utils-plugin", + "@kbn/expressions-plugin", + "@kbn/test-jest-helpers", + "@kbn/i18n-react", + "@kbn/ui-theme", + "@kbn/field-types", + "@kbn/kibana-utils-plugin", + "@kbn/cell-actions", + "@kbn/utility-types", + "@kbn/data-view-field-editor-plugin", + "@kbn/field-formats-plugin", + "@kbn/react-kibana-context-common", + "@kbn/data-plugin", + "@kbn/core", + "@kbn/ui-actions-plugin", + "@kbn/charts-plugin", + "@kbn/kibana-react-plugin", + "@kbn/monaco", + "@kbn/code-editor", + "@kbn/config", + "@kbn/monaco", + ] +} diff --git a/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap index f86ba86999236..b8a983ce582f2 100644 --- a/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap +++ b/packages/shared-ux/code_editor/impl/__snapshots__/code_editor.test.tsx.snap @@ -351,7 +351,7 @@ exports[` is rendered 1`] = ` = ({ value, onChange, width, + height = '100px', options, overrideEditorWillMount, editorDidMount, @@ -478,7 +479,7 @@ export const CodeEditor: React.FC = ({ onChange={onChange} width={isFullScreen ? '100vw' : width} // previously defaulted to height which defaulted to 100% but this makes it unviewable - height={isFullScreen ? '100vh' : '100px'} + height={isFullScreen ? '100vh' : height} editorWillMount={_editorWillMount} editorDidMount={_editorDidMount} options={{ diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index d03d7294e2806..911eecd45a9fb 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -44,8 +44,30 @@ const getBootstrapScript = (isDev) => { } }; -const setServerlessKibanaDevServiceAccountIfPossible = (set, opts) => { - if (!opts.dev || !opts.serverless || process.env.isDevCliChild === 'true') { +const setServerlessKibanaDevServiceAccountIfPossible = (get, set, opts) => { + const esHosts = [].concat( + get('elasticsearch.hosts', []), + opts.elasticsearch ? opts.elasticsearch.split(',') : [] + ); + + /* + * We only handle the service token if serverless ES is running locally. + * Example would be if the user is running SES in the cloud and KBN serverless + * locally, they would be expected to handle auth on their own and this token + * is likely invalid anyways. + */ + const isESlocalhost = esHosts.length + ? esHosts.some((hostUrl) => { + const parsedUrl = url.parse(hostUrl); + return ( + parsedUrl.hostname === 'localhost' || + parsedUrl.hostname === '127.0.0.1' || + parsedUrl.hostname === 'host.docker.internal' + ); + }) + : true; // default is localhost:9200 + + if (!opts.dev || !opts.serverless || !isESlocalhost) { return; } @@ -86,7 +108,7 @@ export function applyConfigOverrides(rawConfig, opts, extraCliOptions) { if (opts.dev) { if (opts.serverless) { - setServerlessKibanaDevServiceAccountIfPossible(set, opts); + setServerlessKibanaDevServiceAccountIfPossible(get, set, opts); } if (!has('elasticsearch.serviceAccountToken') && opts.devCredentials !== false) { diff --git a/src/core/server/integration_tests/http/router.test.ts b/src/core/server/integration_tests/http/router.test.ts index 743624f2f46b3..de5e10d1ee599 100644 --- a/src/core/server/integration_tests/http/router.test.ts +++ b/src/core/server/integration_tests/http/router.test.ts @@ -576,11 +576,19 @@ describe('Handler', () => { 'An internal server error occurred. Check Kibana server logs for details.' ); expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` + Array [ Array [ - Array [ - [Error: unexpected error], - ], - ] + "500 Server Error - /", + Object { + "error": [Error: unexpected error], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, + ], + ] `); }); @@ -617,7 +625,15 @@ describe('Handler', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: Unauthorized], + "500 Server Error - /", + Object { + "error": [Error: Unauthorized], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -639,7 +655,15 @@ describe('Handler', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: Unexpected result from Route Handler. Expected KibanaResponse, but given: string.], + "500 Server Error - /", + Object { + "error": [Error: Unexpected result from Route Handler. Expected KibanaResponse, but given: string.], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -672,6 +696,22 @@ describe('Handler', () => { message: '[request query.page]: expected value of type [number] but got [string]', statusCode: 400, }); + + expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` + Array [ + Array [ + "400 Bad Request - /", + Object { + "error": [Error: [request query.page]: expected value of type [number] but got [string]], + "http": Object { + "response": Object { + "status_code": 400, + }, + }, + }, + ], + ] + `); }); it('accept to receive an array payload', async () => { @@ -1145,7 +1185,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: expected 'location' header to be set], + "500 Server Error - /", + Object { + "error": [Error: expected 'location' header to be set], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -1551,7 +1599,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: Unexpected Http status code. Expected from 400 to 599, but given: 200], + "500 Server Error - /", + Object { + "error": [Error: Unexpected Http status code. Expected from 400 to 599, but given: 200], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -1620,7 +1676,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: expected 'location' header to be set], + "500 Server Error - /", + Object { + "error": [Error: expected 'location' header to be set], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -1760,7 +1824,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: expected error message to be provided], + "500 Server Error - /", + Object { + "error": [Error: expected error message to be provided], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -1786,7 +1858,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: expected error message to be provided], + "500 Server Error - /", + Object { + "error": [Error: expected error message to be provided], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -1811,7 +1891,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: options.statusCode is expected to be set. given options: undefined], + "500 Server Error - /", + Object { + "error": [Error: options.statusCode is expected to be set. given options: undefined], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); @@ -1836,7 +1924,15 @@ describe('Response factory', () => { expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` Array [ Array [ - [Error: Unexpected Http status code. Expected from 100 to 599, but given: 20.], + "500 Server Error - /", + Object { + "error": [Error: Unexpected Http status code. Expected from 100 to 599, but given: 20.], + "http": Object { + "response": Object { + "status_code": 500, + }, + }, + }, ], ] `); diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/incompatible_cluster_routing_allocation.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/incompatible_cluster_routing_allocation.test.ts index b723ca1b62608..d663dc15e9a1c 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/incompatible_cluster_routing_allocation.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/incompatible_cluster_routing_allocation.test.ts @@ -125,7 +125,9 @@ describe('incompatible_cluster_routing_allocation', () => { await root.preboot(); await root.setup(); - root.start(); + root.start().catch(() => { + // Silent catch because the test might be done and call shutdown before starting is completed, causing unwanted thrown errors. + }); // Wait for the INIT -> INIT action retry await retryAsync( diff --git a/src/core/server/integration_tests/saved_objects/routes/update.test.ts b/src/core/server/integration_tests/saved_objects/routes/update.test.ts index c261584217a37..e121fa7a43e0d 100644 --- a/src/core/server/integration_tests/saved_objects/routes/update.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/update.test.ts @@ -24,8 +24,8 @@ import { setupConfig } from './routes_test_utils'; type SetupServerReturn = Awaited>; const testTypes = [ - { name: 'index-pattern', hide: false }, - { name: 'hidden-type', hide: true }, + { name: 'index-pattern', hide: false }, // multi-namespace type + { name: 'hidden-type', hide: true }, // hidden { name: 'hidden-from-http', hide: false, hideFromHttpApis: true }, ]; @@ -117,7 +117,7 @@ describe('PUT /api/saved_objects/{type}/{id?}', () => { 'index-pattern', 'logstash-*', { title: 'Testing' }, - { version: 'foo' } + { version: 'foo', migrationVersionCompatibility: 'raw' } ); }); diff --git a/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts b/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts index 940ea4a160cb6..1d884706fc8ba 100644 --- a/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts +++ b/src/core/server/integration_tests/saved_objects/serverless/migrations/smoke.test.ts @@ -13,10 +13,7 @@ import { createTestServerlessInstances, } from '@kbn/core-test-helpers-kbn-server'; -/** - * Until we merge https://github.com/elastic/kibana/pull/162673 this test should remain skipped. - */ -describe.skip('smoke', () => { +describe('smoke', () => { let serverlessES: TestServerlessESUtils; let serverlessKibana: TestServerlessKibanaUtils; let root: TestServerlessKibanaUtils['root']; diff --git a/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts b/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts index db24bf5a10765..035da58c60fa1 100644 --- a/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts +++ b/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy.test.ts @@ -30,6 +30,7 @@ import { declarePostPitRoute, declarePostUpdateByQueryRoute, declarePassthroughRoute, + declareIndexRoute, setProxyInterrupt, allCombinationsPermutations, } from './repository_with_proxy_utils'; @@ -113,6 +114,7 @@ describe('404s from proxies', () => { declarePostSearchRoute(hapiServer, esHostname, esPort, kbnIndexPath); declarePostPitRoute(hapiServer, esHostname, esPort, kbnIndexPath); declarePostUpdateByQueryRoute(hapiServer, esHostname, esPort, kbnIndexPath); + declareIndexRoute(hapiServer, esHostname, esPort, kbnIndexPath); }); // register index-agnostic routes @@ -396,7 +398,9 @@ describe('404s from proxies', () => { expect(genericNotFoundEsUnavailableError(myError, 'my_type', 'myTypeId1')); }); - it('returns an EsUnavailable error on `update` requests that are interrupted', async () => { + it('returns an EsUnavailable error on `update` requests that are interrupted during index', async () => { + setProxyInterrupt('update'); + let updateError; try { await repository.update('my_type', 'myTypeToUpdate', { @@ -406,9 +410,26 @@ describe('404s from proxies', () => { } catch (err) { updateError = err; } + expect(genericNotFoundEsUnavailableError(updateError)); }); + it('returns an EsUnavailable error on `update` requests that are interrupted during preflight', async () => { + setProxyInterrupt('updatePreflight'); + + let updateError; + try { + await repository.update('my_type', 'myTypeToUpdate', { + title: 'updated title', + }); + expect(false).toBe(true); // Should not get here (we expect the call to throw) + } catch (err) { + updateError = err; + } + + expect(genericNotFoundEsUnavailableError(updateError, 'my_type', 'myTypeToUpdate')); + }); + it('returns an EsUnavailable error on `bulkCreate` requests with a 404 proxy response and wrong product header', async () => { setProxyInterrupt('bulkCreate'); let bulkCreateError: any; diff --git a/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy_utils.ts b/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy_utils.ts index 35b6b37b9c413..6f40d19f609d9 100644 --- a/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy_utils.ts +++ b/src/core/server/integration_tests/saved_objects/service/lib/repository_with_proxy_utils.ts @@ -27,6 +27,8 @@ export const setProxyInterrupt = ( | 'openPit' | 'deleteByNamespace' | 'internalBulkResolve' + | 'update' + | 'updatePreflight' | null ) => (proxyInterrupt = testArg); @@ -63,7 +65,11 @@ export const declareGetRoute = ( path: `/${kbnIndex}/_doc/{type*}`, options: { handler: (req, h) => { - if (req.params.type === 'my_type:myTypeId1' || req.params.type === 'my_type:myType_123') { + if ( + req.params.type === 'my_type:myTypeId1' || + req.params.type === 'my_type:myType_123' || + proxyInterrupt === 'updatePreflight' + ) { return proxyResponseHandler(h, hostname, port); } else { return relayHandler(h, hostname, port); @@ -257,6 +263,31 @@ export const declarePostUpdateByQueryRoute = ( }, }); +// PUT _doc +export const declareIndexRoute = ( + hapiServer: Hapi.Server, + hostname: string, + port: string, + kbnIndex: string +) => + hapiServer.route({ + method: ['PUT', 'POST'], + path: `/${kbnIndex}/_doc/{_id?}`, + options: { + payload: { + output: 'data', + parse: false, + }, + handler: (req, h) => { + if (proxyInterrupt === 'update') { + return proxyResponseHandler(h, hostname, port); + } else { + return relayHandler(h, hostname, port); + } + }, + }, + }); + // catch-all passthrough route export const declarePassthroughRoute = (hapiServer: Hapi.Server, hostname: string, port: string) => hapiServer.route({ diff --git a/src/core/server/integration_tests/saved_objects/service/lib/update.test.ts b/src/core/server/integration_tests/saved_objects/service/lib/update.test.ts new file mode 100644 index 0000000000000..e2b7d91355d81 --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/service/lib/update.test.ts @@ -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 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/promises'; +import { pick } from 'lodash'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { SavedObjectsType, SavedObjectsModelVersionMap } from '@kbn/core-saved-objects-server'; +import { type TestElasticsearchUtils } from '@kbn/core-test-helpers-kbn-server'; +import '../../migrations/jest_matchers'; +import { + getKibanaMigratorTestKit, + startElasticsearch, +} from '../../migrations/kibana_migrator_test_kit'; +import { delay } from '../../migrations/test_utils'; +import { getBaseMigratorParams } from '../../migrations/fixtures/zdt_base.fixtures'; + +export const logFilePath = Path.join(__dirname, 'update.test.log'); + +describe('SOR - update API', () => { + let esServer: TestElasticsearchUtils['es']; + + beforeAll(async () => { + await fs.unlink(logFilePath).catch(() => {}); + esServer = await startElasticsearch(); + }); + + const getType = (version: 'v1' | 'v2'): SavedObjectsType => { + const versionMap: SavedObjectsModelVersionMap = { + 1: { + changes: [], + schemas: { + forwardCompatibility: (attributes) => { + return pick(attributes, 'count'); + }, + }, + }, + }; + + if (version === 'v2') { + versionMap[2] = { + changes: [ + { + type: 'data_backfill', + backfillFn: (document) => { + return { attributes: { even: document.attributes.count % 2 === 0 } }; + }, + }, + ], + }; + } + + return { + name: 'my-test-type', + hidden: false, + namespaceType: 'agnostic', + mappings: { + dynamic: false, + properties: { + count: { type: 'integer' }, + ...(version === 'v2' ? { even: { type: 'boolean' } } : {}), + }, + }, + management: { + importableAndExportable: true, + }, + switchToModelVersionAt: '8.10.0', + modelVersions: versionMap, + }; + }; + + afterAll(async () => { + await esServer?.stop(); + await delay(10); + }); + + const setup = async () => { + const { runMigrations: runMigrationV1, savedObjectsRepository: repositoryV1 } = + await getKibanaMigratorTestKit({ + ...getBaseMigratorParams(), + types: [getType('v1')], + }); + await runMigrationV1(); + + const { + runMigrations: runMigrationV2, + savedObjectsRepository: repositoryV2, + client: esClient, + } = await getKibanaMigratorTestKit({ + ...getBaseMigratorParams(), + types: [getType('v2')], + }); + await runMigrationV2(); + + return { repositoryV1, repositoryV2, esClient }; + }; + + it('supports updates between older and newer versions', async () => { + const { repositoryV1, repositoryV2, esClient } = await setup(); + + await repositoryV1.create('my-test-type', { count: 12 }, { id: 'my-id' }); + + let document = await repositoryV2.get('my-test-type', 'my-id'); + + expect(document.attributes).toEqual({ + count: 12, + even: true, + }); + + await repositoryV2.update('my-test-type', 'my-id', { + count: 11, + even: false, + }); + + document = await repositoryV1.get('my-test-type', 'my-id'); + + expect(document.attributes).toEqual({ + count: 11, + }); + + await repositoryV1.update('my-test-type', 'my-id', { + count: 14, + }); + + document = await repositoryV2.get('my-test-type', 'my-id'); + + expect(document.attributes).toEqual({ + count: 14, + even: true, + }); + + const rawDoc = await fetchDoc(esClient, 'my-test-type', 'my-id'); + expect(rawDoc._source).toEqual( + expect.objectContaining({ + typeMigrationVersion: '10.1.0', + 'my-test-type': { + count: 14, + }, + }) + ); + }); + + const fetchDoc = async (client: ElasticsearchClient, type: string, id: string) => { + return await client.get({ + index: '.kibana', + id: `${type}:${id}`, + }); + }; +}); diff --git a/src/plugins/console/public/lib/autocomplete/autocomplete.ts b/src/plugins/console/public/lib/autocomplete/autocomplete.ts index 970847ac6bedc..04634e635ac12 100644 --- a/src/plugins/console/public/lib/autocomplete/autocomplete.ts +++ b/src/plugins/console/public/lib/autocomplete/autocomplete.ts @@ -1077,11 +1077,7 @@ export default function ({ tracer('has started evaluating current token', currentToken); if (!currentToken) { - if (pos.lineNumber === 1) { - lastEvaluatedToken = null; - tracer('not starting autocomplete due to invalid current token at line 1'); - return; - } + lastEvaluatedToken = null; currentToken = { position: { column: 0, lineNumber: 0 }, value: '', type: '' }; // empty row } diff --git a/src/plugins/content_management/public/content_client/content_client.tsx b/src/plugins/content_management/public/content_client/content_client.tsx index e1d148b74760a..caf7181472f03 100644 --- a/src/plugins/content_management/public/content_client/content_client.tsx +++ b/src/plugins/content_management/public/content_client/content_client.tsx @@ -96,7 +96,7 @@ export class ContentClient { private readonly crudClientProvider: (contentType?: string) => CrudClient, private readonly contentTypeRegistry: ContentTypeRegistry ) { - this.queryClient = new QueryClient(); + this.queryClient = new QueryClient({ defaultOptions: { queries: { networkMode: 'always' } } }); this.queryOptionBuilder = createQueryOptionBuilder({ crudClientProvider: this.crudClientProvider, contentTypeRegistry: this.contentTypeRegistry, diff --git a/src/plugins/data/common/query/text_based_query_state_to_ast.test.ts b/src/plugins/data/common/query/text_based_query_state_to_ast.test.ts index 64f9c5ca59111..ee1e072e8a50f 100644 --- a/src/plugins/data/common/query/text_based_query_state_to_ast.test.ts +++ b/src/plugins/data/common/query/text_based_query_state_to_ast.test.ts @@ -54,4 +54,30 @@ describe('textBasedQueryStateToExpressionAst', () => { }) ); }); + + it('returns an object with the correct structure for an ES|QL query', async () => { + const actual = await textBasedQueryStateToExpressionAst({ + filters: [], + query: { sql: 'FROM foo' }, + time: { + from: 'now', + to: 'now+7d', + }, + }); + + expect(actual).toHaveProperty( + 'chain.1.arguments.timeRange.0.chain.0.arguments', + expect.objectContaining({ + from: ['now'], + to: ['now+7d'], + }) + ); + + expect(actual).toHaveProperty( + 'chain.2.arguments', + expect.objectContaining({ + query: ['FROM foo'], + }) + ); + }); }); diff --git a/src/plugins/data/common/query/text_based_query_state_to_ast.ts b/src/plugins/data/common/query/text_based_query_state_to_ast.ts index cb34d9c9c405c..e24cbbd0a7dab 100644 --- a/src/plugins/data/common/query/text_based_query_state_to_ast.ts +++ b/src/plugins/data/common/query/text_based_query_state_to_ast.ts @@ -49,12 +49,13 @@ export function textBasedQueryStateToExpressionAst({ if (query && isOfAggregateQueryType(query)) { const mode = getAggregateQueryMode(query); - // sql query - if (mode === 'sql' && 'sql' in query) { - const essql = aggregateQueryToAst(query, timeFieldName); + for (const esMode of ['sql', 'esql']) { + if (mode === esMode && esMode in query) { + const essql = aggregateQueryToAst(query, timeFieldName); - if (essql) { - ast.chain.push(essql); + if (essql) { + ast.chain.push(essql); + } } } } diff --git a/src/plugins/data/common/search/expressions/aggregate_query_to_ast.test.ts b/src/plugins/data/common/search/expressions/aggregate_query_to_ast.test.ts index f292954feea82..0ded432eb0508 100644 --- a/src/plugins/data/common/search/expressions/aggregate_query_to_ast.test.ts +++ b/src/plugins/data/common/search/expressions/aggregate_query_to_ast.test.ts @@ -10,14 +10,14 @@ import { aggregateQueryToAst } from './aggregate_query_to_ast'; describe('aggregateQueryToAst', () => { it('should return a function', () => { - expect(aggregateQueryToAst({ sql: 'SELECT * from foo' })).toHaveProperty('type', 'function'); + expect(aggregateQueryToAst({ esql: 'from foo' })).toHaveProperty('type', 'function'); }); it('should forward arguments', () => { - expect(aggregateQueryToAst({ sql: 'SELECT * from foo' }, 'baz')).toHaveProperty( + expect(aggregateQueryToAst({ esql: 'from foo' }, 'baz')).toHaveProperty( 'arguments', expect.objectContaining({ - query: ['SELECT * from foo'], + query: ['from foo'], timeField: ['baz'], }) ); diff --git a/src/plugins/data/common/search/expressions/aggregate_query_to_ast.ts b/src/plugins/data/common/search/expressions/aggregate_query_to_ast.ts index 84e1e4e5f2262..6b69af873585b 100644 --- a/src/plugins/data/common/search/expressions/aggregate_query_to_ast.ts +++ b/src/plugins/data/common/search/expressions/aggregate_query_to_ast.ts @@ -5,10 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - +import { i18n } from '@kbn/i18n'; import { buildExpressionFunction, ExpressionAstFunction } from '@kbn/expressions-plugin/common'; import { AggregateQuery } from '../../query'; import { EssqlExpressionFunctionDefinition } from './essql'; +import { EsqlExpressionFunctionDefinition } from './esql'; export const aggregateQueryToAst = ( query: AggregateQuery, @@ -20,4 +21,11 @@ export const aggregateQueryToAst = ( timeField, }).toAst(); } + if ('esql' in query) { + return buildExpressionFunction('esql', { + query: query.esql, + timeField, + locale: i18n.getLocale(), + }).toAst(); + } }; diff --git a/src/plugins/data/common/search/expressions/esql.ts b/src/plugins/data/common/search/expressions/esql.ts new file mode 100644 index 0000000000000..8ef0f49588303 --- /dev/null +++ b/src/plugins/data/common/search/expressions/esql.ts @@ -0,0 +1,260 @@ +/* + * Copyright 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 { KibanaRequest } from '@kbn/core/server'; +import { castEsToKbnFieldTypeName, ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; +import { i18n } from '@kbn/i18n'; +import type { + Datatable, + DatatableColumnType, + ExpressionFunctionDefinition, +} from '@kbn/expressions-plugin/common'; +import { RequestAdapter } from '@kbn/inspector-plugin/common'; + +import { zipObject } from 'lodash'; +import { Observable, defer, throwError } from 'rxjs'; +import { catchError, map, switchMap, tap } from 'rxjs/operators'; +import { buildEsQuery } from '@kbn/es-query'; +import { getEsQueryConfig } from '../../es_query'; +import { getTime } from '../../query'; +import { ESQL_SEARCH_STRATEGY, IKibanaSearchRequest, ISearchGeneric, KibanaContext } from '..'; +import { IKibanaSearchResponse } from '../types'; +import { UiSettingsCommon } from '../..'; + +type Input = KibanaContext | null; +type Output = Observable; + +interface Arguments { + query: string; + timezone?: string; + timeField?: string; + locale?: string; +} + +export type EsqlExpressionFunctionDefinition = ExpressionFunctionDefinition< + 'esql', + Input, + Arguments, + Output +>; + +interface EsqlFnArguments { + getStartDependencies(getKibanaRequest: () => KibanaRequest): Promise; +} + +interface EsqlStartDependencies { + search: ISearchGeneric; + uiSettings: UiSettingsCommon; +} + +function normalizeType(type: string): DatatableColumnType { + switch (type) { + case ES_FIELD_TYPES._INDEX: + case ES_FIELD_TYPES.GEO_POINT: + case ES_FIELD_TYPES.IP: + return KBN_FIELD_TYPES.STRING; + case '_version': + return KBN_FIELD_TYPES.NUMBER; + case 'datetime': + return KBN_FIELD_TYPES.DATE; + default: + return castEsToKbnFieldTypeName(type) as DatatableColumnType; + } +} + +function sanitize(value: string) { + return value.replace(/[\(\)]/g, '_'); +} + +interface ESQLSearchParams { + time_zone?: string; + query: string; + filter?: unknown; + locale?: string; +} + +interface ESQLSearchReponse { + columns?: Array<{ + name: string; + type: string; + }>; + values: unknown[][]; +} + +export const getEsqlFn = ({ getStartDependencies }: EsqlFnArguments) => { + const essql: EsqlExpressionFunctionDefinition = { + name: 'esql', + type: 'datatable', + inputTypes: ['kibana_context', 'null'], + help: i18n.translate('data.search.esql.help', { + defaultMessage: 'Queries Elasticsearch using ES|QL.', + }), + args: { + query: { + aliases: ['_', 'q'], + types: ['string'], + help: i18n.translate('data.search.esql.query.help', { + defaultMessage: 'An ES|QL query.', + }), + }, + timezone: { + aliases: ['tz'], + types: ['string'], + default: 'UTC', + help: i18n.translate('data.search.esql.timezone.help', { + defaultMessage: + 'The timezone to use for date operations. Valid ISO8601 formats and UTC offsets both work.', + }), + }, + timeField: { + aliases: ['timeField'], + types: ['string'], + help: i18n.translate('data.search.essql.timeField.help', { + defaultMessage: 'The time field to use in the time range filter set in the context.', + }), + }, + locale: { + aliases: ['locale'], + types: ['string'], + help: i18n.translate('data.search.essql.locale.help', { + defaultMessage: 'The locale to use.', + }), + }, + }, + fn( + input, + { query, timezone, timeField, locale }, + { abortSignal, inspectorAdapters, getKibanaRequest } + ) { + return defer(() => + getStartDependencies(() => { + const request = getKibanaRequest?.(); + if (!request) { + throw new Error( + 'A KibanaRequest is required to run queries on the server. ' + + 'Please provide a request object to the expression execution params.' + ); + } + + return request; + }) + ).pipe( + switchMap(({ search, uiSettings }) => { + const params: ESQLSearchParams = { + query, + time_zone: timezone, + locale, + }; + if (input) { + const esQueryConfigs = getEsQueryConfig( + uiSettings as Parameters[0] + ); + const timeFilter = + input.timeRange && + getTime(undefined, input.timeRange, { + fieldName: timeField, + }); + + params.filter = buildEsQuery( + undefined, + input.query || [], + [...(input.filters ?? []), ...(timeFilter ? [timeFilter] : [])], + esQueryConfigs + ); + } + + let startTime = Date.now(); + const logInspectorRequest = () => { + if (!inspectorAdapters.requests) { + inspectorAdapters.requests = new RequestAdapter(); + } + + const request = inspectorAdapters.requests.start( + i18n.translate('data.search.dataRequest.title', { + defaultMessage: 'Data', + }), + { + description: i18n.translate('data.search.es_search.dataRequest.description', { + defaultMessage: + 'This request queries Elasticsearch to fetch the data for the visualization.', + }), + }, + startTime + ); + startTime = Date.now(); + + return request; + }; + + return search< + IKibanaSearchRequest, + IKibanaSearchResponse + >({ params }, { abortSignal, strategy: ESQL_SEARCH_STRATEGY }).pipe( + catchError((error) => { + if (!error.err) { + error.message = `Unexpected error from Elasticsearch: ${error.message}`; + } else { + const { type, reason } = error.err.attributes; + if (type === 'parsing_exception') { + error.message = `Couldn't parse Elasticsearch ES|QL query. You may need to add backticks to names containing special characters. Check your query and try again. Error: ${reason}`; + } else { + error.message = `Unexpected error from Elasticsearch: ${type} - ${reason}`; + } + } + + return throwError(() => error); + }), + tap({ + next({ rawResponse }) { + logInspectorRequest() + .stats({ + hits: { + label: i18n.translate('data.search.es_search.hitsLabel', { + defaultMessage: 'Hits', + }), + value: `${rawResponse.values.length}`, + description: i18n.translate('data.search.es_search.hitsDescription', { + defaultMessage: 'The number of documents returned by the query.', + }), + }, + }) + .json(params) + .ok({ json: rawResponse }); + }, + error(error) { + logInspectorRequest().error({ json: error }); + }, + }) + ); + }), + map(({ rawResponse: body, warning }) => { + const columns = + body.columns?.map(({ name, type }) => ({ + id: sanitize(name), + name: sanitize(name), + meta: { type: normalizeType(type) }, + })) ?? []; + const columnNames = columns.map(({ name }) => name); + const rows = body.values.map((row) => zipObject(columnNames, row)); + + return { + type: 'datatable', + meta: { + type: 'es_ql', + }, + columns, + rows, + warning, + } as Datatable; + }) + ); + }, + }; + + return essql; +}; diff --git a/src/plugins/data/common/search/index.ts b/src/plugins/data/common/search/index.ts index d0d103abe1ea2..50356da1a4655 100644 --- a/src/plugins/data/common/search/index.ts +++ b/src/plugins/data/common/search/index.ts @@ -18,3 +18,4 @@ export * from './strategies/es_search'; export * from './strategies/eql_search'; export * from './strategies/ese_search'; export * from './strategies/sql_search'; +export * from './strategies/esql_search'; diff --git a/src/plugins/data/common/search/poll_search.test.ts b/src/plugins/data/common/search/poll_search.test.ts index dbb8e5137de21..db39b5e187036 100644 --- a/src/plugins/data/common/search/poll_search.test.ts +++ b/src/plugins/data/common/search/poll_search.test.ts @@ -83,7 +83,7 @@ describe('pollSearch', () => { abortSignal: abortController.signal, }).toPromise(); - await new Promise((resolve) => setTimeout(resolve, 500)); + await new Promise((resolve) => setTimeout(resolve, 300)); abortController.abort(); await expect(poll).rejects.toThrow(AbortError); @@ -99,7 +99,7 @@ describe('pollSearch', () => { const cancelFn = jest.fn(); const subscription = pollSearch(searchFn, cancelFn).subscribe(() => {}); - await new Promise((resolve) => setTimeout(resolve, 500)); + await new Promise((resolve) => setTimeout(resolve, 300)); subscription.unsubscribe(); await new Promise((resolve) => setTimeout(resolve, 1000)); diff --git a/src/plugins/data/common/search/poll_search.ts b/src/plugins/data/common/search/poll_search.ts index a58fad3880c69..1a6819257ab67 100644 --- a/src/plugins/data/common/search/poll_search.ts +++ b/src/plugins/data/common/search/poll_search.ts @@ -22,6 +22,8 @@ export const pollSearch = ( else { // if static pollInterval is not provided, then use default back-off logic switch (true) { + case elapsedTime < 1500: + return 300; case elapsedTime < 5000: return 1000; case elapsedTime < 20000: diff --git a/src/plugins/data/common/search/search_source/search_source.ts b/src/plugins/data/common/search/search_source/search_source.ts index 91eea3e50f881..b74b7e111b5ce 100644 --- a/src/plugins/data/common/search/search_source/search_source.ts +++ b/src/plugins/data/common/search/search_source/search_source.ts @@ -918,8 +918,12 @@ export class SearchSource { }; body.query = buildEsQuery(index, query, filters, esQueryConfigs); - // For testing shard failure messages in UI, uncomment the next block and switch to `kibana*` data view - // body.query = { + // For testing shard failure messages in the UI, follow these steps: + // 1. Add all three sample data sets (flights, ecommerce, logs) to Kibana. + // 2. Create a data view using the index pattern `kibana*` and don't use a timestamp field. + // 3. Uncomment the lines below, navigate to Discover, + // and switch to the data view created in step 2. + // body.query.bool.must.push({ // error_query: { // indices: [ // { @@ -930,7 +934,8 @@ export class SearchSource { // }, // ], // }, - // }; + // }); + // Alternatively you could also add this query via "Edit as Query DSL", then it needs no code to be changed if (highlightAll && body.query) { body.highlight = getHighlightRequest(getConfig(UI_SETTINGS.DOC_HIGHLIGHT)); diff --git a/src/plugins/data/common/search/strategies/esql_search/index.ts b/src/plugins/data/common/search/strategies/esql_search/index.ts new file mode 100644 index 0000000000000..12594660136d8 --- /dev/null +++ b/src/plugins/data/common/search/strategies/esql_search/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './types'; diff --git a/src/plugins/discover/public/components/discover_grid/types.ts b/src/plugins/data/common/search/strategies/esql_search/types.ts similarity index 59% rename from src/plugins/discover/public/components/discover_grid/types.ts rename to src/plugins/data/common/search/strategies/esql_search/types.ts index 71d82e35126ac..d71da852e55de 100644 --- a/src/plugins/discover/public/components/discover_grid/types.ts +++ b/src/plugins/data/common/search/strategies/esql_search/types.ts @@ -6,13 +6,4 @@ * Side Public License, v 1. */ -/** - * User configurable state of data grid, persisted in saved search - */ -export interface DiscoverGridSettings { - columns?: Record; -} - -export interface DiscoverGridSettingsColumn { - width?: number; -} +export const ESQL_SEARCH_STRATEGY = 'esql'; diff --git a/src/plugins/data/config.ts b/src/plugins/data/config.ts index 688f65038aa11..03cd77653becb 100644 --- a/src/plugins/data/config.ts +++ b/src/plugins/data/config.ts @@ -55,7 +55,7 @@ export const searchConfigSchema = schema.object({ * Block and wait until the search is completed up to the timeout (see es async_search's `wait_for_completion_timeout`) * TODO: we should optimize this as 100ms is likely not optimal (https://github.com/elastic/kibana/issues/143277) */ - waitForCompletion: schema.duration({ defaultValue: '100ms' }), + waitForCompletion: schema.duration({ defaultValue: '200ms' }), /** * How long the async search needs to be available after each search poll. Ongoing async searches and any saved search results are deleted after this period. * (see es async_search's `keep_alive`) @@ -71,7 +71,7 @@ export const searchConfigSchema = schema.object({ * How long to wait before polling the async_search after the previous poll response. * If not provided, then default dynamic interval with backoff is used. */ - pollInterval: schema.maybe(schema.number({ min: 1000 })), + pollInterval: schema.maybe(schema.number({ min: 200 })), }), aggs: schema.object({ shardDelay: schema.object({ diff --git a/src/plugins/data/public/search/expressions/esql.ts b/src/plugins/data/public/search/expressions/esql.ts new file mode 100644 index 0000000000000..443d4c595c742 --- /dev/null +++ b/src/plugins/data/public/search/expressions/esql.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { StartServicesAccessor } from '@kbn/core/public'; +import { UiSettingsCommon } from '../../../common'; +import { DataPublicPluginStart, DataStartDependencies } from '../../types'; +import { getEsqlFn } from '../../../common/search/expressions/esql'; + +/** + * This is some glue code that takes in `core.getStartServices`, extracts the dependencies + * needed for this function, and wraps them behind a `getStartDependencies` function that + * is then called at runtime. + * + * We do this so that we can be explicit about exactly which dependencies the function + * requires, without cluttering up the top-level `plugin.ts` with this logic. It also + * makes testing the expression function a bit easier since `getStartDependencies` is + * the only thing you should need to mock. + * + * @param getStartServices - core's StartServicesAccessor for this plugin + * @internal + */ +export function getEsql({ + getStartServices, +}: { + getStartServices: StartServicesAccessor; +}) { + return getEsqlFn({ + async getStartDependencies() { + const [ + { uiSettings }, + , + { + nowProvider, + search: { search }, + }, + ] = await getStartServices(); + + return { nowProvider, search, uiSettings: uiSettings as unknown as UiSettingsCommon }; + }, + }); +} diff --git a/src/plugins/data/public/search/expressions/index.ts b/src/plugins/data/public/search/expressions/index.ts index cb07be49e8a62..74e947e2942bb 100644 --- a/src/plugins/data/public/search/expressions/index.ts +++ b/src/plugins/data/public/search/expressions/index.ts @@ -9,5 +9,6 @@ export * from './esaggs'; export * from './esdsl'; export * from './essql'; +export * from './esql'; export * from '../../../common/search/expressions'; export * from './eql'; diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 4a16d9487d2ea..79229eaff91bf 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -63,7 +63,7 @@ import { NowProviderInternalContract } from '../now_provider'; import { DataPublicPluginStart, DataStartDependencies } from '../types'; import { AggsService } from './aggs'; import { createUsageCollector, SearchUsageCollector } from './collectors'; -import { getEql, getEsaggs, getEsdsl, getEssql } from './expressions'; +import { getEql, getEsaggs, getEsdsl, getEssql, getEsql } from './expressions'; import { handleWarnings } from './fetch/handle_warnings'; import { ISearchInterceptor, SearchInterceptor } from './search_interceptor'; @@ -173,6 +173,11 @@ export class SearchService implements Plugin { getStartServices: StartServicesAccessor; }) ); + expressions.registerFunction( + getEsql({ getStartServices } as { + getStartServices: StartServicesAccessor; + }) + ); expressions.registerFunction( getEql({ getStartServices } as { getStartServices: StartServicesAccessor; diff --git a/src/plugins/data/server/search/expressions/esql.ts b/src/plugins/data/server/search/expressions/esql.ts new file mode 100644 index 0000000000000..93a4e136d88df --- /dev/null +++ b/src/plugins/data/server/search/expressions/esql.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 { StartServicesAccessor } from '@kbn/core/server'; +import { DataPluginStart, DataPluginStartDependencies } from '../../plugin'; +import { getEsqlFn } from '../../../common/search/expressions/esql'; + +/** + * This is some glue code that takes in `core.getStartServices`, extracts the dependencies + * needed for this function, and wraps them behind a `getStartDependencies` function that + * is then called at runtime. + * + * We do this so that we can be explicit about exactly which dependencies the function + * requires, without cluttering up the top-level `plugin.ts` with this logic. It also + * makes testing the expression function a bit easier since `getStartDependencies` is + * the only thing you should need to mock. + * + * @param getStartServices - core's StartServicesAccessor for this plugin + * @internal + */ +export function getEsql({ + getStartServices, +}: { + getStartServices: StartServicesAccessor; +}) { + return getEsqlFn({ + getStartDependencies: async (getKibanaRequest) => { + const [{ savedObjects, uiSettings }, , { search }] = await getStartServices(); + const request = getKibanaRequest(); + const savedObjectsClient = savedObjects.getScopedClient(request); + + return { + search: search.asScoped(request).search, + uiSettings: uiSettings.asScopedToClient(savedObjectsClient), + }; + }, + }); +} diff --git a/src/plugins/data/server/search/expressions/index.ts b/src/plugins/data/server/search/expressions/index.ts index 98a08e6383f34..e9a9ff316d137 100644 --- a/src/plugins/data/server/search/expressions/index.ts +++ b/src/plugins/data/server/search/expressions/index.ts @@ -9,4 +9,5 @@ export * from './esaggs'; export * from './esdsl'; export * from './essql'; +export * from './esql'; export * from './eql'; diff --git a/src/plugins/data/server/search/index.ts b/src/plugins/data/server/search/index.ts index 825b7eee3302f..f2cdc40594487 100644 --- a/src/plugins/data/server/search/index.ts +++ b/src/plugins/data/server/search/index.ts @@ -10,6 +10,7 @@ export * from './types'; export * from './strategies/es_search'; export * from './strategies/ese_search'; export * from './strategies/eql_search'; +export * from './strategies/esql_search'; export type { SearchUsage } from './collectors/search'; export { usageProvider, searchUsageObserver } from './collectors/search'; export * from './aggs'; diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index dd199403c53af..71a335ce51592 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -79,8 +79,9 @@ import { SearchSourceService, eqlRawResponse, SQL_SEARCH_STRATEGY, + ESQL_SEARCH_STRATEGY, } from '../../common/search'; -import { getEsaggs, getEsdsl, getEssql, getEql } from './expressions'; +import { getEsaggs, getEsdsl, getEssql, getEql, getEsql } from './expressions'; import { getShardDelayBucketAgg, SHARD_DELAY_AGG_NAME, @@ -95,6 +96,7 @@ import { NoSearchIdInSessionError } from './errors/no_search_id_in_session'; import { CachedUiSettingsClient } from './services'; import { sqlSearchStrategyProvider } from './strategies/sql_search'; import { searchSessionSavedObjectType } from './saved_objects'; +import { esqlSearchStrategyProvider } from './strategies/esql_search'; type StrategyMap = Record>; @@ -176,6 +178,7 @@ export class SearchService implements Plugin { usage ) ); + this.registerSearchStrategy(ESQL_SEARCH_STRATEGY, esqlSearchStrategyProvider(this.logger)); // We don't want to register this because we don't want the client to be able to access this // strategy, but we do want to expose it to other server-side plugins @@ -216,6 +219,7 @@ export class SearchService implements Plugin { expressions.registerFunction(getEsdsl({ getStartServices: core.getStartServices })); expressions.registerFunction(getEssql({ getStartServices: core.getStartServices })); expressions.registerFunction(getEql({ getStartServices: core.getStartServices })); + expressions.registerFunction(getEsql({ getStartServices: core.getStartServices })); expressions.registerFunction(cidrFunction); expressions.registerFunction(dateRangeFunction); expressions.registerFunction(extendedBoundsFunction); diff --git a/src/plugins/data/server/search/strategies/esql_search/esql_search_strategy.ts b/src/plugins/data/server/search/strategies/esql_search/esql_search_strategy.ts new file mode 100644 index 0000000000000..7f3f6f521853d --- /dev/null +++ b/src/plugins/data/server/search/strategies/esql_search/esql_search_strategy.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 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 { from } from 'rxjs'; +import type { Logger } from '@kbn/core/server'; +import { getKbnServerError, KbnServerError } from '@kbn/kibana-utils-plugin/server'; +import type { ISearchStrategy } from '../../types'; + +export const esqlSearchStrategyProvider = ( + logger: Logger, + useInternalUser: boolean = false +): ISearchStrategy => ({ + /** + * @param request + * @param options + * @param deps + * @throws `KbnServerError` + * @returns `Observable>` + */ + search: (request, { abortSignal, ...options }, { esClient, uiSettingsClient }) => { + // Only default index pattern type is supported here. + // See ese for other type support. + if (request.indexType) { + throw new KbnServerError(`Unsupported index pattern type ${request.indexType}`, 400); + } + + const search = async () => { + try { + const { terminateAfter, ...requestParams } = request.params ?? {}; + const { headers, body } = await esClient.asCurrentUser.transport.request( + { + method: 'POST', + path: '/_query', + body: { + ...requestParams, + }, + }, + { + signal: abortSignal, + meta: true, + } + ); + return { + rawResponse: body, + isPartial: false, + isRunning: false, + warning: headers?.warning, + }; + } catch (e) { + throw getKbnServerError(e); + } + }; + + return from(search()); + }, +}); diff --git a/src/plugins/data/server/search/strategies/esql_search/index.ts b/src/plugins/data/server/search/strategies/esql_search/index.ts new file mode 100644 index 0000000000000..14fd011acc3d8 --- /dev/null +++ b/src/plugins/data/server/search/strategies/esql_search/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 { esqlSearchStrategyProvider } from './esql_search_strategy'; diff --git a/src/plugins/discover/common/constants.ts b/src/plugins/discover/common/constants.ts index 3cb696766b65f..e80f9d2449ebc 100644 --- a/src/plugins/discover/common/constants.ts +++ b/src/plugins/discover/common/constants.ts @@ -6,12 +6,18 @@ * Side Public License, v 1. */ -export const MAX_LOADED_GRID_ROWS = 10000; +import { SAMPLE_ROWS_PER_PAGE_SETTING } from '@kbn/discover-utils'; +import { IUiSettingsClient } from '@kbn/core/public'; + export const DEFAULT_ROWS_PER_PAGE = 100; export const ROWS_PER_PAGE_OPTIONS = [10, 25, 50, DEFAULT_ROWS_PER_PAGE, 250, 500]; + export enum VIEW_MODE { DOCUMENT_LEVEL = 'documents', AGGREGATED_LEVEL = 'aggregated', } export const DISABLE_SHARD_FAILURE_WARNING = true; +export const getDefaultRowsPerPage = (uiSettings: IUiSettingsClient): number => { + return parseInt(uiSettings.get(SAMPLE_ROWS_PER_PAGE_SETTING), 10) || DEFAULT_ROWS_PER_PAGE; +}; diff --git a/src/plugins/discover/public/__mocks__/saved_search.ts b/src/plugins/discover/public/__mocks__/saved_search.ts index c6751b2990bc4..90a2a9c680825 100644 --- a/src/plugins/discover/public/__mocks__/saved_search.ts +++ b/src/plugins/discover/public/__mocks__/saved_search.ts @@ -27,11 +27,11 @@ export const savedSearchMockWithTimeFieldNew = { searchSource: createSearchSourceMock({ index: dataViewWithTimefieldMock }), } as unknown as SavedSearch; -export const savedSearchMockWithSQL = { - id: 'the-saved-search-id-sql', +export const savedSearchMockWithESQL = { + id: 'the-saved-search-id-esql', searchSource: createSearchSourceMock({ index: dataViewWithTimefieldMock, - query: { sql: 'SELECT * FROM "the-saved-search-id-sql"' }, + query: { esql: 'FROM "the-saved-search-id-esql"' }, }), } as unknown as SavedSearch; diff --git a/src/plugins/discover/public/application/context/context_app.tsx b/src/plugins/discover/public/application/context/context_app.tsx index c11a9187a937f..19a5058638392 100644 --- a/src/plugins/discover/public/application/context/context_app.tsx +++ b/src/plugins/discover/public/application/context/context_app.tsx @@ -18,15 +18,18 @@ import { generateFilters } from '@kbn/data-plugin/public'; import { i18n } from '@kbn/i18n'; import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; import { removeInterceptedWarningDuplicates } from '@kbn/search-response-warnings'; -import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { + DOC_TABLE_LEGACY, + SEARCH_FIELDS_FROM_SOURCE, + SORT_DEFAULT_ORDER_SETTING, +} from '@kbn/discover-utils'; +import { popularizeField, useColumns } from '@kbn/unified-data-table'; +import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import { ContextErrorMessage } from './components/context_error_message'; import { LoadingStatus } from './services/context_query_state'; import { AppState, GlobalState, isEqualFilters } from './services/context_state'; -import { useColumns } from '../../hooks/use_data_grid_columns'; import { useContextAppState } from './hooks/use_context_app_state'; import { useContextAppFetch } from './hooks/use_context_app_fetch'; -import { popularizeField } from '../../utils/popularize_field'; import { ContextAppContent } from './context_app_content'; import { SurrDocType } from './services/context'; import { useDiscoverServices } from '../../hooks/use_discover_services'; @@ -68,7 +71,7 @@ export const ContextApp = ({ dataView, anchorId, referrer }: ContextAppProps) => const { columns, onAddColumn, onRemoveColumn, onSetColumns } = useColumns({ capabilities, - config: uiSettings, + defaultOrder: uiSettings.get(SORT_DEFAULT_ORDER_SETTING), dataView, dataViews, useNewFieldsApi, diff --git a/src/plugins/discover/public/application/context/context_app_content.test.tsx b/src/plugins/discover/public/application/context/context_app_content.test.tsx index f7ce2235333d4..f6809d63c035d 100644 --- a/src/plugins/discover/public/application/context/context_app_content.test.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.test.tsx @@ -12,11 +12,11 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { ActionBar } from './components/action_bar/action_bar'; import { GetStateReturn } from './services/context_state'; import { SortDirection } from '@kbn/data-plugin/public'; +import { UnifiedDataTable } from '@kbn/unified-data-table'; import { ContextAppContent, ContextAppContentProps } from './context_app_content'; import { LoadingStatus } from './services/context_query_state'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; import { discoverServiceMock } from '../../__mocks__/services'; -import { DiscoverGrid } from '../../components/discover_grid/discover_grid'; import { DocTableWrapper } from '../../components/doc_table/doc_table_wrapper'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { buildDataTableRecord } from '@kbn/discover-utils'; @@ -103,6 +103,6 @@ describe('ContextAppContent test', () => { it('should render discover grid correctly', async () => { const component = await mountComponent({ isLegacy: false }); - expect(component.find(DiscoverGrid).length).toBe(1); + expect(component.find(UnifiedDataTable).length).toBe(1); }); }); diff --git a/src/plugins/discover/public/application/context/context_app_content.tsx b/src/plugins/discover/public/application/context/context_app_content.tsx index 7e07a594e53c6..0443718be6e2b 100644 --- a/src/plugins/discover/public/application/context/context_app_content.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.tsx @@ -18,17 +18,25 @@ import { type SearchResponseInterceptedWarning, SearchResponseWarnings, } from '@kbn/search-response-warnings'; -import { CONTEXT_STEP_SETTING, DOC_HIDE_TIME_COLUMN_SETTING } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { + CONTEXT_STEP_SETTING, + DOC_HIDE_TIME_COLUMN_SETTING, + MAX_DOC_FIELDS_DISPLAYED, + ROW_HEIGHT_OPTION, + SHOW_MULTIFIELDS, +} from '@kbn/discover-utils'; +import { DataLoadingState, UnifiedDataTable } from '@kbn/unified-data-table'; +import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { getDefaultRowsPerPage } from '../../../common/constants'; import { LoadingStatus } from './services/context_query_state'; import { ActionBar } from './components/action_bar/action_bar'; -import { DataLoadingState, DiscoverGrid } from '../../components/discover_grid/discover_grid'; import { AppState } from './services/context_state'; import { SurrDocType } from './services/context'; import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from './services/constants'; import { DocTableContext } from '../../components/doc_table/doc_table_context'; import { useDiscoverServices } from '../../hooks/use_discover_services'; -import { DiscoverGridFlyout } from '../../components/discover_grid/discover_grid_flyout'; +import { DiscoverGridFlyout } from '../../components/discover_grid_flyout'; +import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../../components/discover_tour'; export interface ContextAppContentProps { columns: string[]; @@ -57,7 +65,7 @@ export function clamp(value: number) { return Math.max(Math.min(MAX_CONTEXT_SIZE, value), MIN_CONTEXT_SIZE); } -const DiscoverGridMemoized = React.memo(DiscoverGrid); +const DiscoverGridMemoized = React.memo(UnifiedDataTable); const DocTableContextMemoized = React.memo(DocTableContext); const ActionBarMemoized = React.memo(ActionBar); @@ -121,6 +129,24 @@ export function ContextAppContent({ return [[dataView.timeFieldName!, SortDirection.desc]]; }, [dataView]); + const renderDocumentView = useCallback( + (hit: DataTableRecord, displayedRows: DataTableRecord[], displayedColumns: string[]) => ( + setExpandedDoc(undefined)} + setExpandedDoc={setExpandedDoc} + /> + ), + [addFilter, dataView, onAddColumn, onRemoveColumn] + ); + return ( {!!interceptedWarnings?.length && ( @@ -174,14 +200,17 @@ export function ContextAppContent({ showTimeCol={showTimeCol} useNewFieldsApi={useNewFieldsApi} isPaginationEnabled={false} + rowsPerPageState={getDefaultRowsPerPage(services.uiSettings)} controlColumnIds={controlColumnIds} setExpandedDoc={setExpandedDoc} onFilter={addFilter} - onAddColumn={onAddColumn} - onRemoveColumn={onRemoveColumn} onSetColumns={onSetColumns} - DocumentView={DiscoverGridFlyout} + configRowHeight={services.uiSettings.get(ROW_HEIGHT_OPTION)} + showMultiFields={services.uiSettings.get(SHOW_MULTIFIELDS)} + maxDocFieldsDisplayed={services.uiSettings.get(MAX_DOC_FIELDS_DISPLAYED)} + renderDocumentView={renderDocumentView} services={services} + componentsTourSteps={{ expandButton: DISCOVER_TOUR_STEP_ANCHOR_IDS.expandDocument }} />
diff --git a/src/plugins/discover/public/application/main/components/layout/__stories__/discover_layout.stories.tsx b/src/plugins/discover/public/application/main/components/layout/__stories__/discover_layout.stories.tsx index 80db81bb4228b..4e143c80d96db 100644 --- a/src/plugins/discover/public/application/main/components/layout/__stories__/discover_layout.stories.tsx +++ b/src/plugins/discover/public/application/main/components/layout/__stories__/discover_layout.stories.tsx @@ -68,7 +68,7 @@ storiesOf('components/layout/DiscoverLayout', module).add( ); storiesOf('components/layout/DiscoverLayout', module).add( - 'SQL view', + 'ES|QL view', withDiscoverServices(() => { const props = getPlainRecordLayoutProps(getDataViewMock(false)); return ( diff --git a/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts b/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts index 8d95db014fdc8..d681365767ce8 100644 --- a/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts +++ b/src/plugins/discover/public/application/main/components/layout/__stories__/get_layout_props.ts @@ -159,7 +159,7 @@ export const getPlainRecordLayoutProps = (dataView: DataView) => { columns: ['name', 'message', 'bytes'], sort: [['date', 'desc']], query: { - sql: 'SELECT * FROM "kibana_sample_data_ecommerce"', + esql: 'FROM "kibana_sample_data_ecommerce"', }, filters: [], }); diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx index 5019c3e135acc..ec809e2c2f760 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx @@ -21,29 +21,36 @@ import { SortOrder } from '@kbn/saved-search-plugin/public'; import { CellActionsProvider } from '@kbn/cell-actions'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { SearchResponseWarnings } from '@kbn/search-response-warnings'; +import { DataLoadingState, UnifiedDataTable, useColumns } from '@kbn/unified-data-table'; import { DOC_HIDE_TIME_COLUMN_SETTING, DOC_TABLE_LEGACY, HIDE_ANNOUNCEMENTS, + MAX_DOC_FIELDS_DISPLAYED, + ROW_HEIGHT_OPTION, SAMPLE_SIZE_SETTING, SEARCH_FIELDS_FROM_SOURCE, + SHOW_MULTIFIELDS, + SORT_DEFAULT_ORDER_SETTING, } from '@kbn/discover-utils'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { getDefaultRowsPerPage } from '../../../../../common/constants'; import { useInternalStateSelector } from '../../services/discover_internal_state_container'; import { useAppStateSelector } from '../../services/discover_app_state_container'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; -import { DataLoadingState, DiscoverGrid } from '../../../../components/discover_grid/discover_grid'; import { FetchStatus } from '../../../types'; -import { useColumns } from '../../../../hooks/use_data_grid_columns'; import { RecordRawType } from '../../services/discover_data_state_container'; import { DiscoverStateContainer } from '../../services/discover_state'; import { useDataState } from '../../hooks/use_data_state'; import { DocTableInfinite } from '../../../../components/doc_table/doc_table_infinite'; import { DocumentExplorerCallout } from '../document_explorer_callout'; import { DocumentExplorerUpdateCallout } from '../document_explorer_callout/document_explorer_update_callout'; -import { DiscoverTourProvider } from '../../../../components/discover_tour'; +import { + DISCOVER_TOUR_STEP_ANCHOR_IDS, + DiscoverTourProvider, +} from '../../../../components/discover_tour'; import { getRawRecordType } from '../../utils/get_raw_record_type'; -import { DiscoverGridFlyout } from '../../../../components/discover_grid/discover_grid_flyout'; +import { DiscoverGridFlyout } from '../../../../components/discover_grid_flyout'; import { useSavedSearchInitial } from '../../services/discover_state_provider'; import { useFetchMoreRecords } from './use_fetch_more_records'; @@ -56,7 +63,7 @@ const progressStyle = css` `; const DocTableInfiniteMemoized = React.memo(DocTableInfinite); -const DiscoverGridMemoized = React.memo(DiscoverGrid); +const DataGridMemoized = React.memo(UnifiedDataTable); // export needs for testing export const onResize = ( @@ -147,7 +154,7 @@ function DiscoverDocumentsComponent({ onSetColumns, } = useColumns({ capabilities, - config: uiSettings, + defaultOrder: uiSettings.get(SORT_DEFAULT_ORDER_SETTING), dataView, dataViews, setAppState: stateContainer.appState.update, @@ -184,10 +191,31 @@ function DiscoverDocumentsComponent({ const showTimeCol = useMemo( () => - !isTextBasedQuery && + // for ES|QL we want to show the time column only when is on Document view + (!isTextBasedQuery || !columns?.length) && !uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false) && !!dataView.timeFieldName, - [isTextBasedQuery, uiSettings, dataView.timeFieldName] + [isTextBasedQuery, columns, uiSettings, dataView.timeFieldName] + ); + + const renderDocumentView = useCallback( + (hit: DataTableRecord, displayedRows: DataTableRecord[], displayedColumns: string[]) => ( + setExpandedDoc(undefined)} + setExpandedDoc={setExpandedDoc} + query={query} + /> + ), + [dataView, onAddColumn, onAddFilter, onRemoveColumn, query, savedSearch.id, setExpandedDoc] ); if (isDataViewLoading || (isEmptyDataResult && isDataLoading)) { @@ -216,7 +244,7 @@ function DiscoverDocumentsComponent({ data-test-subj="dscInterceptedWarningsCallout" /> )} - {isLegacy && rows && rows.length && ( + {isLegacy && rows && rows.length > 0 && ( <> {!hideAnnouncements && } )} -
+
-
diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 550be02a6733d..58c23aa561e12 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -23,8 +23,13 @@ import classNames from 'classnames'; import { generateFilters } from '@kbn/data-plugin/public'; import { useDragDropContext } from '@kbn/dom-drag-drop'; import { DataViewField, DataViewType } from '@kbn/data-views-plugin/public'; -import { SEARCH_FIELDS_FROM_SOURCE, SHOW_FIELD_STATISTICS } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; +import { + SEARCH_FIELDS_FROM_SOURCE, + SHOW_FIELD_STATISTICS, + SORT_DEFAULT_ORDER_SETTING, +} from '@kbn/discover-utils'; +import { popularizeField, useColumns } from '@kbn/unified-data-table'; +import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import { useSavedSearchInitial } from '../../services/discover_state_provider'; import { DiscoverStateContainer } from '../../services/discover_state'; import { VIEW_MODE } from '../../../../../common/constants'; @@ -35,12 +40,10 @@ import { useDiscoverServices } from '../../../../hooks/use_discover_services'; import { DiscoverNoResults } from '../no_results'; import { LoadingSpinner } from '../loading_spinner/loading_spinner'; import { DiscoverSidebarResponsive } from '../sidebar'; -import { popularizeField } from '../../../../utils/popularize_field'; import { DiscoverTopNav } from '../top_nav/discover_topnav'; import { getResultState } from '../../utils/get_result_state'; import { DiscoverUninitialized } from '../uninitialized/uninitialized'; import { DataMainMsg, RecordRawType } from '../../services/discover_data_state_container'; -import { useColumns } from '../../../../hooks/use_data_grid_columns'; import { FetchStatus } from '../../../types'; import { useDataState } from '../../hooks/use_data_state'; import { getRawRecordType } from '../../utils/get_raw_record_type'; @@ -127,7 +130,7 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { onRemoveColumn, } = useColumns({ capabilities, - config: uiSettings, + defaultOrder: uiSettings.get(SORT_DEFAULT_ORDER_SETTING), dataView, dataViews, setAppState: stateContainer.appState.update, @@ -175,6 +178,13 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { }, [isSidebarClosed, storage]); const contentCentered = resultState === 'uninitialized' || resultState === 'none'; + const documentState = useDataState(stateContainer.dataState.data$.documents$); + + const textBasedLanguageModeWarning = useMemo(() => { + if (isPlainRecord) { + return documentState.textBasedHeaderWarning; + } + }, [documentState.textBasedHeaderWarning, isPlainRecord]); const textBasedLanguageModeErrors = useMemo(() => { if (isPlainRecord) { @@ -255,6 +265,7 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { updateQuery={stateContainer.actions.onUpdateQuery} isPlainRecord={isPlainRecord} textBasedLanguageModeErrors={textBasedLanguageModeErrors} + textBasedLanguageModeWarning={textBasedLanguageModeWarning} onFieldEdited={onFieldEdited} /> diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx index 6be8266691089..1f8ffa8b655ce 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.test.tsx @@ -497,7 +497,7 @@ describe('discover responsive sidebar', function () { expect(findTestSubject(comp, 'dataView-add-field_btn').length).toBe(1); }); - it('should render correctly in the sql mode', async () => { + it('should render correctly in the ES|QL mode', async () => { const propsWithTextBasedMode = { ...props, columns: ['extension', 'bytes'], @@ -514,7 +514,7 @@ describe('discover responsive sidebar', function () { }) as DataDocuments$, }; const compInTextBasedMode = await mountComponent(propsWithTextBasedMode, { - query: { sql: 'SELECT * FROM `index`' }, + query: { esql: 'FROM `index`' }, }); await act(async () => { diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx index 66f566cff1673..a743d4c1abebd 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import type { Query, TimeRange, AggregateQuery } from '@kbn/es-query'; import { DataViewType, type DataView } from '@kbn/data-views-plugin/public'; import type { DataViewPickerProps } from '@kbn/unified-search-plugin/public'; -import { ENABLE_SQL } from '@kbn/discover-utils'; +import { ENABLE_ESQL } from '@kbn/discover-utils'; import { useSavedSearchInitial } from '../../services/discover_state_provider'; import { useInternalStateSelector } from '../../services/discover_internal_state_container'; import { useDiscoverServices } from '../../../../hooks/use_discover_services'; @@ -31,6 +31,7 @@ export interface DiscoverTopNavProps { stateContainer: DiscoverStateContainer; isPlainRecord: boolean; textBasedLanguageModeErrors?: Error; + textBasedLanguageModeWarning?: string; onFieldEdited: () => Promise; } @@ -42,6 +43,7 @@ export const DiscoverTopNav = ({ updateQuery, isPlainRecord, textBasedLanguageModeErrors, + textBasedLanguageModeWarning, onFieldEdited, }: DiscoverTopNavProps) => { const adHocDataViews = useInternalStateSelector((state) => state.adHocDataViews); @@ -164,10 +166,10 @@ export const DiscoverTopNav = ({ const setMenuMountPoint = useMemo(() => { return getHeaderActionMenuMounter(); }, []); - const isSQLModeEnabled = uiSettings.get(ENABLE_SQL); + const isESQLModeEnabled = uiSettings.get(ENABLE_ESQL); const supportedTextBasedLanguages = []; - if (isSQLModeEnabled) { - supportedTextBasedLanguages.push('SQL'); + if (isESQLModeEnabled) { + supportedTextBasedLanguages.push('ESQL'); } const dataViewPickerProps: DataViewPickerProps = { trigger: { @@ -233,6 +235,7 @@ export const DiscoverTopNav = ({ textBasedLanguageModeErrors={ textBasedLanguageModeErrors ? [textBasedLanguageModeErrors] : undefined } + textBasedLanguageModeWarning={textBasedLanguageModeWarning} onTextBasedSavedAndExit={onTextBasedSavedAndExit} prependFilterBar={ searchBarCustomization?.PrependFilterBar ? ( diff --git a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.test.ts b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.test.ts index 44cf4c503be30..4e3e7068f883d 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.test.ts +++ b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.test.ts @@ -74,7 +74,7 @@ test('getTopNavLinks result', () => { `); }); -test('getTopNavLinks result for sql mode', () => { +test('getTopNavLinks result for ES|QL mode', () => { const topNavLinks = getTopNavLinks({ dataView: dataViewMock, onOpenInspector: jest.fn(), diff --git a/src/plugins/discover/public/application/main/hooks/use_test_based_query_language.test.tsx b/src/plugins/discover/public/application/main/hooks/use_test_based_query_language.test.tsx index 125d47c087640..edacd4ba3976e 100644 --- a/src/plugins/discover/public/application/main/hooks/use_test_based_query_language.test.tsx +++ b/src/plugins/discover/public/application/main/hooks/use_test_based_query_language.test.tsx @@ -50,7 +50,7 @@ function getHookProps( replaceUrlState, }; } -const query = { sql: 'SELECT * from the-data-view-title' }; +const query = { esql: 'from the-data-view-title' }; const msgComplete = { recordRawType: RecordRawType.PLAIN, fetchStatus: FetchStatus.PARTIAL, @@ -103,19 +103,16 @@ describe('useTextBasedQueryLanguage', () => { const { replaceUrlState, stateContainer } = renderHookWithContext(true); await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); - expect(replaceUrlState).toHaveBeenCalledWith({ index: 'the-data-view-id' }); - - replaceUrlState.mockReset(); - - stateContainer.dataState.data$.documents$.next(msgComplete); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); - await waitFor(() => { expect(replaceUrlState).toHaveBeenCalledWith({ index: 'the-data-view-id', - columns: ['field1', 'field2'], }); }); + + replaceUrlState.mockReset(); + + stateContainer.dataState.data$.documents$.next(msgComplete); + expect(replaceUrlState).toHaveBeenCalledTimes(0); }); test('should change viewMode to DOCUMENT_LEVEL if it was AGGREGATED_LEVEL', async () => { const { replaceUrlState } = renderHookWithContext(false, { @@ -132,7 +129,7 @@ describe('useTextBasedQueryLanguage', () => { const { replaceUrlState, stateContainer } = renderHookWithContext(false); const documents$ = stateContainer.dataState.data$.documents$; stateContainer.dataState.data$.documents$.next(msgComplete); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); replaceUrlState.mockReset(); documents$.next({ @@ -145,7 +142,7 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title' }, + query: { esql: 'from the-data-view-title | keep field1' }, }); await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); @@ -162,7 +159,7 @@ describe('useTextBasedQueryLanguage', () => { const documents$ = stateContainer.dataState.data$.documents$; documents$.next(msgComplete); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); replaceUrlState.mockReset(); documents$.next({ @@ -175,7 +172,7 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title' }, + query: { esql: 'from the-data-view-title | keep field1' }, }); await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); replaceUrlState.mockReset(); @@ -190,17 +187,17 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title WHERE field1=1' }, + query: { esql: 'from the-data-view-title | keep field 1 | WHERE field1=1' }, }); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(0)); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); }); test('if its not a text based query coming along, it should be ignored', async () => { const { replaceUrlState, stateContainer } = renderHookWithContext(false); const documents$ = stateContainer.dataState.data$.documents$; documents$.next(msgComplete); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); replaceUrlState.mockReset(); documents$.next({ @@ -225,7 +222,7 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title WHERE field1=1' }, + query: { esql: 'from the-data-view-title | keep field 1 | WHERE field1=1' }, }); await waitFor(() => { @@ -253,7 +250,7 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title WHERE field1=1' }, + query: { esql: 'from the-data-view-title | keep field 1 | WHERE field1=1' }, }); documents$.next({ @@ -266,9 +263,9 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title' }, + query: { esql: 'from the-data-view-title | keep field1' }, }); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); expect(replaceUrlState).toHaveBeenCalledWith({ columns: ['field1'], }); @@ -284,9 +281,9 @@ describe('useTextBasedQueryLanguage', () => { documents$.next({ recordRawType: RecordRawType.PLAIN, fetchStatus: FetchStatus.LOADING, - query: { sql: 'SELECT * from the-data-view-title WHERE field1=2' }, + query: { esql: 'from the-data-view-title | WHERE field1=2' }, }); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); + expect(replaceUrlState).toHaveBeenCalledTimes(0); documents$.next({ recordRawType: RecordRawType.PLAIN, fetchStatus: FetchStatus.PARTIAL, @@ -297,9 +294,9 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT * from the-data-view-title WHERE field1=2' }, + query: { esql: 'from the-data-view-title | WHERE field1=2' }, }); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(2)); + expect(replaceUrlState).toHaveBeenCalledTimes(0); stateContainer.appState.getState = jest.fn(() => { return { columns: ['field1', 'field2'], index: 'the-data-view-id' }; }); @@ -308,7 +305,7 @@ describe('useTextBasedQueryLanguage', () => { documents$.next({ recordRawType: RecordRawType.PLAIN, fetchStatus: FetchStatus.LOADING, - query: { sql: 'SELECT field1; from the-data-view-title WHERE field1=2' }, + query: { esql: 'from the-data-view-title | keep field 1; | WHERE field1=2' }, }); documents$.next({ @@ -319,7 +316,7 @@ describe('useTextBasedQueryLanguage', () => { documents$.next({ recordRawType: RecordRawType.PLAIN, fetchStatus: FetchStatus.LOADING, - query: { sql: 'SELECT field1 from the-data-view-title' }, + query: { esql: 'from the-data-view-title | keep field1' }, }); documents$.next({ @@ -332,7 +329,7 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-title' }, + query: { esql: 'from the-data-view-title | keep field1' }, }); await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); @@ -350,7 +347,7 @@ describe('useTextBasedQueryLanguage', () => { renderHook(() => useTextBasedQueryLanguage(props), { wrapper: getHookContext(stateContainer) }); documents$.next(msgComplete); - await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); replaceUrlState.mockReset(); documents$.next({ @@ -363,7 +360,7 @@ describe('useTextBasedQueryLanguage', () => { flattened: { field1: 1 }, } as unknown as DataTableRecord, ], - query: { sql: 'SELECT field1 from the-data-view-*' }, + query: { esql: 'from the-data-view-* | keep field1' }, }); props.stateContainer.actions.setDataView(dataViewAdHoc); await waitFor(() => expect(replaceUrlState).toHaveBeenCalledTimes(1)); diff --git a/src/plugins/discover/public/application/main/hooks/use_text_based_query_language.ts b/src/plugins/discover/public/application/main/hooks/use_text_based_query_language.ts index 4939049ceedda..fb3725d12b1e1 100644 --- a/src/plugins/discover/public/application/main/hooks/use_text_based_query_language.ts +++ b/src/plugins/discover/public/application/main/hooks/use_text_based_query_language.ts @@ -6,12 +6,7 @@ * Side Public License, v 1. */ import { isEqual } from 'lodash'; -import { - isOfAggregateQueryType, - getIndexPatternFromSQLQuery, - AggregateQuery, - Query, -} from '@kbn/es-query'; +import { isOfAggregateQueryType, getAggregateQueryMode } from '@kbn/es-query'; import { useCallback, useEffect, useRef } from 'react'; import type { DataViewsContract } from '@kbn/data-views-plugin/public'; import { VIEW_MODE } from '@kbn/saved-search-plugin/public'; @@ -21,6 +16,8 @@ import { getValidViewMode } from '../utils/get_valid_view_mode'; import { FetchStatus } from '../../types'; const MAX_NUM_OF_COLUMNS = 50; +// For ES|QL we want in case of the following commands to display a table view, otherwise display a document view +const TRANSFORMATIONAL_COMMANDS = ['stats', 'project', 'keep']; /** * Hook to take care of text based query language state transformations when a new result is returned @@ -33,11 +30,14 @@ export function useTextBasedQueryLanguage({ stateContainer: DiscoverStateContainer; dataViews: DataViewsContract; }) { - const prev = useRef<{ query: AggregateQuery | Query | undefined; columns: string[] }>({ + const prev = useRef<{ + query: string; + columns: string[]; + }>({ columns: [], - query: undefined, + query: '', }); - const indexTitle = useRef(''); + const initialFetch = useRef(true); const savedSearch = useSavedSearchInitial(); const cleanup = useCallback(() => { @@ -45,9 +45,8 @@ export function useTextBasedQueryLanguage({ // cleanup when it's not a text based query lang prev.current = { columns: [], - query: undefined, + query: '', }; - indexTitle.current = ''; } }, []); @@ -63,51 +62,60 @@ export function useTextBasedQueryLanguage({ fetchStatus: FetchStatus.COMPLETE, }); }; - const { columns: stateColumns, index, viewMode } = stateContainer.appState.getState(); + const { index, viewMode } = stateContainer.appState.getState(); let nextColumns: string[] = []; const isTextBasedQueryLang = - recordRawType === 'plain' && isOfAggregateQueryType(query) && 'sql' in query; + recordRawType === 'plain' && + isOfAggregateQueryType(query) && + ('sql' in query || 'esql' in query); const hasResults = Boolean(next.result?.length); - const initialFetch = !prev.current.columns.length; + let queryHasTransformationalCommands = 'sql' in query; + if ('esql' in query) { + TRANSFORMATIONAL_COMMANDS.forEach((command: string) => { + if (query.esql.toLowerCase().includes(command)) { + queryHasTransformationalCommands = true; + return; + } + }); + } if (isTextBasedQueryLang) { + const language = getAggregateQueryMode(query); if (next.fetchStatus !== FetchStatus.PARTIAL) { return; } + const dataViewObj = stateContainer.internalState.getState().dataView!; + if (hasResults) { // check if state needs to contain column transformation due to a different columns in the resultset const firstRow = next.result![0]; const firstRowColumns = Object.keys(firstRow.raw).slice(0, MAX_NUM_OF_COLUMNS); - if ( - !isEqual(firstRowColumns, prev.current.columns) && - !isEqual(query, prev.current.query) - ) { - prev.current = { columns: firstRowColumns, query }; + if (!queryHasTransformationalCommands) { + nextColumns = []; + initialFetch.current = false; + } else { nextColumns = firstRowColumns; - } - - if (firstRowColumns && initialFetch) { - prev.current = { columns: firstRowColumns, query }; + if ( + initialFetch.current && + !prev.current.columns.length && + Boolean(dataViewObj?.id === index) + ) { + prev.current.columns = firstRowColumns; + } } } - const indexPatternFromQuery = getIndexPatternFromSQLQuery(query.sql); - - const dataViewObj = stateContainer.internalState.getState().dataView!; - - // don't set the columns on initial fetch, to prevent overwriting existing state - const addColumnsToState = Boolean( - nextColumns.length && (!initialFetch || !stateColumns?.length) - ); + const addColumnsToState = !isEqual(nextColumns, prev.current.columns); + const queryChanged = query[language] !== prev.current.query; // no need to reset index to state if it hasn't changed - const addDataViewToState = Boolean(dataViewObj?.id !== index) || initialFetch; - const queryChanged = indexPatternFromQuery !== indexTitle.current; - if (!addColumnsToState && !queryChanged) { + const addDataViewToState = Boolean(dataViewObj?.id !== index); + if (!queryChanged || (!addDataViewToState && !addColumnsToState)) { sendComplete(); return; } if (queryChanged) { - indexTitle.current = indexPatternFromQuery; + prev.current.query = query[language]; + prev.current.columns = nextColumns; } const nextState = { ...(addDataViewToState && { index: dataViewObj.id }), diff --git a/src/plugins/discover/public/application/main/services/discover_app_state_container.ts b/src/plugins/discover/public/application/main/services/discover_app_state_container.ts index ea2d1d1f2324a..47cd216b1547e 100644 --- a/src/plugins/discover/public/application/main/services/discover_app_state_container.ts +++ b/src/plugins/discover/public/application/main/services/discover_app_state_container.ts @@ -23,12 +23,12 @@ import { SavedSearch, VIEW_MODE } from '@kbn/saved-search-plugin/public'; import { IKbnUrlStateStorage, ISyncStateRef, syncState } from '@kbn/kibana-utils-plugin/public'; import { isEqual } from 'lodash'; import { connectToQueryState, syncGlobalQueryStateWithUrl } from '@kbn/data-plugin/public'; +import type { UnifiedDataTableSettings } from '@kbn/unified-data-table'; import type { DiscoverServices } from '../../../build_services'; import { addLog } from '../../../utils/add_log'; import { cleanupUrlState } from '../utils/cleanup_url_state'; import { getStateDefaults } from '../utils/get_state_defaults'; import { handleSourceColumnState } from '../../../utils/state_helpers'; -import type { DiscoverGridSettings } from '../../../components/discover_grid/types'; export const APP_STATE_URL_KEY = '_a'; export interface DiscoverAppStateContainer extends ReduxLikeStateContainer { @@ -87,7 +87,7 @@ export interface DiscoverAppState { /** * Data Grid related state */ - grid?: DiscoverGridSettings; + grid?: UnifiedDataTableSettings; /** * Hide chart */ diff --git a/src/plugins/discover/public/application/main/services/discover_data_state_container.test.ts b/src/plugins/discover/public/application/main/services/discover_data_state_container.test.ts index d3f600dcfaff8..516d81cc9c3f0 100644 --- a/src/plugins/discover/public/application/main/services/discover_data_state_container.test.ts +++ b/src/plugins/discover/public/application/main/services/discover_data_state_container.test.ts @@ -10,7 +10,7 @@ import { waitFor } from '@testing-library/react'; import { buildDataTableRecord } from '@kbn/discover-utils'; import { dataViewMock, esHitsMockWithSort } from '@kbn/discover-utils/src/__mocks__'; import { discoverServiceMock } from '../../../__mocks__/services'; -import { savedSearchMockWithSQL } from '../../../__mocks__/saved_search'; +import { savedSearchMockWithESQL } from '../../../__mocks__/saved_search'; import { FetchStatus } from '../../types'; import { setUrlTracker } from '../../../kibana_services'; import { urlTrackerMock } from '../../../__mocks__/url_tracker.mock'; @@ -104,10 +104,10 @@ describe('test getDataStateContainer', () => { test('useSavedSearch returns plain record raw type', async () => { const stateContainer = getDiscoverStateMock({ - savedSearch: savedSearchMockWithSQL, + savedSearch: savedSearchMockWithESQL, }); - stateContainer.savedSearchState.load = jest.fn().mockResolvedValue(savedSearchMockWithSQL); - await stateContainer.actions.loadSavedSearch({ savedSearchId: savedSearchMockWithSQL.id }); + stateContainer.savedSearchState.load = jest.fn().mockResolvedValue(savedSearchMockWithESQL); + await stateContainer.actions.loadSavedSearch({ savedSearchId: savedSearchMockWithESQL.id }); expect(stateContainer.dataState.data$.main$.getValue().recordRawType).toBe(RecordRawType.PLAIN); }); diff --git a/src/plugins/discover/public/application/main/services/discover_data_state_container.ts b/src/plugins/discover/public/application/main/services/discover_data_state_container.ts index f243d9884ca9e..417fa6679501b 100644 --- a/src/plugins/discover/public/application/main/services/discover_data_state_container.ts +++ b/src/plugins/discover/public/application/main/services/discover_data_state_container.ts @@ -57,7 +57,7 @@ export enum RecordRawType { */ DOCUMENT = 'document', /** - * Data returned e.g. SQL queries, flat structure + * Data returned e.g. ES|QL queries, flat structure * */ PLAIN = 'plain', } @@ -78,6 +78,7 @@ export interface DataMainMsg extends DataMsg { export interface DataDocumentsMsg extends DataMsg { result?: DataTableRecord[]; textBasedQueryColumns?: DatatableColumn[]; // columns from text-based request + textBasedHeaderWarning?: string; interceptedWarnings?: SearchResponseInterceptedWarning[]; // warnings (like shard failures) } diff --git a/src/plugins/discover/public/application/main/services/discover_state.test.ts b/src/plugins/discover/public/application/main/services/discover_state.test.ts index f402988942a10..bcd96315ce575 100644 --- a/src/plugins/discover/public/application/main/services/discover_state.test.ts +++ b/src/plugins/discover/public/application/main/services/discover_state.test.ts @@ -468,8 +468,8 @@ describe('Test discover state actions', () => { ); }); - test('loadSavedSearch without id containing sql, adding no warning toast with an invalid index', async () => { - const url = "/#?_a=(index:abcde,query:(sql:'Select * from test'))&_g=()"; + test('loadSavedSearch without id containing ES|QL, adding no warning toast with an invalid index', async () => { + const url = "/#?_a=(index:abcde,query:(esql:'FROM test'))&_g=()"; const { state } = await getState(url, { savedSearch: savedSearchMock, isEmptyUrl: false }); await state.actions.loadSavedSearch(); expect(discoverServiceMock.toastNotifications.addWarning).not.toHaveBeenCalled(); diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts index 7f19ec3a23695..ba8a09e17e3d1 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.test.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.test.ts @@ -22,7 +22,7 @@ import { SavedSearchData, } from '../services/discover_data_state_container'; import { fetchDocuments } from './fetch_documents'; -import { fetchSql } from './fetch_sql'; +import { fetchTextBased } from './fetch_text_based'; import { buildDataTableRecord } from '@kbn/discover-utils'; import { dataViewMock, esHitsMockWithSort } from '@kbn/discover-utils/src/__mocks__'; import { searchResponseWarningsMock } from '@kbn/search-response-warnings/src/__mocks__/search_response_warnings'; @@ -31,12 +31,12 @@ jest.mock('./fetch_documents', () => ({ fetchDocuments: jest.fn().mockResolvedValue([]), })); -jest.mock('./fetch_sql', () => ({ - fetchSql: jest.fn().mockResolvedValue([]), +jest.mock('./fetch_text_based', () => ({ + fetchTextBased: jest.fn().mockResolvedValue([]), })); const mockFetchDocuments = fetchDocuments as unknown as jest.MockedFunction; -const mockFetchSQL = fetchSql as unknown as jest.MockedFunction; +const mockfetchTextBased = fetchTextBased as unknown as jest.MockedFunction; function subjectCollector(subject: Subject): () => Promise { const promise = firstValueFrom( @@ -88,7 +88,7 @@ describe('test fetchAll', () => { }; mockFetchDocuments.mockReset().mockResolvedValue({ records: [] }); - mockFetchSQL.mockReset().mockResolvedValue({ records: [] }); + mockfetchTextBased.mockReset().mockResolvedValue({ records: [] }); }); test('changes of fetchStatus when starting with FetchStatus.UNINITIALIZED', async () => { @@ -246,18 +246,18 @@ describe('test fetchAll', () => { ]); }); - test('emits loading and documents on documents$ correctly for SQL query', async () => { + test('emits loading and documents on documents$ correctly for ES|QL query', async () => { const collect = subjectCollector(subjects.documents$); const hits = [ { _id: '1', _index: 'logs' }, { _id: '2', _index: 'logs' }, ]; const documents = hits.map((hit) => buildDataTableRecord(hit, dataViewMock)); - mockFetchSQL.mockResolvedValue({ + mockfetchTextBased.mockResolvedValue({ records: documents, textBasedQueryColumns: [{ id: '1', name: 'test1', meta: { type: 'number' } }], }); - const query = { sql: 'SELECT * from foo' }; + const query = { esql: 'from foo' }; deps = { abortController: new AbortController(), inspectorAdapters: { requests: new RequestAdapter() }, diff --git a/src/plugins/discover/public/application/main/utils/fetch_all.ts b/src/plugins/discover/public/application/main/utils/fetch_all.ts index bf2bc0c1eb1b0..ff754b065a130 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_all.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_all.ts @@ -27,7 +27,7 @@ import { fetchDocuments } from './fetch_documents'; import { FetchStatus } from '../../types'; import { DataMsg, RecordRawType, SavedSearchData } from '../services/discover_data_state_container'; import { DiscoverServices } from '../../../build_services'; -import { fetchSql } from './fetch_sql'; +import { fetchTextBased } from './fetch_text_based'; import { InternalState } from '../services/discover_internal_state_container'; export interface FetchDeps { @@ -70,10 +70,10 @@ export function fetchAll( const query = getAppState().query; const prevQuery = dataSubjects.documents$.getValue().query; const recordRawType = getRawRecordType(query); + const useTextbased = recordRawType === RecordRawType.PLAIN; if (reset) { sendResetMsg(dataSubjects, initialFetchStatus, recordRawType); } - const useSql = recordRawType === RecordRawType.PLAIN; if (recordRawType === RecordRawType.DOCUMENT) { // Update the base searchSource, base for all child fetches @@ -92,14 +92,14 @@ export function fetchAll( // Start fetching all required requests const response = - useSql && query - ? fetchSql(query, dataView, data, services.expressions, inspectorAdapters) + useTextbased && query + ? fetchTextBased(query, dataView, data, services.expressions, inspectorAdapters) : fetchDocuments(searchSource, fetchDeps); - const fetchType = useSql && query ? 'fetchSql' : 'fetchDocuments'; + const fetchType = useTextbased && query ? 'fetchTextBased' : 'fetchDocuments'; const startTime = window.performance.now(); // Handle results of the individual queries and forward the results to the corresponding dataSubjects response - .then(({ records, textBasedQueryColumns, interceptedWarnings }) => { + .then(({ records, textBasedQueryColumns, interceptedWarnings, textBasedHeaderWarning }) => { if (services.analytics) { const duration = window.performance.now() - startTime; reportPerformanceMetricEvent(services.analytics, { @@ -125,7 +125,7 @@ export function fetchAll( * So it takes too long, a bad user experience, also a potential flakniess in tests */ const fetchStatus = - useSql && (!prevQuery || !isEqual(query, prevQuery)) + useTextbased && (!prevQuery || !isEqual(query, prevQuery)) ? FetchStatus.PARTIAL : FetchStatus.COMPLETE; @@ -133,6 +133,7 @@ export function fetchAll( fetchStatus, result: records, textBasedQueryColumns, + textBasedHeaderWarning, interceptedWarnings, recordRawType, query, diff --git a/src/plugins/discover/public/application/main/utils/fetch_documents.ts b/src/plugins/discover/public/application/main/utils/fetch_documents.ts index 767163259304f..892da705f4b8f 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_documents.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_documents.ts @@ -12,7 +12,7 @@ import { isCompleteResponse, ISearchSource } from '@kbn/data-plugin/public'; import { SAMPLE_SIZE_SETTING, buildDataTableRecordList } from '@kbn/discover-utils'; import type { EsHitRecord } from '@kbn/discover-utils/types'; import { getSearchResponseInterceptedWarnings } from '@kbn/search-response-warnings'; -import type { RecordsFetchResponse } from '../../../types'; +import type { RecordsFetchResponse } from '../../types'; import { DISABLE_SHARD_FAILURE_WARNING } from '../../../../common/constants'; import { FetchDeps } from './fetch_all'; diff --git a/src/plugins/discover/public/application/main/utils/fetch_sql.ts b/src/plugins/discover/public/application/main/utils/fetch_text_based.ts similarity index 87% rename from src/plugins/discover/public/application/main/utils/fetch_sql.ts rename to src/plugins/discover/public/application/main/utils/fetch_text_based.ts index 73c716e8f9351..6a164bfd8a5f8 100644 --- a/src/plugins/discover/public/application/main/utils/fetch_sql.ts +++ b/src/plugins/discover/public/application/main/utils/fetch_text_based.ts @@ -15,16 +15,16 @@ import type { Datatable } from '@kbn/expressions-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/common'; import { textBasedQueryStateToAstWithValidation } from '@kbn/data-plugin/common'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { RecordsFetchResponse } from '../../../types'; +import type { RecordsFetchResponse } from '../../types'; -interface SQLErrorResponse { +interface TextBasedErrorResponse { error: { message: string; }; type: 'error'; } -export function fetchSql( +export function fetchTextBased( query: Query | AggregateQuery, dataView: DataView, data: DataPublicPluginStart, @@ -49,14 +49,16 @@ export function fetchSql( let finalData: DataTableRecord[] = []; let textBasedQueryColumns: Datatable['columns'] | undefined; let error: string | undefined; + let textBasedHeaderWarning: string | undefined; execution.pipe(pluck('result')).subscribe((resp) => { - const response = resp as Datatable | SQLErrorResponse; + const response = resp as Datatable | TextBasedErrorResponse; if (response.type === 'error') { error = response.error.message; } else { const table = response as Datatable; const rows = table?.rows ?? []; textBasedQueryColumns = table?.columns ?? undefined; + textBasedHeaderWarning = table.warning ?? undefined; finalData = rows.map( (row: Record, idx: number) => ({ @@ -74,6 +76,7 @@ export function fetchSql( return { records: finalData || [], textBasedQueryColumns, + textBasedHeaderWarning, }; } }); @@ -81,6 +84,7 @@ export function fetchSql( return { records: [] as DataTableRecord[], textBasedQueryColumns: [], + textBasedHeaderWarning: undefined, }; }) .catch((err) => { diff --git a/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.test.ts b/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.test.ts index 0b81061ab68ff..0dfbd84224f4d 100644 --- a/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.test.ts +++ b/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.test.ts @@ -20,13 +20,13 @@ describe('getDataViewByTextBasedQueryLang', () => { }); const services = discoverServiceMock; it('returns the current dataview if is adhoc and query has not changed', async () => { - const query = { sql: 'Select * from data-view-ad-hoc-title' }; + const query = { esql: 'from data-view-ad-hoc-title' }; const dataView = await getDataViewByTextBasedQueryLang(query, dataViewAdHoc, services); expect(dataView).toStrictEqual(dataViewAdHoc); }); it('creates an adhoc dataview if the current dataview is persistent and query has not changed', async () => { - const query = { sql: 'Select * from the-data-view-title' }; + const query = { esql: 'from the-data-view-title' }; const dataView = await getDataViewByTextBasedQueryLang(query, dataViewMock, services); expect(dataView.isPersisted()).toEqual(false); expect(dataView.timeFieldName).toBe('@timestamp'); @@ -40,7 +40,7 @@ describe('getDataViewByTextBasedQueryLang', () => { title: 'test-1', timeFieldName: undefined, }); - const query = { sql: 'Select * from the-data-view-title' }; + const query = { esql: 'from the-data-view-title' }; const dataView = await getDataViewByTextBasedQueryLang(query, dataViewAdHoc, services); expect(dataView.isPersisted()).toEqual(false); expect(dataView.timeFieldName).toBeUndefined(); diff --git a/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.ts b/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.ts index 3b38b95dfceb1..09ac5f1e87686 100644 --- a/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.ts +++ b/src/plugins/discover/public/application/main/utils/get_data_view_by_text_based_query_lang.ts @@ -5,7 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { AggregateQuery, getIndexPatternFromSQLQuery } from '@kbn/es-query'; +import { + AggregateQuery, + getIndexPatternFromSQLQuery, + getIndexPatternFromESQLQuery, +} from '@kbn/es-query'; import { DataView } from '@kbn/data-views-plugin/common'; import { DiscoverServices } from '../../../build_services'; @@ -14,9 +18,16 @@ export async function getDataViewByTextBasedQueryLang( currentDataView: DataView | undefined, services: DiscoverServices ) { - const text = 'sql' in query ? query.sql : undefined; + let indexPatternFromQuery = ''; + if ('sql' in query) { + indexPatternFromQuery = getIndexPatternFromSQLQuery(query.sql); + } + if ('esql' in query) { + indexPatternFromQuery = getIndexPatternFromESQLQuery(query.esql); + } + // we should find a better way to work with ESQL queries which dont need a dataview + if (!indexPatternFromQuery && currentDataView) return currentDataView; - const indexPatternFromQuery = getIndexPatternFromSQLQuery(text); if ( currentDataView?.isPersisted() || indexPatternFromQuery !== currentDataView?.getIndexPattern() diff --git a/src/plugins/discover/public/application/main/utils/get_raw_record_type.test.ts b/src/plugins/discover/public/application/main/utils/get_raw_record_type.test.ts index 146a5a80a125f..781cfef1387a9 100644 --- a/src/plugins/discover/public/application/main/utils/get_raw_record_type.test.ts +++ b/src/plugins/discover/public/application/main/utils/get_raw_record_type.test.ts @@ -15,8 +15,8 @@ describe('getRawRecordType', () => { expect(mode).toEqual(RecordRawType.DOCUMENT); }); - it('returns sql for Query type query', () => { - const mode = getRawRecordType({ sql: 'SELECT * from foo' }); + it('returns esql for Query type query', () => { + const mode = getRawRecordType({ esql: 'from foo' }); expect(mode).toEqual(RecordRawType.PLAIN); }); diff --git a/src/plugins/discover/public/application/main/utils/get_state_defaults.test.ts b/src/plugins/discover/public/application/main/utils/get_state_defaults.test.ts index 103520c71998b..19e9f6a64c88b 100644 --- a/src/plugins/discover/public/application/main/utils/get_state_defaults.test.ts +++ b/src/plugins/discover/public/application/main/utils/get_state_defaults.test.ts @@ -10,7 +10,7 @@ import { getStateDefaults } from './get_state_defaults'; import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks'; import { VIEW_MODE } from '@kbn/saved-search-plugin/common'; import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield'; -import { savedSearchMock, savedSearchMockWithSQL } from '../../../__mocks__/saved_search'; +import { savedSearchMock, savedSearchMockWithESQL } from '../../../__mocks__/saved_search'; import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; import { discoverServiceMock } from '../../../__mocks__/services'; @@ -81,7 +81,7 @@ describe('getStateDefaults', () => { const actualForUndefinedViewMode = getStateDefaults({ services: discoverServiceMock, savedSearch: { - ...savedSearchMockWithSQL, + ...savedSearchMockWithESQL, viewMode: undefined, }, }); @@ -90,7 +90,7 @@ describe('getStateDefaults', () => { const actualForTextBasedWithInvalidViewMode = getStateDefaults({ services: discoverServiceMock, savedSearch: { - ...savedSearchMockWithSQL, + ...savedSearchMockWithESQL, viewMode: VIEW_MODE.AGGREGATED_LEVEL, }, }); @@ -99,7 +99,7 @@ describe('getStateDefaults', () => { const actualForTextBasedWithValidViewMode = getStateDefaults({ services: discoverServiceMock, savedSearch: { - ...savedSearchMockWithSQL, + ...savedSearchMockWithESQL, viewMode: VIEW_MODE.DOCUMENT_LEVEL, }, }); diff --git a/src/plugins/discover/public/application/main/utils/is_text_based_query.test.ts b/src/plugins/discover/public/application/main/utils/is_text_based_query.test.ts index 53e85216ba0bf..78f7b24d3c10a 100644 --- a/src/plugins/discover/public/application/main/utils/is_text_based_query.test.ts +++ b/src/plugins/discover/public/application/main/utils/is_text_based_query.test.ts @@ -12,6 +12,7 @@ describe('isTextBasedQuery', () => { it('should work correctly', () => { expect(isTextBasedQuery({ query: '', language: 'lucene' })).toEqual(false); expect(isTextBasedQuery({ sql: 'SELECT * from foo' })).toEqual(true); + expect(isTextBasedQuery({ esql: 'from foo' })).toEqual(true); expect(isTextBasedQuery()).toEqual(false); }); }); diff --git a/src/plugins/discover/public/application/types.ts b/src/plugins/discover/public/application/types.ts index 57677236cbf7a..3fc375a5ebcb7 100644 --- a/src/plugins/discover/public/application/types.ts +++ b/src/plugins/discover/public/application/types.ts @@ -6,6 +6,10 @@ * Side Public License, v 1. */ +import type { DatatableColumn } from '@kbn/expressions-plugin/common'; +import type { DataTableRecord } from '@kbn/discover-utils/types'; +import type { SearchResponseInterceptedWarning } from '@kbn/search-response-warnings'; + export enum FetchStatus { UNINITIALIZED = 'uninitialized', LOADING = 'loading', @@ -16,3 +20,10 @@ export enum FetchStatus { } export type DiscoverDisplayMode = 'embedded' | 'standalone'; + +export interface RecordsFetchResponse { + records: DataTableRecord[]; + textBasedQueryColumns?: DatatableColumn[]; + textBasedHeaderWarning?: string; + interceptedWarnings?: SearchResponseInterceptedWarning[]; +} diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.test.tsx b/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.test.tsx deleted file mode 100644 index 079a26c265d27..0000000000000 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_cell_actions.test.tsx +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ -const mockCopyToClipboard = jest.fn((value) => true); -jest.mock('@elastic/eui', () => { - const original = jest.requireActual('@elastic/eui'); - return { - ...original, - copyToClipboard: (value: string) => mockCopyToClipboard(value), - }; -}); - -jest.mock('../../hooks/use_discover_services', () => { - const services = { - toastNotifications: { - addInfo: jest.fn(), - }, - }; - const originalModule = jest.requireActual('../../hooks/use_discover_services'); - return { - ...originalModule, - useDiscoverServices: () => services, - }; -}); - -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { findTestSubject } from '@elastic/eui/lib/test'; -import { FilterInBtn, FilterOutBtn, buildCellActions, CopyBtn } from './discover_grid_cell_actions'; -import { DiscoverGridContext } from './discover_grid_context'; -import { EuiButton } from '@elastic/eui'; -import { discoverGridContextMock } from '../../__mocks__/grid_context'; -import { DataViewField } from '@kbn/data-views-plugin/public'; - -describe('Discover cell actions ', function () { - it('should not show cell actions for unfilterable fields', async () => { - expect(buildCellActions({ name: 'foo', filterable: false } as DataViewField)).toEqual([ - CopyBtn, - ]); - }); - - it('should show filter actions for filterable fields', async () => { - expect(buildCellActions({ name: 'foo', filterable: true } as DataViewField, jest.fn())).toEqual( - [FilterInBtn, FilterOutBtn, CopyBtn] - ); - }); - - it('should show Copy action for _source field', async () => { - expect( - buildCellActions({ name: '_source', type: '_source', filterable: false } as DataViewField) - ).toEqual([CopyBtn]); - }); - - it('triggers filter function when FilterInBtn is clicked', async () => { - const component = mountWithIntl( - - } - rowIndex={1} - colIndex={1} - columnId="extension" - isExpanded={false} - /> - - ); - const button = findTestSubject(component, 'filterForButton'); - await button.simulate('click'); - expect(discoverGridContextMock.onFilter).toHaveBeenCalledWith( - discoverGridContextMock.dataView.fields.getByName('extension'), - 'jpg', - '+' - ); - }); - it('triggers filter function when FilterInBtn is clicked for a non-provided value', async () => { - const component = mountWithIntl( - - } - rowIndex={0} - colIndex={1} - columnId="extension" - isExpanded={false} - /> - - ); - const button = findTestSubject(component, 'filterForButton'); - await button.simulate('click'); - expect(discoverGridContextMock.onFilter).toHaveBeenCalledWith( - discoverGridContextMock.dataView.fields.getByName('extension'), - undefined, - '+' - ); - }); - it('triggers filter function when FilterInBtn is clicked for an empty string value', async () => { - const component = mountWithIntl( - - } - rowIndex={4} - colIndex={1} - columnId="message" - isExpanded={false} - /> - - ); - const button = findTestSubject(component, 'filterForButton'); - await button.simulate('click'); - expect(discoverGridContextMock.onFilter).toHaveBeenCalledWith( - discoverGridContextMock.dataView.fields.getByName('message'), - '', - '+' - ); - }); - it('triggers filter function when FilterOutBtn is clicked', async () => { - const component = mountWithIntl( - - } - rowIndex={1} - colIndex={1} - columnId="extension" - isExpanded={false} - /> - - ); - const button = findTestSubject(component, 'filterOutButton'); - await button.simulate('click'); - expect(discoverGridContextMock.onFilter).toHaveBeenCalledWith( - discoverGridContextMock.dataView.fields.getByName('extension'), - 'jpg', - '-' - ); - }); - it('triggers clipboard copy when CopyBtn is clicked', async () => { - const component = mountWithIntl( - - } - rowIndex={1} - colIndex={1} - columnId="extension" - isExpanded={false} - /> - - ); - const button = findTestSubject(component, 'copyClipboardButton'); - await button.simulate('click'); - expect(mockCopyToClipboard).toHaveBeenCalledWith('jpg'); - }); -}); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx similarity index 99% rename from src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx rename to src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx index d8691180dc727..9593c6c81c31e 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.test.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx @@ -199,7 +199,7 @@ describe('Discover flyout', function () { it('should not render single/surrounding views for text based', async () => { const { component } = await mountComponent({ - query: { sql: 'Select * from indexpattern' }, + query: { esql: 'FROM indexpattern' }, }); const singleDocumentView = findTestSubject(component, 'docTableRowAction'); expect(singleDocumentView.length).toBeFalsy(); diff --git a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx similarity index 97% rename from src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx rename to src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx index ab25ac97fdc3c..a9130df52738e 100644 --- a/src/plugins/discover/public/components/discover_grid/discover_grid_flyout.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.tsx @@ -45,7 +45,7 @@ export interface DiscoverGridFlyoutProps { onClose: () => void; onFilter?: DocViewFilterFn; onRemoveColumn: (column: string) => void; - setExpandedDoc: (doc: DataTableRecord) => void; + setExpandedDoc: (doc?: DataTableRecord) => void; } function getIndexByDocId(hits: DataTableRecord[], id: string) { @@ -120,7 +120,7 @@ export function DiscoverGridFlyout({

@@ -216,7 +216,7 @@ export function DiscoverGridFlyout({ pageCount={pageCount} activePage={activePage} onPageClick={setPage} - className="dscTable__flyoutDocumentNavigation" + className="unifiedDataTable__flyoutDocumentNavigation" compressed data-test-subj="dscDocNavigation" /> @@ -255,3 +255,6 @@ export function DiscoverGridFlyout({ ); } + +// eslint-disable-next-line import/no-default-export +export default DiscoverGridFlyout; diff --git a/src/plugins/discover/public/components/discover_grid_flyout/index.ts b/src/plugins/discover/public/components/discover_grid_flyout/index.ts new file mode 100644 index 0000000000000..da7fa274494b1 --- /dev/null +++ b/src/plugins/discover/public/components/discover_grid_flyout/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 { withSuspense } from '@kbn/shared-ux-utility'; +import { lazy } from 'react'; +export type { DiscoverGridFlyoutProps } from './discover_grid_flyout'; + +export const DiscoverGridFlyout = withSuspense(lazy(() => import('./discover_grid_flyout'))); diff --git a/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx b/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx index 18ba8817391ac..bd0e2e3439451 100644 --- a/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx +++ b/src/plugins/discover/public/components/doc_table/components/pager/tool_bar_pagination.tsx @@ -19,7 +19,7 @@ import { import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { euiLightVars } from '@kbn/ui-theme'; -import { getRowsPerPageOptions } from '../../../../utils/rows_per_page'; +import { getRowsPerPageOptions } from '@kbn/unified-data-table'; export const MAX_ROWS_PER_PAGE_OPTION = 100; diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx index e6caae3c4a7dd..9a44ae3834f7c 100644 --- a/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_embeddable.tsx @@ -59,30 +59,34 @@ import { SORT_DEFAULT_ORDER_SETTING, buildDataTableRecord, } from '@kbn/discover-utils'; -import { VIEW_MODE, DISABLE_SHARD_FAILURE_WARNING } from '../../common/constants'; +import type { UnifiedDataTableProps } from '@kbn/unified-data-table'; +import type { UnifiedDataTableSettings } from '@kbn/unified-data-table'; +import { columnActions } from '@kbn/unified-data-table'; +import { + VIEW_MODE, + DISABLE_SHARD_FAILURE_WARNING, + getDefaultRowsPerPage, +} from '../../common/constants'; import type { ISearchEmbeddable, SearchInput, SearchOutput } from './types'; import type { DiscoverServices } from '../build_services'; import { getSortForEmbeddable, SortPair } from '../utils/sorting'; import { SEARCH_EMBEDDABLE_TYPE, SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER_ID } from './constants'; import { SavedSearchEmbeddableComponent } from './saved_search_embeddable_component'; -import * as columnActions from '../components/doc_table/actions/columns'; import { handleSourceColumnState } from '../utils/state_helpers'; -import type { DiscoverGridProps } from '../components/discover_grid/discover_grid'; -import type { DiscoverGridSettings } from '../components/discover_grid/types'; import type { DocTableProps } from '../components/doc_table/doc_table_wrapper'; import { updateSearchSource } from './utils/update_search_source'; import { FieldStatisticsTable } from '../application/main/components/field_stats_table'; +import { fetchTextBased } from '../application/main/utils/fetch_text_based'; import { isTextBasedQuery } from '../application/main/utils/is_text_based_query'; import { getValidViewMode } from '../application/main/utils/get_valid_view_mode'; -import { fetchSql } from '../application/main/utils/fetch_sql'; import { ADHOC_DATA_VIEW_RENDER_EVENT } from '../constants'; import { getDiscoverLocatorParams } from './get_discover_locator_params'; -export type SearchProps = Partial & +export type SearchProps = Partial & Partial & { savedSearchId?: string; filters?: Filter[]; - settings?: DiscoverGridSettings; + settings?: UnifiedDataTableSettings; description?: string; sharedItemTitle?: string; inspectorAdapters?: Adapters; @@ -321,12 +325,12 @@ export class SavedSearchEmbeddable const query = savedSearch.searchSource.getField('query'); const dataView = savedSearch.searchSource.getField('index')!; - const useSql = this.isTextBasedSearch(savedSearch); + const useTextBased = this.isTextBasedSearch(savedSearch); try { - // Request SQL data - if (useSql && query) { - const result = await fetchSql( + // Request text based data + if (useTextBased && query) { + const result = await fetchTextBased( savedSearch.searchSource.getField('query')!, dataView, this.services.data, @@ -585,7 +589,10 @@ export class SavedSearchEmbeddable searchProps.sharedItemTitle = this.panelTitle; searchProps.searchTitle = this.panelTitle; searchProps.rowHeightState = this.input.rowHeight || savedSearch.rowHeight; - searchProps.rowsPerPageState = this.input.rowsPerPage || savedSearch.rowsPerPage; + searchProps.rowsPerPageState = + this.input.rowsPerPage || + savedSearch.rowsPerPage || + getDefaultRowsPerPage(this.services.uiSettings); searchProps.filters = savedSearch.searchSource.getField('filter') as Filter[]; searchProps.savedSearchId = savedSearch.id; diff --git a/src/plugins/discover/public/embeddable/saved_search_embeddable_component.tsx b/src/plugins/discover/public/embeddable/saved_search_embeddable_component.tsx index fd28f3114211f..f8c7aa39c1a7c 100644 --- a/src/plugins/discover/public/embeddable/saved_search_embeddable_component.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_embeddable_component.tsx @@ -8,11 +8,8 @@ import React from 'react'; import { AggregateQuery, Query } from '@kbn/es-query'; -import { - DiscoverGridEmbeddable, - DiscoverGridEmbeddableProps, - DataLoadingState, -} from './saved_search_grid'; +import { DataLoadingState } from '@kbn/unified-data-table'; +import { DiscoverGridEmbeddable, DiscoverGridEmbeddableProps } from './saved_search_grid'; import { DiscoverDocTableEmbeddable } from '../components/doc_table/create_doc_table_embeddable'; import { DocTableEmbeddableProps } from '../components/doc_table/doc_table_embeddable'; import { isTextBasedQuery } from '../application/main/utils/is_text_based_query'; @@ -47,7 +44,7 @@ export function SavedSearchEmbeddableComponent({ loadingState={searchProps.isLoading ? DataLoadingState.loading : DataLoadingState.loaded} showFullScreenButton={false} query={query} - className="dscDiscoverGrid" + className="unifiedDataTable" /> ); } diff --git a/src/plugins/discover/public/embeddable/saved_search_grid.tsx b/src/plugins/discover/public/embeddable/saved_search_grid.tsx index b818286660301..580a55534b573 100644 --- a/src/plugins/discover/public/embeddable/saved_search_grid.tsx +++ b/src/plugins/discover/public/embeddable/saved_search_grid.tsx @@ -5,43 +5,80 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import React, { memo, useState } from 'react'; +import React, { memo, useCallback, useState } from 'react'; import type { DataTableRecord } from '@kbn/discover-utils/types'; +import { AggregateQuery, Query } from '@kbn/es-query'; import type { SearchResponseInterceptedWarning } from '@kbn/search-response-warnings'; import { - DiscoverGrid, - DiscoverGridProps, - DataLoadingState as DiscoverDataLoadingState, -} from '../components/discover_grid/discover_grid'; + DataLoadingState as DiscoverGridLoadingState, + UnifiedDataTable, +} from '@kbn/unified-data-table'; +import type { UnifiedDataTableProps } from '@kbn/unified-data-table'; import './saved_search_grid.scss'; -import { DiscoverGridFlyout } from '../components/discover_grid/discover_grid_flyout'; +import { MAX_DOC_FIELDS_DISPLAYED, ROW_HEIGHT_OPTION, SHOW_MULTIFIELDS } from '@kbn/discover-utils'; +import { DiscoverGridFlyout } from '../components/discover_grid_flyout'; import { SavedSearchEmbeddableBase } from './saved_search_embeddable_base'; -export { DataLoadingState } from '../components/discover_grid/discover_grid'; +import { DISCOVER_TOUR_STEP_ANCHOR_IDS } from '../components/discover_tour'; -export interface DiscoverGridEmbeddableProps extends DiscoverGridProps { +export interface DiscoverGridEmbeddableProps extends UnifiedDataTableProps { totalHitCount?: number; + query?: AggregateQuery | Query; interceptedWarnings?: SearchResponseInterceptedWarning[]; + onAddColumn: (column: string) => void; + onRemoveColumn: (column: string) => void; + savedSearchId?: string; } -export const DiscoverGridMemoized = memo(DiscoverGrid); +export const DataGridMemoized = memo(UnifiedDataTable); export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) { const { interceptedWarnings, ...gridProps } = props; const [expandedDoc, setExpandedDoc] = useState(undefined); + const renderDocumentView = useCallback( + (hit: DataTableRecord, displayedRows: DataTableRecord[], displayedColumns: string[]) => ( + setExpandedDoc(undefined)} + setExpandedDoc={setExpandedDoc} + query={props.query} + /> + ), + [ + props.dataView, + props.onAddColumn, + props.onFilter, + props.onRemoveColumn, + props.query, + props.savedSearchId, + ] + ); + return ( - ); diff --git a/src/plugins/discover/public/hooks/use_row_heights_options.test.tsx b/src/plugins/discover/public/hooks/use_row_heights_options.test.tsx deleted file mode 100644 index 113f34ab723dd..0000000000000 --- a/src/plugins/discover/public/hooks/use_row_heights_options.test.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 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, { ReactNode } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; -import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { DiscoverServices } from '../build_services'; -import { LocalStorageMock } from '../__mocks__/local_storage_mock'; -import { uiSettingsMock } from '../__mocks__/ui_settings'; -import { useRowHeightsOptions } from './use_row_heights_options'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; - -const CONFIG_ROW_HEIGHT = 3; - -const getWrapper = (services: DiscoverServices) => { - return ({ children }: { children: ReactNode }) => ( - {children} - ); -}; - -describe('useRowHeightsOptions', () => { - test('should apply rowHeight from savedSearch', () => { - const { result } = renderHook( - () => { - return useRowHeightsOptions({ - rowHeightState: 2, - }); - }, - { - wrapper: getWrapper({ - uiSettings: uiSettingsMock, - storage: new LocalStorageMock({}) as unknown as Storage, - } as DiscoverServices), - } - ); - - expect(result.current.defaultHeight).toEqual({ lineCount: 2 }); - }); - - test('should apply rowHeight from local storage', () => { - const { result } = renderHook( - () => { - return useRowHeightsOptions({}); - }, - { - wrapper: getWrapper({ - uiSettings: uiSettingsMock, - storage: new LocalStorageMock({ - ['discover:dataGridRowHeight']: { - previousRowHeight: 5, - previousConfigRowHeight: 3, - }, - }) as unknown as Storage, - } as DiscoverServices), - } - ); - - expect(result.current.defaultHeight).toEqual({ lineCount: 5 }); - }); - - test('should apply rowHeight from uiSettings', () => { - const { result } = renderHook( - () => { - return useRowHeightsOptions({}); - }, - { - wrapper: getWrapper({ - uiSettings: uiSettingsMock, - storage: new LocalStorageMock({}) as unknown as Storage, - } as unknown as DiscoverServices), - } - ); - - expect(result.current.defaultHeight).toEqual({ - lineCount: CONFIG_ROW_HEIGHT, - }); - }); - - test('should apply rowHeight from uiSettings instead of local storage value, since uiSettings has been changed', () => { - const { result } = renderHook( - () => { - return useRowHeightsOptions({}); - }, - { - wrapper: getWrapper({ - uiSettings: uiSettingsMock, - storage: new LocalStorageMock({ - ['discover:dataGridRowHeight']: { - previousRowHeight: 4, - // different from uiSettings (config), now user changed it to 3, but prev was 4 - previousConfigRowHeight: 4, - }, - }) as unknown as Storage, - } as unknown as DiscoverServices), - } - ); - - expect(result.current.defaultHeight).toEqual({ - lineCount: CONFIG_ROW_HEIGHT, - }); - }); -}); diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index bd06f793a6447..d6bbbd0eed9f0 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -30,7 +30,7 @@ import { TRUNCATE_MAX_HEIGHT, SHOW_FIELD_STATISTICS, ROW_HEIGHT_OPTION, - ENABLE_SQL, + ENABLE_ESQL, } from '@kbn/discover-utils'; import { DEFAULT_ROWS_PER_PAGE, ROWS_PER_PAGE_OPTIONS } from '../common/constants'; @@ -308,18 +308,18 @@ export const getUiSettings: (docLinks: DocLinksServiceSetup) => Record` + - i18n.translate('discover.advancedSettings.enableSQL.discussLinkText', { + i18n.translate('discover.advancedSettings.enableESQL.discussLinkText', { defaultMessage: 'discuss.elastic.co/c/elastic-stack/kibana', }) + '', diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 231dcc926b830..3328073a026e7 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -63,7 +63,6 @@ "@kbn/core-application-browser", "@kbn/core-saved-objects-server", "@kbn/discover-utils", - "@kbn/field-types", "@kbn/search-response-warnings", "@kbn/content-management-plugin", "@kbn/unified-doc-viewer", @@ -71,6 +70,7 @@ "@kbn/serverless", "@kbn/react-kibana-mount", "@kbn/react-kibana-context-render", + "@kbn/unified-data-table", "@kbn/no-data-page-plugin" ], "exclude": [ diff --git a/src/plugins/expressions/common/expression_types/specs/datatable.ts b/src/plugins/expressions/common/expression_types/specs/datatable.ts index 38b21addd5968..fbba26f3d4dc8 100644 --- a/src/plugins/expressions/common/expression_types/specs/datatable.ts +++ b/src/plugins/expressions/common/expression_types/specs/datatable.ts @@ -131,6 +131,7 @@ export interface Datatable { columns: DatatableColumn[]; meta?: DatatableMeta; rows: DatatableRow[]; + warning?: string; } export interface SerializedDatatable extends Datatable { diff --git a/src/plugins/interactive_setup/public/progress_indicator.tsx b/src/plugins/interactive_setup/public/progress_indicator.tsx index 9fee7e6da7110..5da14e8081555 100644 --- a/src/plugins/interactive_setup/public/progress_indicator.tsx +++ b/src/plugins/interactive_setup/public/progress_indicator.tsx @@ -27,14 +27,7 @@ function isKibanaPastPreboot(response?: Response, body?: StatusResponse) { if (!response?.headers.get('content-type')?.includes('application/json')) { return false; } - - return ( - // Status endpoint may require authentication after `preboot` stage. - response?.status === 401 || - // We're only interested in the availability of the critical core services. - (body?.status?.core?.elasticsearch?.level === 'available' && - body?.status?.core?.savedObjects?.level === 'available') - ); + return body?.status?.overall?.level === 'available'; } export const ProgressIndicator: FunctionComponent = ({ onSuccess }) => { diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts index 9822d2985bced..f17f1e1cc42e8 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/schema.ts @@ -501,7 +501,7 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'discover:enableSql': { + 'discover:enableESQL': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 1b5f84019eb7b..902190f0cf675 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -34,7 +34,7 @@ export interface UsageStats { 'discover:searchFieldsFromSource': boolean; 'discover:showFieldStatistics': boolean; 'discover:showMultiFields': boolean; - 'discover:enableSql': boolean; + 'discover:enableESQL': boolean; 'discover:maxDocFieldsDisplayed': number; 'securitySolution:rulesTableRefresh': string; 'observability:enableInspectEsQueries': boolean; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 7beb57daee234..e90ab7c9d6a2b 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -9941,7 +9941,7 @@ "description": "Non-default value of setting." } }, - "discover:enableSql": { + "discover:enableESQL": { "type": "boolean", "_meta": { "description": "Non-default value of setting." diff --git a/src/plugins/text_based_languages/kibana.jsonc b/src/plugins/text_based_languages/kibana.jsonc index 472560aa3b488..f22a87185b54c 100644 --- a/src/plugins/text_based_languages/kibana.jsonc +++ b/src/plugins/text_based_languages/kibana.jsonc @@ -6,6 +6,14 @@ "id": "textBasedLanguages", "server": false, "browser": true, + "optionalPlugins": [ + "indexManagement" + ], + "requiredPlugins": [ + "data", + "expressions", + "dataViews" + ], "requiredBundles": [ "kibanaReact", ] diff --git a/src/plugins/text_based_languages/public/create_editor.tsx b/src/plugins/text_based_languages/public/create_editor.tsx index 1fefff765f9b2..534d86420b74d 100644 --- a/src/plugins/text_based_languages/public/create_editor.tsx +++ b/src/plugins/text_based_languages/public/create_editor.tsx @@ -27,7 +27,7 @@ export const TextBasedLangEditor = (props: TextBasedLanguagesEditorProps) => { return ( diff --git a/src/plugins/text_based_languages/public/kibana_services.ts b/src/plugins/text_based_languages/public/kibana_services.ts index 01f0dd4a823d3..8592904a69370 100644 --- a/src/plugins/text_based_languages/public/kibana_services.ts +++ b/src/plugins/text_based_languages/public/kibana_services.ts @@ -7,17 +7,25 @@ */ import { BehaviorSubject } from 'rxjs'; - -import { CoreStart } from '@kbn/core/public'; +import type { CoreStart } from '@kbn/core/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import { IndexManagementPluginSetup } from '@kbn/index-management-plugin/public'; export let core: CoreStart; -const servicesReady$ = new BehaviorSubject<{ core: CoreStart; darkMode: boolean } | undefined>( - undefined -); +interface ServiceDeps { + core: CoreStart; + darkMode: boolean; + dataViews: DataViewsPublicPluginStart; + expressions: ExpressionsStart; + indexManagementApiService?: IndexManagementPluginSetup['apiService']; +} + +const servicesReady$ = new BehaviorSubject(undefined); export const untilPluginStartServicesReady = () => { if (servicesReady$.value) return Promise.resolve(servicesReady$.value); - return new Promise<{ core: CoreStart; darkMode: boolean }>((resolve) => { + return new Promise((resolve) => { const subscription = servicesReady$.subscribe((deps) => { if (deps) { subscription.unsubscribe(); @@ -27,9 +35,20 @@ export const untilPluginStartServicesReady = () => { }); }; -export const setKibanaServices = (kibanaCore: CoreStart) => { +export const setKibanaServices = ( + kibanaCore: CoreStart, + dataViews: DataViewsPublicPluginStart, + expressions: ExpressionsStart, + indexManagement?: IndexManagementPluginSetup +) => { core = kibanaCore; core.theme.theme$.subscribe(({ darkMode }) => { - servicesReady$.next({ core, darkMode }); + servicesReady$.next({ + core, + darkMode, + dataViews, + expressions, + indexManagementApiService: indexManagement?.apiService, + }); }); }; diff --git a/src/plugins/text_based_languages/public/plugin.ts b/src/plugins/text_based_languages/public/plugin.ts index f983baf517f8c..d496bdfe30f99 100755 --- a/src/plugins/text_based_languages/public/plugin.ts +++ b/src/plugins/text_based_languages/public/plugin.ts @@ -6,16 +6,31 @@ * Side Public License, v 1. */ -import { Plugin, CoreStart } from '@kbn/core/public'; +import type { Plugin, CoreStart, CoreSetup } from '@kbn/core/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import type { IndexManagementPluginSetup } from '@kbn/index-management-plugin/public'; import { setKibanaServices } from './kibana_services'; +interface TextBasedLanguagesPluginStart { + dataViews: DataViewsPublicPluginStart; + expressions: ExpressionsStart; +} + +interface TextBasedLanguagesPluginSetup { + indexManagement: IndexManagementPluginSetup; +} + export class TextBasedLanguagesPlugin implements Plugin<{}, void> { - public setup() { + private indexManagement?: IndexManagementPluginSetup; + + public setup(_: CoreSetup, { indexManagement }: TextBasedLanguagesPluginSetup) { + this.indexManagement = indexManagement; return {}; } - public start(core: CoreStart): void { - setKibanaServices(core); + public start(core: CoreStart, { dataViews, expressions }: TextBasedLanguagesPluginStart): void { + setKibanaServices(core, dataViews, expressions, this.indexManagement); } public stop() {} diff --git a/src/plugins/text_based_languages/tsconfig.json b/src/plugins/text_based_languages/tsconfig.json index d8b5cbd5e965b..152a2aba25c6b 100644 --- a/src/plugins/text_based_languages/tsconfig.json +++ b/src/plugins/text_based_languages/tsconfig.json @@ -13,6 +13,9 @@ "@kbn/text-based-editor", "@kbn/kibana-react-plugin", "@kbn/core", + "@kbn/expressions-plugin", + "@kbn/data-views-plugin", + "@kbn/index-management-plugin", ], "exclude": [ "target/**/*", diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx index 733f9040b3b3a..26c771e405be8 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx @@ -16,8 +16,7 @@ import type { DataView } from '@kbn/data-views-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { ElasticRequestState } from '@kbn/unified-doc-viewer'; import { DOC_TABLE_LEGACY, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; -import { useEsDocSearch } from '../../hooks'; -import { useUnifiedDocViewerServices } from '../../hooks'; +import { useEsDocSearch, useUnifiedDocViewerServices } from '../../hooks'; import { getHeight } from './get_height'; import { JSONCodeEditorCommonMemoized } from '../json_code_editor'; diff --git a/src/plugins/unified_histogram/public/__mocks__/suggestions.ts b/src/plugins/unified_histogram/public/__mocks__/suggestions.ts index 0a92393f60ec3..bed2eee388cde 100644 --- a/src/plugins/unified_histogram/public/__mocks__/suggestions.ts +++ b/src/plugins/unified_histogram/public/__mocks__/suggestions.ts @@ -39,7 +39,7 @@ export const currentSuggestionMock = { '46aa21fa-b747-4543-bf90-0b40007c546d': { index: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', query: { - sql: 'SELECT Dest, AvgTicketPrice FROM "kibana_sample_data_flights"', + esql: 'FROM kibana_sample_data_flights | keep Dest, AvgTicketPrice', }, columns: [ { @@ -141,7 +141,7 @@ export const currentSuggestionMock = { fieldName: '', contextualFields: ['Dest', 'AvgTicketPrice'], query: { - sql: 'SELECT Dest, AvgTicketPrice FROM "kibana_sample_data_flights"', + esql: 'FROM "kibana_sample_data_flights"', }, }, }, @@ -178,7 +178,7 @@ export const allSuggestionsMock = [ '2513a3d4-ad9d-48ea-bd58-8b6419ab97e6': { index: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', query: { - sql: 'SELECT Dest, AvgTicketPrice FROM "kibana_sample_data_flights"', + esql: 'FROM "kibana_sample_data_flights"', }, columns: [ { @@ -281,7 +281,7 @@ export const allSuggestionsMock = [ fieldName: '', contextualFields: ['Dest', 'AvgTicketPrice'], query: { - sql: 'SELECT Dest, AvgTicketPrice FROM "kibana_sample_data_flights"', + esql: 'FROM "kibana_sample_data_flights"', }, }, }, diff --git a/src/plugins/unified_histogram/public/chart/chart.tsx b/src/plugins/unified_histogram/public/chart/chart.tsx index a9baa653ecee4..0172b1b6107c1 100644 --- a/src/plugins/unified_histogram/public/chart/chart.tsx +++ b/src/plugins/unified_histogram/public/chart/chart.tsx @@ -69,6 +69,7 @@ export interface ChartProps { disabledActions?: LensEmbeddableInput['disabledActions']; input$?: UnifiedHistogramInput$; lensTablesAdapter?: Record; + isOnHistogramMode?: boolean; onResetChartHeight?: () => void; onChartHiddenChange?: (chartHidden: boolean) => void; onTimeIntervalChange?: (timeInterval: string) => void; @@ -105,6 +106,7 @@ export function Chart({ disabledActions, input$: originalInput$, lensTablesAdapter, + isOnHistogramMode, onResetChartHeight, onChartHiddenChange, onTimeIntervalChange, @@ -427,7 +429,7 @@ export function Chart({ disableTriggers={disableTriggers} disabledActions={disabledActions} onTotalHitsChange={onTotalHitsChange} - hasLensSuggestions={Boolean(currentSuggestion)} + hasLensSuggestions={!Boolean(isOnHistogramMode)} onChartLoad={onChartLoad} onFilter={onFilter} onBrushEnd={onBrushEnd} diff --git a/src/plugins/unified_histogram/public/chart/chart_config_panel.test.tsx b/src/plugins/unified_histogram/public/chart/chart_config_panel.test.tsx index 710666ac6637b..ef673826672ea 100644 --- a/src/plugins/unified_histogram/public/chart/chart_config_panel.test.tsx +++ b/src/plugins/unified_histogram/public/chart/chart_config_panel.test.tsx @@ -36,7 +36,7 @@ describe('ChartConfigPanel', () => { isPlainRecord: true, lensTablesAdapter: lensTablesAdapterMock, query: { - sql: 'Select * from test', + esql: 'from test', }, }} /> diff --git a/src/plugins/unified_histogram/public/chart/histogram.test.tsx b/src/plugins/unified_histogram/public/chart/histogram.test.tsx index ef77af13209c0..78f06687a0e7e 100644 --- a/src/plugins/unified_histogram/public/chart/histogram.test.tsx +++ b/src/plugins/unified_histogram/public/chart/histogram.test.tsx @@ -38,7 +38,7 @@ const getMockLensAttributes = () => suggestion: undefined, }); -function mountComponent() { +function mountComponent(isPlainRecord = false, hasLensSuggestions = false) { const services = unifiedHistogramServicesMock; services.data.query.timefilter.timefilter.getAbsoluteTime = () => { return { from: '2020-05-14T11:05:13.590', to: '2020-05-14T11:20:13.590' }; @@ -51,7 +51,8 @@ function mountComponent() { request: { searchSessionId: '123', }, - hasLensSuggestions: false, + hasLensSuggestions, + isPlainRecord, hits: { status: UnifiedHistogramFetchStatus.loading, total: undefined, @@ -237,4 +238,76 @@ describe('Histogram', () => { ); expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters }); }); + + it('should execute onLoad correctly for textbased language and no Lens suggestions', async () => { + const { component, props } = mountComponent(true, false); + const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; + const onLoad = component.find(embeddable).props().onLoad; + const adapters = createDefaultInspectorAdapters(); + adapters.tables.tables.layerId = { + meta: { type: 'es_ql' }, + columns: [ + { + id: 'rows', + name: 'rows', + meta: { + type: 'number', + dimensionName: 'Vertical axis', + }, + }, + ], + rows: [ + { + rows: 16, + }, + { + rows: 4, + }, + ], + } as any; + act(() => { + onLoad(false, adapters); + }); + expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( + UnifiedHistogramFetchStatus.complete, + 20 + ); + expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters }); + }); + + it('should execute onLoad correctly for textbased language and Lens suggestions', async () => { + const { component, props } = mountComponent(true, true); + const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; + const onLoad = component.find(embeddable).props().onLoad; + const adapters = createDefaultInspectorAdapters(); + adapters.tables.tables.layerId = { + meta: { type: 'es_ql' }, + columns: [ + { + id: 'rows', + name: 'rows', + meta: { + type: 'number', + dimensionName: 'Vertical axis', + }, + }, + ], + rows: [ + { + var0: 5584.925311203319, + }, + { + var0: 6788.7777444444, + }, + ], + } as any; + act(() => { + onLoad(false, adapters); + }); + expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( + UnifiedHistogramFetchStatus.complete, + 2 + ); + expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters }); + }); }); diff --git a/src/plugins/unified_histogram/public/chart/histogram.tsx b/src/plugins/unified_histogram/public/chart/histogram.tsx index ffc9cb82515a5..0046e0b6a87bd 100644 --- a/src/plugins/unified_histogram/public/chart/histogram.tsx +++ b/src/plugins/unified_histogram/public/chart/histogram.tsx @@ -10,7 +10,7 @@ import { useEuiTheme, useResizeObserver } from '@elastic/eui'; import { css } from '@emotion/react'; import React, { useState, useRef, useEffect } from 'react'; import type { DataView } from '@kbn/data-views-plugin/public'; -import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; +import type { DefaultInspectorAdapters, Datatable } from '@kbn/expressions-plugin/common'; import type { IKibanaSearchResponse } from '@kbn/data-plugin/public'; import type { estypes } from '@elastic/elasticsearch'; import type { TimeRange } from '@kbn/es-query'; @@ -53,6 +53,29 @@ export interface HistogramProps { withDefaultActions: EmbeddableComponentProps['withDefaultActions']; } +const computeTotalHits = ( + hasLensSuggestions: boolean, + adapterTables: + | { + [key: string]: Datatable; + } + | undefined, + isPlainRecord?: boolean +) => { + if (isPlainRecord && hasLensSuggestions) { + return Object.values(adapterTables ?? {})?.[0]?.rows?.length; + } else if (isPlainRecord && !hasLensSuggestions) { + // ES|QL histogram case + let rowsCount = 0; + Object.values(adapterTables ?? {})?.[0]?.rows.forEach((r) => { + rowsCount += r.rows; + }); + return rowsCount; + } else { + return adapterTables?.unifiedHistogram?.meta?.statistics?.totalCount; + } +}; + export function Histogram({ services: { data, lens, uiSettings }, dataView, @@ -113,10 +136,7 @@ export function Histogram({ } const adapterTables = adapters?.tables?.tables; - const totalHits = - isPlainRecord && hasLensSuggestions - ? Object.values(adapterTables ?? {})?.[0]?.rows?.length - : adapterTables?.unifiedHistogram?.meta?.statistics?.totalCount; + const totalHits = computeTotalHits(hasLensSuggestions, adapterTables, isPlainRecord); onTotalHitsChange?.( isLoading ? UnifiedHistogramFetchStatus.loading : UnifiedHistogramFetchStatus.complete, diff --git a/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts b/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts index 187bf76751007..e6f3aeaa3a002 100644 --- a/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts +++ b/src/plugins/unified_histogram/public/chart/hooks/use_total_hits.test.ts @@ -123,7 +123,7 @@ describe('useTotalHits', () => { ...getDeps(), isPlainRecord: true, onTotalHitsChange, - query: { sql: 'select * from test' }, + query: { esql: 'from test' }, }; renderHook(() => useTotalHits(deps)); expect(onTotalHitsChange).toBeCalledTimes(1); diff --git a/src/plugins/unified_histogram/public/chart/utils/get_lens_attributes.test.ts b/src/plugins/unified_histogram/public/chart/utils/get_lens_attributes.test.ts index f54b1b5b5c456..2a4523d152066 100644 --- a/src/plugins/unified_histogram/public/chart/utils/get_lens_attributes.test.ts +++ b/src/plugins/unified_histogram/public/chart/utils/get_lens_attributes.test.ts @@ -636,7 +636,7 @@ describe('getLensAttributes', () => { }, "fieldName": "", "query": Object { - "sql": "SELECT Dest, AvgTicketPrice FROM \\"kibana_sample_data_flights\\"", + "esql": "FROM \\"kibana_sample_data_flights\\"", }, }, "layers": Object { @@ -675,7 +675,7 @@ describe('getLensAttributes', () => { ], "index": "d3d7af60-4c81-11e8-b3d7-01146121b73d", "query": Object { - "sql": "SELECT Dest, AvgTicketPrice FROM \\"kibana_sample_data_flights\\"", + "esql": "FROM kibana_sample_data_flights | keep Dest, AvgTicketPrice", }, "timeField": "timestamp", }, diff --git a/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts b/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts index c0eeb9448eee7..c9ab0d5220aed 100644 --- a/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts +++ b/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts @@ -136,13 +136,13 @@ describe('useStateProps', () => { `); }); - it('should return the correct props when an SQL query is used', () => { + it('should return the correct props when an ES|QL query is used', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ stateService, dataView: dataViewWithTimefieldMock, - query: { sql: 'SELECT * FROM index' }, + query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', }) @@ -222,7 +222,7 @@ describe('useStateProps', () => { useStateProps({ stateService, dataView: dataViewWithTimefieldMock, - query: { sql: 'SELECT * FROM index' }, + query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', }) diff --git a/src/plugins/unified_histogram/public/layout/hooks/compute_interval.test.ts b/src/plugins/unified_histogram/public/layout/hooks/compute_interval.test.ts new file mode 100644 index 0000000000000..04a94d172d1ac --- /dev/null +++ b/src/plugins/unified_histogram/public/layout/hooks/compute_interval.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { calculateBounds } from '@kbn/data-plugin/public'; +import { computeInterval } from './compute_interval'; + +describe('computeInterval', () => { + const dataMock = dataPluginMock.createStartContract(); + dataMock.query.timefilter.timefilter.getTime = () => { + return { from: '1991-03-29T08:04:00.694Z', to: '2021-03-29T07:04:00.695Z' }; + }; + dataMock.query.timefilter.timefilter.calculateBounds = (timeRange) => { + return calculateBounds(timeRange); + }; + + it('should return correct interval for 24 hours timerange', () => { + expect( + computeInterval( + { + from: '2023-08-15T10:00:00.000Z', + to: '2023-08-16T10:17:34.591Z', + }, + dataMock + ) + ).toEqual('30 minute'); + }); + + it('should return correct interval for 7 days timerange', () => { + expect( + computeInterval( + { + from: '2023-08-08T21:00:00.000Z', + to: '2023-08-16T10:18:56.569Z', + }, + dataMock + ) + ).toEqual('3 hour'); + }); + + it('should return correct interval for 1 month timerange', () => { + expect( + computeInterval( + { + from: '2023-07-16T21:00:00.000Z', + to: '2023-08-16T10:19:43.573Z', + }, + dataMock + ) + ).toEqual('12 hour'); + }); + + it('should return correct interval for 1 year timerange', () => { + expect( + computeInterval( + { + from: '2022-08-15T21:00:00.000Z', + to: '2023-08-16T10:21:18.589Z', + }, + dataMock + ) + ).toEqual('1 week'); + }); +}); diff --git a/src/plugins/unified_histogram/public/layout/hooks/compute_interval.ts b/src/plugins/unified_histogram/public/layout/hooks/compute_interval.ts new file mode 100644 index 0000000000000..bf6270e8255c7 --- /dev/null +++ b/src/plugins/unified_histogram/public/layout/hooks/compute_interval.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; + +// follows the same logic with vega auto_date function +// we could move to a package and reuse in the future +const barTarget = 50; // same as vega +const roundInterval = (interval: number) => { + { + switch (true) { + case interval <= 500: // <= 0.5s + return '100 millisecond'; + case interval <= 5000: // <= 5s + return '1 second'; + case interval <= 7500: // <= 7.5s + return '5 second'; + case interval <= 15000: // <= 15s + return '10 second'; + case interval <= 45000: // <= 45s + return '30 second'; + case interval <= 180000: // <= 3m + return '1 minute'; + case interval <= 450000: // <= 9m + return '5 minute'; + case interval <= 1200000: // <= 20m + return '10 minute'; + case interval <= 2700000: // <= 45m + return '30 minute'; + case interval <= 7200000: // <= 2h + return '1 hour'; + case interval <= 21600000: // <= 6h + return '3 hour'; + case interval <= 86400000: // <= 24h + return '12 hour'; + case interval <= 604800000: // <= 1w + return '24 hour'; + case interval <= 1814400000: // <= 3w + return '1 week'; + case interval < 3628800000: // < 2y + return '30 day'; + default: + return '1 year'; + } + } +}; + +export const computeInterval = (timeRange: TimeRange, data: DataPublicPluginStart): string => { + const bounds = data.query.timefilter.timefilter.calculateBounds(timeRange!); + const min = bounds.min!.valueOf(); + const max = bounds.max!.valueOf(); + const interval = (max - min) / barTarget; + return roundInterval(interval); +}; diff --git a/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts b/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts index e4936b9345a6d..b6d02753d140a 100644 --- a/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts +++ b/src/plugins/unified_histogram/public/layout/hooks/use_lens_suggestions.ts @@ -5,13 +5,21 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - import { DataView } from '@kbn/data-views-plugin/common'; -import { AggregateQuery, isOfAggregateQueryType, Query } from '@kbn/es-query'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { + AggregateQuery, + isOfAggregateQueryType, + getAggregateQueryMode, + Query, + TimeRange, +} from '@kbn/es-query'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { LensSuggestionsApi, Suggestion } from '@kbn/lens-plugin/public'; import { isEqual } from 'lodash'; import { useEffect, useMemo, useRef, useState } from 'react'; +import { computeInterval } from './compute_interval'; +const TRANSFORMATIONAL_COMMANDS = ['stats', 'project', 'keep']; export const useLensSuggestions = ({ dataView, @@ -19,6 +27,8 @@ export const useLensSuggestions = ({ originalSuggestion, isPlainRecord, columns, + data, + timeRange, lensSuggestionsApi, onSuggestionChange, }: { @@ -27,6 +37,8 @@ export const useLensSuggestions = ({ originalSuggestion?: Suggestion; isPlainRecord?: boolean; columns?: DatatableColumn[]; + data: DataPublicPluginStart; + timeRange?: TimeRange; lensSuggestionsApi: LensSuggestionsApi; onSuggestionChange?: (suggestion: Suggestion | undefined) => void; }) => { @@ -50,6 +62,63 @@ export const useLensSuggestions = ({ const currentSuggestion = originalSuggestion ?? suggestions.firstSuggestion; const suggestionDeps = useRef(getSuggestionDeps({ dataView, query, columns })); + const histogramSuggestion = useMemo(() => { + if ( + !currentSuggestion && + dataView.isTimeBased() && + query && + isOfAggregateQueryType(query) && + getAggregateQueryMode(query) === 'esql' && + timeRange + ) { + let queryHasTransformationalCommands = false; + if ('esql' in query) { + TRANSFORMATIONAL_COMMANDS.forEach((command: string) => { + if (query.esql.toLowerCase().includes(command)) { + queryHasTransformationalCommands = true; + return; + } + }); + } + + if (queryHasTransformationalCommands) return undefined; + + const interval = computeInterval(timeRange, data); + const language = getAggregateQueryMode(query); + const histogramQuery = `${query[language]} | eval uniqueName = 1 + | EVAL timestamp=DATE_TRUNC(${interval}, ${dataView.timeFieldName}) | stats rows = count(uniqueName) by timestamp | rename timestamp as \`${dataView.timeFieldName} every ${interval}\``; + const context = { + dataViewSpec: dataView?.toSpec(), + fieldName: '', + textBasedColumns: [ + { + id: `${dataView.timeFieldName} every ${interval}`, + name: `${dataView.timeFieldName} every ${interval}`, + meta: { + type: 'date', + }, + }, + { + id: 'rows', + name: 'rows', + meta: { + type: 'number', + }, + }, + ] as DatatableColumn[], + query: { + esql: histogramQuery, + }, + }; + const sug = lensSuggestionsApi(context, dataView, ['lnsDatatable']) ?? []; + if (sug.length) { + return sug[0]; + } + return undefined; + } + return undefined; + }, [currentSuggestion, dataView, query, timeRange, data, lensSuggestionsApi]); + useEffect(() => { const newSuggestionsDeps = getSuggestionDeps({ dataView, query, columns }); @@ -70,8 +139,9 @@ export const useLensSuggestions = ({ return { allSuggestions, - currentSuggestion, - suggestionUnsupported: !currentSuggestion && !dataView.isTimeBased(), + currentSuggestion: histogramSuggestion ?? currentSuggestion, + suggestionUnsupported: !currentSuggestion && !histogramSuggestion && isPlainRecord, + isOnHistogramMode: Boolean(histogramSuggestion), }; }; diff --git a/src/plugins/unified_histogram/public/layout/layout.tsx b/src/plugins/unified_histogram/public/layout/layout.tsx index d0414f0682489..d2088d4776445 100644 --- a/src/plugins/unified_histogram/public/layout/layout.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.tsx @@ -203,15 +203,18 @@ export const UnifiedHistogramLayout = ({ children, withDefaultActions, }: UnifiedHistogramLayoutProps) => { - const { allSuggestions, currentSuggestion, suggestionUnsupported } = useLensSuggestions({ - dataView, - query, - originalSuggestion, - isPlainRecord, - columns, - lensSuggestionsApi, - onSuggestionChange, - }); + const { allSuggestions, currentSuggestion, suggestionUnsupported, isOnHistogramMode } = + useLensSuggestions({ + dataView, + query, + originalSuggestion, + isPlainRecord, + columns, + timeRange, + data: services.data, + lensSuggestionsApi, + onSuggestionChange, + }); const chart = suggestionUnsupported ? undefined : originalChart; @@ -287,6 +290,7 @@ export const UnifiedHistogramLayout = ({ onFilter={onFilter} onBrushEnd={onBrushEnd} lensTablesAdapter={lensTablesAdapter} + isOnHistogramMode={isOnHistogramMode} withDefaultActions={withDefaultActions} /> diff --git a/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx b/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx index 2b4f3257f2bf5..5cf4795e1ee75 100644 --- a/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx +++ b/src/plugins/unified_search/public/__stories__/search_bar.stories.tsx @@ -535,7 +535,7 @@ storiesOf('SearchBar', module) ], } as unknown as SearchBarProps) ) - .add('with dataviewPicker with SQL', () => + .add('with dataviewPicker with ESQL', () => wrapSearchBarInContext({ dataViewPickerComponentProps: { currentDataViewId: '1234', @@ -547,66 +547,66 @@ storiesOf('SearchBar', module) onChangeDataView: action('onChangeDataView'), onAddField: action('onAddField'), onDataViewCreated: action('onDataViewCreated'), - textBasedLanguages: ['SQL'], + textBasedLanguages: ['ESQL'], }, } as SearchBarProps) ) - .add('with dataviewPicker with SQL and sql query', () => + .add('with dataviewPicker with ESQL and ESQL query', () => wrapSearchBarInContext({ dataViewPickerComponentProps: { currentDataViewId: '1234', trigger: { 'data-test-subj': 'dataView-switch-link', - label: 'SQL', - title: 'SQL', + label: 'ESQL', + title: 'ESQL', }, onChangeDataView: action('onChangeDataView'), onAddField: action('onAddField'), onDataViewCreated: action('onDataViewCreated'), - textBasedLanguages: ['SQL'], + textBasedLanguages: ['ESQL'], }, - query: { sql: 'SELECT field1, field2 FROM DATAVIEW' }, + query: { esql: 'from dataview | project field1, field2' }, } as unknown as SearchBarProps) ) - .add('with dataviewPicker with SQL and large sql query', () => + .add('with dataviewPicker with ESQL and large ESQL query', () => wrapSearchBarInContext({ dataViewPickerComponentProps: { currentDataViewId: '1234', trigger: { 'data-test-subj': 'dataView-switch-link', - label: 'SQL', - title: 'SQL', + label: 'ESQL', + title: 'ESQL', }, onChangeDataView: action('onChangeDataView'), onAddField: action('onAddField'), onDataViewCreated: action('onDataViewCreated'), - textBasedLanguages: ['SQL'], + textBasedLanguages: ['ESQL'], }, query: { - sql: 'SELECT field1, field2, field 3, field 4, field 5 FROM DATAVIEW WHERE field5 IS NOT NULL AND field4 IS NULL', + esql: 'from dataview | project field1, field2, field 3, field 4, field 5 | where field5 > 5 | stats var = avg(field3)', }, } as unknown as SearchBarProps) ) - .add('with dataviewPicker with SQL and errors in sql query', () => + .add('with dataviewPicker with ESQL and errors in ESQL query', () => wrapSearchBarInContext({ dataViewPickerComponentProps: { currentDataViewId: '1234', trigger: { 'data-test-subj': 'dataView-switch-link', - label: 'SQL', - title: 'SQL', + label: 'ESQL', + title: 'ESQL', }, onChangeDataView: action('onChangeDataView'), onAddField: action('onAddField'), onDataViewCreated: action('onDataViewCreated'), - textBasedLanguages: ['SQL'], + textBasedLanguages: ['ESQL'], }, textBasedLanguageModeErrors: [ new Error( - '[essql] > Unexpected error from Elasticsearch: verification_exception - Found 1 problem line 1:16: Unknown column [field10]' + '[esql] > Unexpected error from Elasticsearch: verification_exception - Found 1 problem line 1:16: Unknown column [field10]' ), ], - query: { sql: 'SELECT field1, field10 FROM DATAVIEW' }, + query: { esql: 'from dataview | project field10' }, } as unknown as SearchBarProps) ) .add('in disabled state', () => diff --git a/src/plugins/unified_search/public/dataview_picker/change_dataview.test.tsx b/src/plugins/unified_search/public/dataview_picker/change_dataview.test.tsx index be359f25a6496..7492018b3a6c2 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.test.tsx +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.test.tsx @@ -137,8 +137,8 @@ describe('DataView component', () => { wrapDataViewComponentInContext( { ...props, - textBasedLanguages: [TextBasedLanguages.ESQL, TextBasedLanguages.SQL], - textBasedLanguage: TextBasedLanguages.SQL, + textBasedLanguages: [TextBasedLanguages.ESQL], + textBasedLanguage: TextBasedLanguages.ESQL, }, false ) diff --git a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx index 72f777cfcae93..7d04fd5fa3621 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx @@ -11,6 +11,8 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { css } from '@emotion/react'; import { EuiPopover, + EuiPanel, + EuiBadge, EuiHorizontalRule, EuiButton, EuiContextMenuPanel, @@ -26,11 +28,11 @@ import { EuiToolTip, } from '@elastic/eui'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { AggregateQuery, getLanguageDisplayName } from '@kbn/es-query'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { IUnifiedSearchPluginServices } from '../types'; -import type { DataViewPickerPropsExtended } from './data_view_picker'; +import { type DataViewPickerPropsExtended } from './data_view_picker'; import type { DataViewListItemEnhanced } from './dataview_list'; -import type { TextBasedLanguagesListProps } from './text_languages_list'; import type { TextBasedLanguagesTransitionModalProps } from './text_languages_transition_modal'; import adhoc from './assets/adhoc.svg'; import { changeDataViewStyles } from './change_dataview.styles'; @@ -52,13 +54,6 @@ export const TextBasedLanguagesTransitionModal = ( ); -const LazyTextBasedLanguagesList = React.lazy(() => import('./text_languages_list')); -export const TextBasedLanguagesList = (props: TextBasedLanguagesListProps) => ( - }> - - -); - const mapAdHocDataView = (adHocDataView: DataView) => { return { title: adHocDataView.title, @@ -122,7 +117,7 @@ export function ChangeDataView({ useEffect(() => { if (textBasedLanguage) { - setTriggerLabel(textBasedLanguage.toUpperCase()); + setTriggerLabel(getLanguageDisplayName(textBasedLanguage).toUpperCase()); } else { setTriggerLabel(trigger.label); } @@ -245,7 +240,8 @@ export function ChangeDataView({ 'unifiedSearch.query.queryBar.indexPattern.textBasedLangSwitchWarning', { defaultMessage: - "Switching data views removes the current SQL query. Save this search to ensure you don't lose work.", + "Switching data views removes the current {textBasedLanguage} query. Save this search to ensure you don't lose work.", + values: { textBasedLanguage }, } )} > @@ -335,42 +331,24 @@ export function ChangeDataView({ if (textBasedLanguages?.length) { panelItems.push( , - - - -
- {i18n.translate( - 'unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesLabel', - { - defaultMessage: 'Text-based query languages', - } - )} -
-
-
-
, - { - setTriggerLabel(lang); - setPopoverIsOpen(false); - setIsTextBasedLangSelected(true); - // also update the query with the sql query - onTextLangQuerySubmit?.({ sql: `SELECT * FROM "${trigger.title}"` }); - }} - /> + + onTextBasedSubmit({ esql: `from ${trigger.title} | limit 10` })} + data-test-subj="select-text-based-language-panel" + > + {i18n.translate('unifiedSearch.query.queryBar.textBasedLanguagesTryLabel', { + defaultMessage: 'Try ES|QL', + })} + + {i18n.translate('unifiedSearch.query.queryBar.textBasedLanguagesTechPreviewLabel', { + defaultMessage: 'Technical preview', + })} + + + ); } @@ -384,6 +362,14 @@ export function ChangeDataView({ setIsTextLangTransitionModalDismissed(true); }, [storage]); + const onTextBasedSubmit = useCallback( + (q: AggregateQuery) => { + onTextLangQuerySubmit?.(q); + setPopoverIsOpen(false); + }, + [onTextLangQuerySubmit] + ); + const cleanup = useCallback( (shouldDismissModal: boolean) => { setIsTextLangTransitionModalVisible(false); @@ -434,6 +420,7 @@ export function ChangeDataView({ ); } diff --git a/src/plugins/unified_search/public/dataview_picker/explore_matching_button.tsx b/src/plugins/unified_search/public/dataview_picker/explore_matching_button.tsx index 77fe947061480..c02908007200f 100644 --- a/src/plugins/unified_search/public/dataview_picker/explore_matching_button.tsx +++ b/src/plugins/unified_search/public/dataview_picker/explore_matching_button.tsx @@ -35,7 +35,6 @@ export const ExploreMatchingButton = ({ alignItems="center" gutterSize="none" justifyContent="spaceBetween" - data-test-subj="select-text-based-language-panel" css={css` margin: ${euiTheme.size.s}; margin-bottom: 0; diff --git a/src/plugins/unified_search/public/dataview_picker/text_languages_list.test.tsx b/src/plugins/unified_search/public/dataview_picker/text_languages_list.test.tsx deleted file mode 100644 index deb619b236338..0000000000000 --- a/src/plugins/unified_search/public/dataview_picker/text_languages_list.test.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React, { MouseEvent } from 'react'; -import { EuiSelectable } from '@elastic/eui'; -import { act } from 'react-dom/test-utils'; -import { ShallowWrapper } from 'enzyme'; -import { shallowWithIntl as shallow } from '@kbn/test-jest-helpers'; -import TextBasedLanguagesList, { TextBasedLanguagesListProps } from './text_languages_list'; -import { TextBasedLanguages } from './data_view_picker'; - -function getTextLanguagesPickerList(instance: ShallowWrapper) { - return instance.find(EuiSelectable).first(); -} - -function getTextLanguagesPickerOptions(instance: ShallowWrapper) { - return getTextLanguagesPickerList(instance).prop('options'); -} - -function selectTextLanguagePickerOption(instance: ShallowWrapper, selectedLabel: string) { - const event = {} as MouseEvent; - const options: Array<{ label: string; checked?: 'on' | 'off' }> = getTextLanguagesPickerOptions( - instance - ).map((option: { label: string }) => - option.label === selectedLabel - ? { ...option, checked: 'on' } - : { ...option, checked: undefined } - ); - const selectedOption = { label: selectedLabel }; - return getTextLanguagesPickerList(instance).prop('onChange')!(options, event, selectedOption); -} - -describe('Text based languages list component', () => { - const changeLanguageSpy = jest.fn(); - let props: TextBasedLanguagesListProps; - beforeEach(() => { - props = { - selectedOption: 'ESQL', - onChange: changeLanguageSpy, - textBasedLanguages: [TextBasedLanguages.ESQL, TextBasedLanguages.SQL], - }; - }); - it('should trigger the onChange if a new language is selected', async () => { - const component = shallow(); - await act(async () => { - selectTextLanguagePickerOption(component, 'SQL'); - }); - expect(changeLanguageSpy).toHaveBeenCalled(); - }); - - it('should list all languages', () => { - const component = shallow(); - - expect(getTextLanguagesPickerOptions(component)!.map((option: any) => option.label)).toEqual([ - 'ESQL', - 'SQL', - ]); - }); -}); diff --git a/src/plugins/unified_search/public/dataview_picker/text_languages_list.tsx b/src/plugins/unified_search/public/dataview_picker/text_languages_list.tsx deleted file mode 100644 index ac4717ad40d48..0000000000000 --- a/src/plugins/unified_search/public/dataview_picker/text_languages_list.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiSelectable, EuiPanel, EuiBadge } from '@elastic/eui'; -import { TextBasedLanguages } from './data_view_picker'; - -export interface TextBasedLanguagesListProps { - textBasedLanguages: TextBasedLanguages[]; - onChange: (lang: string) => void; - selectedOption: string; -} - -// Needed for React.lazy -// eslint-disable-next-line import/no-default-export -export default function TextBasedLanguagesList({ - textBasedLanguages, - onChange, - selectedOption, -}: TextBasedLanguagesListProps) { - return ( - - key="textbasedLanguages-options" - data-test-subj="text-based-languages-switcher" - singleSelection="always" - options={textBasedLanguages.map((lang) => ({ - key: lang, - label: lang, - value: lang, - checked: lang === selectedOption ? 'on' : undefined, - append: ( - - {i18n.translate('unifiedSearch.query.queryBar.textBasedLanguagesTechPreviewLabel', { - defaultMessage: 'Technical preview', - })} - - ), - }))} - onChange={(choices) => { - const choice = choices.find(({ checked }) => checked) as unknown as { - value: string; - }; - onChange(choice.value); - }} - > - {(list) => ( - - {list} - - )} - - ); -} diff --git a/src/plugins/unified_search/public/dataview_picker/text_languages_transition_modal.tsx b/src/plugins/unified_search/public/dataview_picker/text_languages_transition_modal.tsx index f7eb0c4a74a22..c59599907456b 100644 --- a/src/plugins/unified_search/public/dataview_picker/text_languages_transition_modal.tsx +++ b/src/plugins/unified_search/public/dataview_picker/text_languages_transition_modal.tsx @@ -25,18 +25,21 @@ import { export interface TextBasedLanguagesTransitionModalProps { closeModal: (dismissFlag: boolean, needsSave?: boolean) => void; setIsTextLangTransitionModalVisible: (flag: boolean) => void; + textBasedLanguage?: string; } // Needed for React.lazy // eslint-disable-next-line import/no-default-export export default function TextBasedLanguagesTransitionModal({ closeModal, setIsTextLangTransitionModalVisible, + textBasedLanguage, }: TextBasedLanguagesTransitionModalProps) { const [dismissModalChecked, setDismissModalChecked] = useState(false); const onTransitionModalDismiss = useCallback((e) => { setDismissModalChecked(e.target.checked); }, []); + const language = textBasedLanguage?.toUpperCase(); return ( setIsTextLangTransitionModalVisible(false)} style={{ width: 700 }}> @@ -56,7 +59,8 @@ export default function TextBasedLanguagesTransitionModal({ 'unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalBody', { defaultMessage: - "Switching data views removes the current SQL query. Save this search to ensure you don't lose work.", + "Switching data views removes the current {language} query. Save this search to ensure you don't lose work.", + values: { language }, } )} diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index 6e72baf29c7b1..0a20154b0d0b6 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -12,7 +12,12 @@ import React, { ReactNode, useCallback, useEffect, useMemo, useRef, useState } f import deepEqual from 'fast-deep-equal'; import useObservable from 'react-use/lib/useObservable'; import type { Filter, TimeRange, Query, AggregateQuery } from '@kbn/es-query'; -import { getAggregateQueryMode, isOfQueryType, isOfAggregateQueryType } from '@kbn/es-query'; +import { + getAggregateQueryMode, + isOfQueryType, + isOfAggregateQueryType, + getLanguageDisplayName, +} from '@kbn/es-query'; import { TextBasedLangEditor } from '@kbn/text-based-languages/public'; import { EMPTY } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -79,13 +84,14 @@ const getWrapperWithTooltip = ( ) => { if (enableTooltip && query && isOfAggregateQueryType(query)) { const textBasedLanguage = getAggregateQueryMode(query); + const displayName = getLanguageDisplayName(textBasedLanguage); return ( {children} @@ -138,6 +144,7 @@ export interface QueryBarTopRowProps onFiltersUpdated?: (filters: Filter[]) => void; dataViewPickerComponentProps?: DataViewPickerProps; textBasedLanguageModeErrors?: Error[]; + textBasedLanguageModeWarning?: string; onTextBasedSavedAndExit?: ({ onSave }: OnSaveTextLanguageQueryProps) => void; filterBar?: React.ReactNode; showDatePickerAsBadge?: boolean; @@ -648,6 +655,7 @@ export const QueryBarTopRow = React.memo( expandCodeEditor={(status: boolean) => setCodeEditorIsExpanded(status)} isCodeEditorExpanded={codeEditorIsExpanded} errors={props.textBasedLanguageModeErrors} + warning={props.textBasedLanguageModeWarning} detectTimestamp={detectTimestamp} onTextLangQuerySubmit={() => onSubmit({ diff --git a/src/plugins/unified_search/public/search_bar/create_search_bar.tsx b/src/plugins/unified_search/public/search_bar/create_search_bar.tsx index 0879a12f31cef..8ffca3fbb0bda 100644 --- a/src/plugins/unified_search/public/search_bar/create_search_bar.tsx +++ b/src/plugins/unified_search/public/search_bar/create_search_bar.tsx @@ -247,6 +247,7 @@ export function createSearchBar({ {...overrideDefaultBehaviors(props)} dataViewPickerComponentProps={props.dataViewPickerComponentProps} textBasedLanguageModeErrors={props.textBasedLanguageModeErrors} + textBasedLanguageModeWarning={props.textBasedLanguageModeWarning} onTextBasedSavedAndExit={props.onTextBasedSavedAndExit} displayStyle={props.displayStyle} isScreenshotMode={isScreenshotMode} diff --git a/src/plugins/unified_search/public/search_bar/search_bar.tsx b/src/plugins/unified_search/public/search_bar/search_bar.tsx index aa84d4136ed36..b2d3b5abc966c 100644 --- a/src/plugins/unified_search/public/search_bar/search_bar.tsx +++ b/src/plugins/unified_search/public/search_bar/search_bar.tsx @@ -104,6 +104,7 @@ export interface SearchBarOwnProps { fillSubmitButton?: boolean; dataViewPickerComponentProps?: DataViewPickerProps; textBasedLanguageModeErrors?: Error[]; + textBasedLanguageModeWarning?: string; onTextBasedSavedAndExit?: ({ onSave }: OnSaveTextLanguageQueryProps) => void; showSubmitButton?: boolean; submitButtonStyle?: QueryBarTopRowProps['submitButtonStyle']; @@ -597,6 +598,7 @@ class SearchBarUI extends C onFiltersUpdated={this.props.onFiltersUpdated} dataViewPickerComponentProps={this.props.dataViewPickerComponentProps} textBasedLanguageModeErrors={this.props.textBasedLanguageModeErrors} + textBasedLanguageModeWarning={this.props.textBasedLanguageModeWarning} onTextBasedSavedAndExit={this.props.onTextBasedSavedAndExit} showDatePickerAsBadge={this.shouldShowDatePickerAsBadge()} filterBar={filterBar} diff --git a/test/examples/search/warnings.ts b/test/examples/search/warnings.ts index 24656ed68285c..3f2166447f652 100644 --- a/test/examples/search/warnings.ts +++ b/test/examples/search/warnings.ts @@ -26,7 +26,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); const esArchiver = getService('esArchiver'); - describe('handling warnings with search source fetch', function () { + // Failing: See https://github.com/elastic/kibana/issues/139879 + describe.skip('handling warnings with search source fetch', function () { const dataViewTitle = 'sample-01,sample-01-rollup'; const fromTime = 'Jun 17, 2022 @ 00:00:00.000'; const toTime = 'Jun 23, 2022 @ 00:00:00.000'; @@ -167,6 +168,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // click "see full error" button in the toast const [openShardModalButton] = await testSubjects.findAll('openShardFailureModalBtn'); await openShardModalButton.click(); + await testSubjects.exists('shardFailureModalTitle'); const modalHeader = await testSubjects.find('shardFailureModalTitle'); expect(await modalHeader.getVisibleText()).to.be('2 of 4 shards failed'); // request diff --git a/test/examples/unified_field_list_examples/field_stats.ts b/test/examples/unified_field_list_examples/field_stats.ts index de662e737cb2d..0c1ebca9f3a11 100644 --- a/test/examples/unified_field_list_examples/field_stats.ts +++ b/test/examples/unified_field_list_examples/field_stats.ts @@ -52,7 +52,8 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { await PageObjects.unifiedFieldList.cleanSidebarLocalStorage(); }); - describe('field distribution', () => { + // FLAKY: https://github.com/elastic/kibana/issues/165608 + describe.skip('field distribution', () => { before(async () => { await PageObjects.unifiedFieldList.toggleSidebarSection('empty'); // it will allow to render more fields in Available fields section }); diff --git a/test/functional/apps/console/_autocomplete.ts b/test/functional/apps/console/_autocomplete.ts index af5e9e6741197..8f2a927a4ff24 100644 --- a/test/functional/apps/console/_autocomplete.ts +++ b/test/functional/apps/console/_autocomplete.ts @@ -14,7 +14,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); - const PageObjects = getPageObjects(['common', 'console']); + const PageObjects = getPageObjects(['common', 'console', 'header']); const find = getService('find'); describe('console autocomplete feature', function describeIndexTests() { @@ -44,11 +44,160 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(true); }); + // FLAKY: https://github.com/elastic/kibana/issues/165465 + describe.skip('Autocomplete behavior', () => { + beforeEach(async () => { + await PageObjects.console.clearTextArea(); + await PageObjects.console.pressEnter(); + }); + + it('HTTP methods', async () => { + const suggestions = { + G: ['GET'], + P: ['PUT', 'POST'], + D: ['DELETE'], + H: ['HEAD'], + }; + for (const [char, methods] of Object.entries(suggestions)) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.enterText(char); + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.isAutocompleteVisible() + ); + expect(await PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + + for (const [i, method] of methods.entries()) { + expect(await PageObjects.console.getAutocompleteSuggestion(i)).to.be.eql(method); + } + + await PageObjects.console.pressEscape(); + await PageObjects.console.pressEnter(); + } + }); + + it('ES API endpoints', async () => { + const suggestions = { + 'GET _': ['_alias', '_all'], + 'PUT _': ['_all'], + 'POST _': ['_aliases', '_all'], + 'DELETE _': ['_all'], + 'HEAD _': ['_alias', '_all'], + }; + for (const [text, endpoints] of Object.entries(suggestions)) { + for (const char of text) { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.enterText(char); + } + + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.isAutocompleteVisible() + ); + expect(await PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + + for (const [i, endpoint] of endpoints.entries()) { + expect(await PageObjects.console.getAutocompleteSuggestion(i)).to.be.eql(endpoint); + } + + await PageObjects.console.pressEscape(); + await PageObjects.console.pressEnter(); + } + }); + + it('JSON autocompletion with placeholder fields', async () => { + await PageObjects.console.enterText('GET _search\n{'); + await PageObjects.console.pressEnter(); + + for (const char of '"ag') { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.enterText(char); + } + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.isAutocompleteVisible() + ); + expect(await PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + await PageObjects.console.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(await PageObjects.console.getAllVisibleText()).to.be.eql( + ` +GET _search +{ + "aggs": { + "NAME": { + "AGG_TYPE": {} + } + } +} +`.replace(/\n/g, '') + ); + // cursor should be located between '"' and 'N' + expect(await PageObjects.console.getCurrentLineNumber()).to.be.eql(5); + + await PageObjects.console.pressDown(); + await PageObjects.console.pressRight(); + await PageObjects.console.pressRight(); + for (let i = 0; i < 8; i++) { + await PageObjects.console.pressRight(true); // select 'AGG_TYPE' + } + + for (const char of 'ter') { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.enterText(char); + } + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.isAutocompleteVisible() + ); + expect(await PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + await PageObjects.console.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(await PageObjects.console.getAllVisibleText()).to.be.eql( + ` +GET _search +{ + "aggs": { + "NAME": { + "terms": { + "field": "" + } + } + } +} +`.replace(/\n/g, '') + ); + }); + + it('Dynamic autocomplete', async () => { + await PageObjects.console.enterRequest('POST test/_doc\n{}'); + await PageObjects.console.clickPlay(); + + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await PageObjects.console.getResponseStatus()).to.be('201'); + + await PageObjects.console.pressEnter(); + for (const char of 'POST t') { + await PageObjects.console.sleepForDebouncePeriod(); + log.debug('Key type "%s"', char); + await PageObjects.console.enterText(char); + } + await retry.waitFor('autocomplete to be visible', () => + PageObjects.console.isAutocompleteVisible() + ); + expect(await PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + + expect(await PageObjects.console.getAutocompleteSuggestion(0)).to.be.eql('test'); + }); + }); + // FLAKY: https://github.com/elastic/kibana/issues/164584 describe.skip('anti-regression watchdogs', () => { beforeEach(async () => { await PageObjects.console.clearTextArea(); - await PageObjects.console.pressEnter(); }); it('should suppress auto-complete on arrow keys', async () => { @@ -92,7 +241,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { for (const method of methods) { await PageObjects.console.clearTextArea(); - await PageObjects.console.pressEnter(); for (const char of method.slice(0, -1)) { await PageObjects.console.sleepForDebouncePeriod(); diff --git a/test/functional/apps/discover/group2/_data_grid_footer.ts b/test/functional/apps/discover/group2/_data_grid_footer.ts index a1d2ff0294d23..4cc7b96a52607 100644 --- a/test/functional/apps/discover/group2/_data_grid_footer.ts +++ b/test/functional/apps/discover/group2/_data_grid_footer.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; -const FOOTER_SELECTOR = 'discoverTableFooter'; +const FOOTER_SELECTOR = 'unifiedDataTableFooter'; const LOAD_MORE_SELECTOR = 'dscGridSampleSizeFetchMoreLink'; export default function ({ getService, getPageObjects }: FtrProviderContext) { diff --git a/test/functional/apps/discover/group2/_data_grid_pagination.ts b/test/functional/apps/discover/group2/_data_grid_pagination.ts index 7da02308c73be..4d0c81c4cfebc 100644 --- a/test/functional/apps/discover/group2/_data_grid_pagination.ts +++ b/test/functional/apps/discover/group2/_data_grid_pagination.ts @@ -52,18 +52,18 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show footer only for the last page', async () => { // footer is not shown - await testSubjects.missingOrFail('discoverTableFooter'); + await testSubjects.missingOrFail('unifiedDataTableFooter'); // go to next page await testSubjects.click('pagination-button-next'); // footer is not shown yet await retry.try(async function () { - await testSubjects.missingOrFail('discoverTableFooter'); + await testSubjects.missingOrFail('unifiedDataTableFooter'); }); // go to the last page await testSubjects.click('pagination-button-4'); // footer is shown now await retry.try(async function () { - await testSubjects.existOrFail('discoverTableFooter'); + await testSubjects.existOrFail('unifiedDataTableFooter'); }); }); @@ -80,7 +80,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async function () { return !testSubjects.exists('pagination-button-1'); // only page 0 is left }); - await testSubjects.existOrFail('discoverTableFooter'); + await testSubjects.existOrFail('unifiedDataTableFooter'); }); it('should render exact number of rows which where configured in the saved search or in settings', async () => { diff --git a/test/functional/apps/discover/group2/_sql_view.ts b/test/functional/apps/discover/group2/_esql_view.ts similarity index 77% rename from test/functional/apps/discover/group2/_sql_view.ts rename to test/functional/apps/discover/group2/_esql_view.ts index 95ce1516728d2..1f7493b6ff905 100644 --- a/test/functional/apps/discover/group2/_sql_view.ts +++ b/test/functional/apps/discover/group2/_esql_view.ts @@ -28,10 +28,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const defaultSettings = { defaultIndex: 'logstash-*', - 'discover:enableSql': true, + 'discover:enableESQL': true, }; - describe('discover sql view', async function () { + describe('discover esql view', async function () { before(async () => { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); log.debug('load kibana index with default index pattern'); @@ -44,7 +44,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('test', () => { - it('should render sql view correctly', async function () { + it('should render esql view correctly', async function () { await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); expect(await testSubjects.exists('showQueryBarMenu')).to.be(true); @@ -62,7 +62,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('field-@message-showDetails'); expect(await testSubjects.exists('discoverFieldListPanelEdit-@message')).to.be(true); - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); expect(await testSubjects.exists('fieldListFiltersFieldSearch')).to.be(true); @@ -72,12 +72,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await testSubjects.exists('showQueryBarMenu')).to.be(false); expect(await testSubjects.exists('addFilter')).to.be(false); expect(await testSubjects.exists('dscViewModeDocumentButton')).to.be(false); - // when Lens suggests a table, we render the histogram + // when Lens suggests a table, we render an ESQL based histogram expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true); expect(await testSubjects.exists('unifiedHistogramQueryHits')).to.be(true); expect(await testSubjects.exists('discoverAlertsButton')).to.be(false); expect(await testSubjects.exists('shareTopNavButton')).to.be(true); - expect(await testSubjects.exists('dataGridColumnSortingButton')).to.be(true); + expect(await testSubjects.exists('dataGridColumnSortingButton')).to.be(false); expect(await testSubjects.exists('docTableExpandToggleColumn')).to.be(true); expect(await testSubjects.exists('fieldListFiltersFieldTypeFilterToggle')).to.be(true); await testSubjects.click('field-@message-showDetails'); @@ -85,33 +85,27 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should perform test query correctly', async function () { - await PageObjects.discover.selectTextBaseLang('SQL'); - const testQuery = `SELECT "@tags", geo.dest, count(*) occurred FROM "logstash-*" - GROUP BY "@tags", geo.dest - HAVING occurred > 20 - ORDER BY occurred DESC`; + await PageObjects.discover.selectTextBaseLang(); + const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); - // here Lens suggests a heatmap so it is rendered + // here Lens suggests a XY so it is rendered expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true); - expect(await testSubjects.exists('heatmapChart')).to.be(true); - const cell = await dataGrid.getCellElement(0, 4); - expect(await cell.getVisibleText()).to.be('2269'); + expect(await testSubjects.exists('xyVisChart')).to.be(true); + const cell = await dataGrid.getCellElement(0, 2); + expect(await cell.getVisibleText()).to.be('1'); }); it('should render when switching to a time range with no data, then back to a time range with data', async () => { - await PageObjects.discover.selectTextBaseLang('SQL'); - const testQuery = `SELECT "@tags", geo.dest, count(*) occurred FROM "logstash-*" - GROUP BY "@tags", geo.dest - HAVING occurred > 20 - ORDER BY occurred DESC`; + await PageObjects.discover.selectTextBaseLang(); + const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); - let cell = await dataGrid.getCellElement(0, 4); - expect(await cell.getVisibleText()).to.be('2269'); + let cell = await dataGrid.getCellElement(0, 2); + expect(await cell.getVisibleText()).to.be('1'); await PageObjects.timePicker.setAbsoluteRange( 'Sep 19, 2015 @ 06:31:44.000', 'Sep 19, 2015 @ 06:31:44.000' @@ -120,23 +114,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await testSubjects.exists('discoverNoResults')).to.be(true); await PageObjects.timePicker.setDefaultAbsoluteRange(); await PageObjects.header.waitUntilLoadingHasFinished(); - cell = await dataGrid.getCellElement(0, 4); - expect(await cell.getVisibleText()).to.be('2269'); + cell = await dataGrid.getCellElement(0, 2); + expect(await cell.getVisibleText()).to.be('1'); }); it('should query an index pattern that doesnt translate to a dataview correctly', async function () { - await PageObjects.discover.selectTextBaseLang('SQL'); - const testQuery = `SELECT "@tags", geo.dest, count(*) occurred FROM "logstash*" - GROUP BY "@tags", geo.dest - HAVING occurred > 20 - ORDER BY occurred DESC`; + await PageObjects.discover.selectTextBaseLang(); + const testQuery = `from logstash* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); - const cell = await dataGrid.getCellElement(0, 4); - expect(await cell.getVisibleText()).to.be('2269'); + const cell = await dataGrid.getCellElement(0, 2); + expect(await cell.getVisibleText()).to.be('1'); }); }); }); diff --git a/test/functional/apps/discover/group2/index.ts b/test/functional/apps/discover/group2/index.ts index 17562157f444e..163c6b1a9f205 100644 --- a/test/functional/apps/discover/group2/index.ts +++ b/test/functional/apps/discover/group2/index.ts @@ -32,7 +32,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_data_grid_pagination')); loadTestFile(require.resolve('./_data_grid_footer')); loadTestFile(require.resolve('./_adhoc_data_views')); - loadTestFile(require.resolve('./_sql_view')); + loadTestFile(require.resolve('./_esql_view')); loadTestFile(require.resolve('./_indexpattern_with_unmapped_fields')); loadTestFile(require.resolve('./_runtime_fields_editor')); loadTestFile(require.resolve('./_huge_fields')); diff --git a/test/functional/apps/discover/group3/_request_counts.ts b/test/functional/apps/discover/group3/_request_counts.ts index c1224596d3e00..fdee64ada9965 100644 --- a/test/functional/apps/discover/group3/_request_counts.ts +++ b/test/functional/apps/discover/group3/_request_counts.ts @@ -38,7 +38,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*', 'bfetch:disable': true, - 'discover:enableSql': true, + 'discover:enableESQL': true, }); await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); }); @@ -54,7 +54,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); }); - const getSearchCount = async (type: 'ese' | 'sql') => { + const getSearchCount = async (type: 'ese' | 'esql') => { const requests = await browser.execute(() => performance .getEntries() @@ -69,7 +69,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await elasticChart.canvasExists(); }; - const expectSearches = async (type: 'ese' | 'sql', expected: number, cb: Function) => { + const expectSearches = async (type: 'ese' | 'esql', expected: number, cb: Function) => { await browser.execute(async () => { performance.clearResourceTimings(); }); @@ -86,12 +86,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { savedSearch, query1, query2, + savedSearchesRequests, setQuery, }: { - type: 'ese' | 'sql'; + type: 'ese' | 'esql'; savedSearch: string; query1: string; query2: string; + savedSearchesRequests?: number; setQuery: (query: string) => Promise; }) => { it('should send 2 search requests (documents + chart) on page load', async () => { @@ -143,8 +145,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'Sep 23, 2015 @ 00:00:00.000' ); await waitForLoadingToFinish(); + // TODO: Check why the request happens 4 times in case of opening a saved search + // https://github.com/elastic/kibana/issues/165192 // creating the saved search - await expectSearches(type, 2, async () => { + await expectSearches(type, savedSearchesRequests ?? 2, async () => { await PageObjects.discover.saveSearch(savedSearch); }); // resetting the saved search @@ -160,7 +164,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await waitForLoadingToFinish(); }); // loading the saved search - await expectSearches(type, 2, async () => { + // TODO: https://github.com/elastic/kibana/issues/165192 + await expectSearches(type, savedSearchesRequests ?? 2, async () => { await PageObjects.discover.loadSavedSearch(savedSearch); }); }); @@ -218,21 +223,24 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - describe('SQL mode', () => { - const type = 'sql'; + describe('ES|QL mode', () => { + const type = 'esql'; beforeEach(async () => { - await PageObjects.discover.selectTextBaseLang('SQL'); - monacoEditor.setCodeEditorValue('SELECT count(*) FROM "logstash-*" WHERE bytes > 1000'); + await PageObjects.discover.selectTextBaseLang(); + monacoEditor.setCodeEditorValue( + 'from logstash-* | where bytes > 1000 | stats countB = count(bytes)' + ); await queryBar.clickQuerySubmitButton(); await waitForLoadingToFinish(); }); getSharedTests({ type, - savedSearch: 'sql test', - query1: 'SELECT type, count(*) FROM "logstash-*" WHERE bytes > 1000 GROUP BY type', - query2: 'SELECT type, count(*) FROM "logstash-*" WHERE bytes < 2000 GROUP BY type', + savedSearch: 'esql test', + query1: 'from logstash-* | where bytes > 1000 | stats countB = count(bytes) ', + query2: 'from logstash-* | where bytes < 2000 | stats countB = count(bytes) ', + savedSearchesRequests: 4, setQuery: (query) => monacoEditor.setCodeEditorValue(query), }); }); diff --git a/test/functional/apps/discover/group3/_sidebar.ts b/test/functional/apps/discover/group3/_sidebar.ts index 265466b5c67f9..eefda4891390b 100644 --- a/test/functional/apps/discover/group3/_sidebar.ts +++ b/test/functional/apps/discover/group3/_sidebar.ts @@ -96,7 +96,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should show filters by type in text-based view', async function () { - await kibanaServer.uiSettings.update({ 'discover:enableSql': true }); + await kibanaServer.uiSettings.update({ 'discover:enableESQL': true }); await browser.refresh(); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); @@ -105,7 +105,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(options).to.have.length(6); await PageObjects.unifiedFieldList.closeSidebarFieldFilter(); - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); await PageObjects.unifiedFieldList.openSidebarFieldFilter(); @@ -113,7 +113,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(options).to.have.length(3); expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '50 selected fields. 51 available fields.' + '82 available fields.' ); await testSubjects.click('typeFilter-number'); @@ -121,7 +121,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.waitFor('updates', async () => { return ( (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '6 selected fields. 6 available fields.' + '6 available fields.' ); }); }); @@ -366,7 +366,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should show selected and available fields in text-based mode', async function () { - await kibanaServer.uiSettings.update({ 'discover:enableSql': true }); + await kibanaServer.uiSettings.update({ 'discover:enableESQL': true }); await browser.refresh(); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); @@ -375,24 +375,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { INITIAL_FIELD_LIST_SUMMARY ); - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '50 selected fields. 51 available fields.' + '82 available fields.' ); await PageObjects.unifiedFieldList.clickFieldListItemRemove('extension'); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 selected fields. 51 available fields.' + '82 available fields.' ); - const testQuery = `SELECT "@tags", geo.dest, count(*) occurred FROM "logstash-*" - GROUP BY "@tags", geo.dest - HAVING occurred > 20 - ORDER BY occurred DESC`; + const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); @@ -400,11 +397,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '3 selected fields. 3 available fields.' + '2 selected fields. 2 available fields.' ); expect( (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('selected')).join(', ') - ).to.be('@tags, geo.dest, occurred'); + ).to.be('countB, geo.dest'); await PageObjects.unifiedSearch.switchDataView( 'discover-dataView-switch-link', diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index 9efe80741621e..21a183c832606 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -150,6 +150,18 @@ export class ConsolePageObject extends FtrService { return !attribute.includes('display: none;'); } + public async getAutocompleteSuggestion(index: number = 0) { + const children1 = await this.find + .allByCssSelector('.ace_autocomplete .ace_line :nth-child(1)') + .catch(() => null); + const children2 = await this.find + .allByCssSelector('.ace_autocomplete .ace_line :nth-child(2)') + .catch(() => null); + if (!children1 || !children2) return null; + + return (await children1[index].getVisibleText()) + (await children2[index].getVisibleText()); + } + public async enterRequest(request: string = '\nGET _search') { const textArea = await this.getEditorTextArea(); await textArea.pressKeys(request); @@ -206,24 +218,24 @@ export class ConsolePageObject extends FtrService { await textArea.pressKeys(Key.ESCAPE); } - public async pressDown() { + public async pressDown(shift: boolean = false) { const textArea = await this.testSubjects.find('console-textarea'); - await textArea.pressKeys(Key.DOWN); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.DOWN] : Key.DOWN); } - public async pressLeft() { + public async pressLeft(shift: boolean = false) { const textArea = await this.testSubjects.find('console-textarea'); - await textArea.pressKeys(Key.LEFT); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.LEFT] : Key.LEFT); } - public async pressRight() { + public async pressRight(shift: boolean = false) { const textArea = await this.testSubjects.find('console-textarea'); - await textArea.pressKeys(Key.RIGHT); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.RIGHT] : Key.RIGHT); } - public async pressUp() { + public async pressUp(shift: boolean = false) { const textArea = await this.testSubjects.find('console-textarea'); - await textArea.pressKeys(Key.UP); + await textArea.pressKeys(shift ? [Key.SHIFT, Key.UP] : Key.UP); } public async clearTextArea() { diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 7ddd4f303d975..1545975667c60 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -500,11 +500,9 @@ export class DiscoverPageObject extends FtrService { return items; } - public async selectTextBaseLang(lang: 'SQL') { + public async selectTextBaseLang() { await this.testSubjects.click('discover-dataView-switch-link'); - await this.find.clickByCssSelector( - `[data-test-subj="text-based-languages-switcher"] [title="${lang}"]` - ); + await this.testSubjects.click('select-text-based-language-panel'); await this.header.waitUntilLoadingHasFinished(); } diff --git a/test/functional/page_objects/home_page.ts b/test/functional/page_objects/home_page.ts index ac942c70b5d90..61eb1f40c49e7 100644 --- a/test/functional/page_objects/home_page.ts +++ b/test/functional/page_objects/home_page.ts @@ -53,7 +53,9 @@ export class HomePageObject extends FtrService { } async isWelcomeInterstitialDisplayed() { - return await this.testSubjects.isDisplayed('homeWelcomeInterstitial'); + // give the interstitial enough time to fade in + await new Promise((resolve) => setTimeout(resolve, 500)); + return await this.testSubjects.isDisplayed('homeWelcomeInterstitial', 2000); } async isGuidedOnboardingLandingDisplayed() { diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts index fd46e5ac1448b..0a1798442f360 100644 --- a/test/functional/services/common/browser.ts +++ b/test/functional/services/common/browser.ts @@ -73,6 +73,11 @@ class BrowserService extends FtrService { return await this.driver.manage().window().getRect(); } + public async getWindowInnerSize(): Promise<{ height: number; width: number }> { + const JS_GET_INNER_WIDTH = 'return { width: window.innerWidth, height: window.innerHeight };'; + return await this.driver.executeScript(JS_GET_INNER_WIDTH); + } + /** * Sets the dimensions of a window. * https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/lib/webdriver_exports_Window.html @@ -659,6 +664,12 @@ class BrowserService extends FtrService { this.log.error( `WebDriver session is no longer valid.\nProbably Chrome process crashed when it tried to use more memory than what was available.` ); + // TODO: Remove this after a while. We are enabling richer logs in order to try catch the real error cause. + this.log.error( + `Original Error Logging.\n Name: ${err.name};\n Message: ${err.message};\n Stack: ${ + err.stack + }\n RemoteStack: ${(err as NoSuchSessionError).remoteStacktrace}` + ); } return false; } diff --git a/test/functional/services/common/test_subjects.ts b/test/functional/services/common/test_subjects.ts index e54a1caa08d26..9cbce20b05068 100644 --- a/test/functional/services/common/test_subjects.ts +++ b/test/functional/services/common/test_subjects.ts @@ -285,9 +285,9 @@ export class TestSubjects extends FtrService { return await element.isEnabled(); } - public async isDisplayed(selector: string): Promise { + public async isDisplayed(selector: string, timeout?: number): Promise { this.log.debug(`TestSubjects.isDisplayed(${selector})`); - const element = await this.find(selector); + const element = await this.find(selector, timeout); return await element.isDisplayed(); } diff --git a/test/plugin_functional/test_suites/core_plugins/applications.ts b/test/plugin_functional/test_suites/core_plugins/applications.ts index df4ac37b96464..5af71ba799457 100644 --- a/test/plugin_functional/test_suites/core_plugins/applications.ts +++ b/test/plugin_functional/test_suites/core_plugins/applications.ts @@ -49,11 +49,11 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide const navigateTo = async (path: string) => await browser.navigateTo(`${deployment.getHostPort()}${path}`); - // FLAKY: https://github.com/elastic/kibana/issues/127545 - describe.skip('ui applications', function describeIndexTests() { + describe('ui applications', function describeIndexTests() { before(async () => { await esArchiver.emptyKibanaIndex(); await PageObjects.common.navigateToApp('foo'); + await PageObjects.common.dismissBanner(); }); it('starts on home page', async () => { @@ -126,7 +126,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide expect(await testSubjects.exists('headerGlobalNav')).to.be(false); const wrapperHeight = await getAppWrapperHeight(); - const windowHeight = (await browser.getWindowSize()).height; + const windowHeight = (await browser.getWindowInnerSize()).height; expect(wrapperHeight).to.eql(windowHeight); }); @@ -136,7 +136,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide expect(await testSubjects.exists('headerGlobalNav')).to.be(true); const wrapperHeight = await getAppWrapperHeight(); - const windowHeight = (await browser.getWindowSize()).height; + const windowHeight = (await browser.getWindowInnerSize()).height; expect(wrapperHeight).to.be.below(windowHeight); }); }); diff --git a/tsconfig.base.json b/tsconfig.base.json index b7e3ed499f701..afbbdcfe7601b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1084,6 +1084,8 @@ "@kbn/preboot-example-plugin/*": ["examples/preboot_example/*"], "@kbn/presentation-util-plugin": ["src/plugins/presentation_util"], "@kbn/presentation-util-plugin/*": ["src/plugins/presentation_util/*"], + "@kbn/profiling-data-access-plugin": ["x-pack/plugins/profiling_data_access"], + "@kbn/profiling-data-access-plugin/*": ["x-pack/plugins/profiling_data_access/*"], "@kbn/profiling-plugin": ["x-pack/plugins/profiling"], "@kbn/profiling-plugin/*": ["x-pack/plugins/profiling/*"], "@kbn/random-sampling": ["x-pack/packages/kbn-random-sampling"], @@ -1494,6 +1496,8 @@ "@kbn/ui-shared-deps-src/*": ["packages/kbn-ui-shared-deps-src/*"], "@kbn/ui-theme": ["packages/kbn-ui-theme"], "@kbn/ui-theme/*": ["packages/kbn-ui-theme/*"], + "@kbn/unified-data-table": ["packages/kbn-unified-data-table"], + "@kbn/unified-data-table/*": ["packages/kbn-unified-data-table/*"], "@kbn/unified-doc-viewer": ["packages/kbn-unified-doc-viewer"], "@kbn/unified-doc-viewer/*": ["packages/kbn-unified-doc-viewer/*"], "@kbn/unified-doc-viewer-examples": ["examples/unified_doc_viewer"], diff --git a/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_icons.tsx b/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_icons.tsx index b81b25144fcd0..f2b8247840cac 100644 --- a/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_icons.tsx +++ b/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_icons.tsx @@ -81,9 +81,7 @@ export const LandingLinkIcon: React.FC = React.memo(functi - - {description} - + {description} {children} diff --git a/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_images.tsx b/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_images.tsx index 18c8ef07c10cb..20caecd5a4e2c 100644 --- a/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_images.tsx +++ b/x-pack/packages/security-solution/navigation/src/landing_links/landing_links_images.tsx @@ -89,7 +89,7 @@ export const LandingLinksImages: React.FC = React.memo( {isBeta && }

- + {description} diff --git a/x-pack/plugins/actions/kibana.jsonc b/x-pack/plugins/actions/kibana.jsonc index 9152e64ba898a..78f66742c2a03 100644 --- a/x-pack/plugins/actions/kibana.jsonc +++ b/x-pack/plugins/actions/kibana.jsonc @@ -21,7 +21,8 @@ "usageCollection", "spaces", "security", - "monitoringCollection" + "monitoringCollection", + "serverless" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/actions/server/config.ts b/x-pack/plugins/actions/server/config.ts index 9a620d1452f23..da45fd40cf925 100644 --- a/x-pack/plugins/actions/server/config.ts +++ b/x-pack/plugins/actions/server/config.ts @@ -64,6 +64,15 @@ const connectorTypeSchema = schema.object({ maxAttempts: schema.maybe(schema.number({ min: MIN_MAX_ATTEMPTS, max: MAX_MAX_ATTEMPTS })), }); +// We leverage enabledActionTypes list by allowing the other plugins to overwrite it by using "setEnabledConnectorTypes" in the plugin setup. +// The list can be overwritten only if it's not already been set in the config. +const enabledConnectorTypesSchema = schema.arrayOf( + schema.oneOf([schema.string(), schema.literal(EnabledActionTypes.Any)]), + { + defaultValue: [AllowedHosts.Any], + } +); + export const configSchema = schema.object({ allowedHosts: schema.arrayOf( schema.oneOf([schema.string({ hostname: true }), schema.literal(AllowedHosts.Any)]), @@ -71,12 +80,7 @@ export const configSchema = schema.object({ defaultValue: [AllowedHosts.Any], } ), - enabledActionTypes: schema.arrayOf( - schema.oneOf([schema.string(), schema.literal(EnabledActionTypes.Any)]), - { - defaultValue: [AllowedHosts.Any], - } - ), + enabledActionTypes: enabledConnectorTypesSchema, preconfiguredAlertHistoryEsIndex: schema.boolean({ defaultValue: false }), preconfigured: schema.recordOf(schema.string(), preconfiguredActionSchema, { defaultValue: {}, @@ -129,6 +133,7 @@ export const configSchema = schema.object({ }); export type ActionsConfig = TypeOf; +export type EnabledConnectorTypes = TypeOf; // It would be nicer to add the proxyBypassHosts / proxyOnlyHosts restriction on // simultaneous usage in the config validator directly, but there's no good way to express diff --git a/x-pack/plugins/actions/server/mocks.ts b/x-pack/plugins/actions/server/mocks.ts index ad26114cf7d07..70a2cfd9f8e85 100644 --- a/x-pack/plugins/actions/server/mocks.ts +++ b/x-pack/plugins/actions/server/mocks.ts @@ -31,6 +31,7 @@ const createSetupMock = () => { getCaseConnectorClass: jest.fn(), getActionsHealth: jest.fn(), getActionsConfigurationUtilities: jest.fn(), + setEnabledConnectorTypes: jest.fn(), }; return mock; }; diff --git a/x-pack/plugins/actions/server/plugin.test.ts b/x-pack/plugins/actions/server/plugin.test.ts index 66d75da5fd7cf..d3bc3be1a9deb 100644 --- a/x-pack/plugins/actions/server/plugin.test.ts +++ b/x-pack/plugins/actions/server/plugin.test.ts @@ -348,6 +348,163 @@ describe('Actions Plugin', () => { expect(pluginSetup.isPreconfiguredConnector('anotherConnectorId')).toEqual(false); }); }); + + describe('setEnabledConnectorTypes (works only on serverless)', () => { + function setup(config: ActionsConfig) { + context = coreMock.createPluginInitializerContext(config); + plugin = new ActionsPlugin(context); + coreSetup = coreMock.createSetup(); + pluginsSetup = { + taskManager: taskManagerMock.createSetup(), + encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(), + licensing: licensingMock.createSetup(), + eventLog: eventLogMock.createSetup(), + usageCollection: usageCollectionPluginMock.createSetupContract(), + features: featuresPluginMock.createSetup(), + serverless: {}, + }; + } + + it('should set connector type enabled', async () => { + setup(getConfig()); + // coreMock.createSetup doesn't support Plugin generics + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup); + const coreStart = coreMock.createStart(); + const pluginsStart = { + licensing: licensingMock.createStart(), + taskManager: taskManagerMock.createStart(), + encryptedSavedObjects: encryptedSavedObjectsMock.createStart(), + eventLog: eventLogMock.createStart(), + }; + const pluginStart = plugin.start(coreStart, pluginsStart); + + pluginSetup.registerType({ + id: '.server-log', + name: 'Server log', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + pluginSetup.registerType({ + id: '.slack', + name: 'Slack', + minimumLicenseRequired: 'gold', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + pluginSetup.setEnabledConnectorTypes(['.server-log']); + expect(pluginStart.isActionTypeEnabled('.server-log')).toBeTruthy(); + expect(pluginStart.isActionTypeEnabled('.slack')).toBeFalsy(); + }); + + it('should set all the connector types enabled when null or ["*"] passed', async () => { + setup(getConfig()); + // coreMock.createSetup doesn't support Plugin generics + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup); + const coreStart = coreMock.createStart(); + const pluginsStart = { + licensing: licensingMock.createStart(), + taskManager: taskManagerMock.createStart(), + encryptedSavedObjects: encryptedSavedObjectsMock.createStart(), + eventLog: eventLogMock.createStart(), + }; + const pluginStart = plugin.start(coreStart, pluginsStart); + + pluginSetup.registerType({ + id: '.server-log', + name: 'Server log', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + pluginSetup.registerType({ + id: '.index', + name: 'Index', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + pluginSetup.setEnabledConnectorTypes(['*']); + expect(pluginStart.isActionTypeEnabled('.server-log')).toBeTruthy(); + expect(pluginStart.isActionTypeEnabled('.index')).toBeTruthy(); + }); + + it('should set all the connector types disabled when [] passed', async () => { + setup(getConfig()); + // coreMock.createSetup doesn't support Plugin generics + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup); + const coreStart = coreMock.createStart(); + const pluginsStart = { + licensing: licensingMock.createStart(), + taskManager: taskManagerMock.createStart(), + encryptedSavedObjects: encryptedSavedObjectsMock.createStart(), + eventLog: eventLogMock.createStart(), + }; + const pluginStart = plugin.start(coreStart, pluginsStart); + + pluginSetup.registerType({ + id: '.server-log', + name: 'Server log', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + pluginSetup.registerType({ + id: '.index', + name: 'Index', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + pluginSetup.setEnabledConnectorTypes([]); + expect(pluginStart.isActionTypeEnabled('.server-log')).toBeFalsy(); + expect(pluginStart.isActionTypeEnabled('.index')).toBeFalsy(); + }); + + it('should throw if the enabledActionTypes is already set by the config', async () => { + setup({ ...getConfig(), enabledActionTypes: ['.email'] }); + // coreMock.createSetup doesn't support Plugin generics + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup); + + expect(() => pluginSetup.setEnabledConnectorTypes(['.index'])).toThrow( + "Enabled connector types can be set only if they haven't already been set in the config" + ); + }); + }); }); describe('start()', () => { @@ -396,6 +553,38 @@ describe('Actions Plugin', () => { }; }); + it('should throw when there is an invalid connector type in enabledActionTypes', async () => { + const pluginSetup = await plugin.setup(coreSetup, { + ...pluginsSetup, + encryptedSavedObjects: { + ...pluginsSetup.encryptedSavedObjects, + canEncrypt: true, + }, + serverless: {}, + }); + + pluginSetup.registerType({ + id: '.server-log', + name: 'Server log', + minimumLicenseRequired: 'basic', + supportedFeatureIds: ['alerting'], + validate: { + config: { schema: schema.object({}) }, + secrets: { schema: schema.object({}) }, + params: { schema: schema.object({}) }, + }, + executor, + }); + + pluginSetup.setEnabledConnectorTypes(['.server-log', 'non-existing']); + + await expect(async () => + plugin.start(coreStart, { ...pluginsStart, serverless: {} }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Action type \\"non-existing\\" is not registered."` + ); + }); + describe('getActionsClientWithRequest()', () => { it('should not throw error when ESO plugin has encryption key', async () => { await plugin.setup(coreSetup, { diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index b8b88b05049ca..415a9e36a1c01 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -40,7 +40,8 @@ import { } from '@kbn/event-log-plugin/server'; import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; -import { ActionsConfig, getValidatedConfig } from './config'; +import { ServerlessPluginSetup } from '@kbn/serverless/server'; +import { ActionsConfig, AllowedHosts, EnabledConnectorTypes, getValidatedConfig } from './config'; import { resolveCustomHosts } from './lib/custom_host_settings'; import { ActionsClient } from './actions_client/actions_client'; import { ActionTypeRegistry } from './action_type_registry'; @@ -100,10 +101,8 @@ import { createSubActionConnectorFramework } from './sub_action_framework'; import { IServiceAbstract, SubActionConnectorType } from './sub_action_framework/types'; import { SubActionConnector } from './sub_action_framework/sub_action_connector'; import { CaseConnector } from './sub_action_framework/case'; -import { - type IUnsecuredActionsClient, - UnsecuredActionsClient, -} from './unsecured_actions_client/unsecured_actions_client'; +import type { IUnsecuredActionsClient } from './unsecured_actions_client/unsecured_actions_client'; +import { UnsecuredActionsClient } from './unsecured_actions_client/unsecured_actions_client'; import { createBulkUnsecuredExecutionEnqueuerFunction } from './create_unsecured_execute_function'; import { createSystemConnectors } from './create_system_actions'; @@ -130,6 +129,7 @@ export interface PluginSetupContract { getCaseConnectorClass: () => IServiceAbstract; getActionsHealth: () => { hasPermanentEncryptionKey: boolean }; getActionsConfigurationUtilities: () => ActionsConfigurationUtilities; + setEnabledConnectorTypes: (connectorTypes: EnabledConnectorTypes) => void; } export interface PluginStartContract { @@ -169,6 +169,7 @@ export interface ActionsPluginsSetup { features: FeaturesPluginSetup; spaces?: SpacesPluginSetup; monitoringCollection?: MonitoringCollectionSetup; + serverless?: ServerlessPluginSetup; } export interface ActionsPluginsStart { @@ -178,6 +179,7 @@ export interface ActionsPluginsStart { eventLog: IEventLogClientService; spaces?: SpacesPluginStart; security?: SecurityPluginStart; + serverless?: ServerlessPluginSetup; } const includedHiddenTypes = [ @@ -375,6 +377,20 @@ export class ActionsPlugin implements Plugin actionsConfigUtils, + setEnabledConnectorTypes: (connectorTypes) => { + if ( + !!plugins.serverless && + this.actionsConfig.enabledActionTypes.length === 1 && + this.actionsConfig.enabledActionTypes[0] === AllowedHosts.Any + ) { + this.actionsConfig.enabledActionTypes.pop(); + this.actionsConfig.enabledActionTypes.push(...connectorTypes); + } else { + throw new Error( + "Enabled connector types can be set only if they haven't already been set in the config" + ); + } + }, }; } @@ -542,6 +558,8 @@ export class ActionsPlugin implements Plugin { return this.actionTypeRegistry!.isActionTypeEnabled(id, options); @@ -695,6 +713,19 @@ export class ActionsPlugin implements Plugin { + if ( + !!plugins.serverless && + this.actionsConfig.enabledActionTypes.length > 0 && + this.actionsConfig.enabledActionTypes[0] !== AllowedHosts.Any + ) { + this.actionsConfig.enabledActionTypes.forEach((connectorType) => { + // Throws error if action type doesn't exist + this.actionTypeRegistry?.get(connectorType); + }); + } + }; + public stop() { if (this.licenseState) { this.licenseState.clean(); diff --git a/x-pack/plugins/actions/tsconfig.json b/x-pack/plugins/actions/tsconfig.json index 0f4d2faf03e1a..3beeddef429b2 100644 --- a/x-pack/plugins/actions/tsconfig.json +++ b/x-pack/plugins/actions/tsconfig.json @@ -43,6 +43,7 @@ "@kbn/core-saved-objects-api-server-mocks", "@kbn/core-elasticsearch-server-mocks", "@kbn/core-logging-server-mocks", + "@kbn/serverless" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts index 2471617e7b1f4..899ffe9d928b7 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_map/service_map.cy.ts @@ -9,7 +9,7 @@ import { synthtrace } from '../../../synthtrace'; import { opbeans } from '../../fixtures/synthtrace/opbeans'; const start = '2021-10-10T00:00:00.000Z'; -const end = '2021-10-10T00:15:00.000Z'; +const end = '2021-10-10T00:01:00.000Z'; const serviceMapHref = url.format({ pathname: '/app/apm/service-map', @@ -29,7 +29,7 @@ const detailedServiceMap = url.format({ }, }); -describe('Service map', () => { +describe('service map', () => { before(() => { synthtrace.index( opbeans({ @@ -47,20 +47,28 @@ describe('Service map', () => { cy.loginAsViewerUser(); }); - describe('When navigating to service map', () => { - it('opens service map', () => { + describe('when navigating to service map', () => { + beforeEach(() => { + cy.intercept('GET', '/internal/apm/service-map?*').as('serviceMap'); cy.visitKibana(serviceMapHref); - cy.contains('h1', 'Services'); + + cy.wait('@serviceMap'); + }); + + it('shows nodes in service map', { retries: 3 }, () => { + cy.wait(500); + cy.getByTestSubj('serviceMap').matchImage(); }); - it('opens detailed service map', () => { + it('shows nodes in detailed service map', () => { cy.visitKibana(detailedServiceMap); cy.contains('h1', 'opbeans-java'); + cy.wait(500); + cy.getByTestSubj('serviceMap').matchImage(); }); - describe('When there is no data', () => { + describe('when there is no data', () => { it('shows empty state', () => { - cy.visitKibana(serviceMapHref); // we need to dismiss the service-group call out first cy.contains('Dismiss').click(); cy.getByTestSubj('apmUnifiedSearchBar').type('_id : foo{enter}'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts index c191a9add4e96..204d05255ac58 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -8,6 +8,7 @@ import 'cypress-real-events/support'; import { Interception } from 'cypress/types/net-stubbing'; import 'cypress-axe'; import moment from 'moment'; +import '@frsource/cypress-plugin-visual-regression-diff'; import { AXE_CONFIG, AXE_OPTIONS } from '@kbn/axe-config'; import { ApmUsername } from '../../../server/test_helpers/create_apm_users/authentication'; diff --git a/x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts b/x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts index 5194a7aa549b2..9fe1c8608fad2 100644 --- a/x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts +++ b/x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts @@ -10,6 +10,8 @@ import { LogLevel, } from '@kbn/apm-synthtrace'; import { createEsClientForTesting } from '@kbn/test'; +// eslint-disable-next-line @kbn/imports/no_unresolvable_imports +import { initPlugin } from '@frsource/cypress-plugin-visual-regression-diff/plugins'; import del from 'del'; import { some } from 'lodash'; import { Readable } from 'stream'; @@ -35,6 +37,8 @@ export function setupNodeEvents( synthtraceEsClient.pipeline(synthtraceEsClient.getDefaultPipeline(false)); + initPlugin(on, config); + on('task', { // send logs to node process log(message) { diff --git a/x-pack/plugins/apm/public/assistant_functions/get_apm_services_list.ts b/x-pack/plugins/apm/public/assistant_functions/get_apm_services_list.ts index 83f1c53d5ca70..9047f768449e5 100644 --- a/x-pack/plugins/apm/public/assistant_functions/get_apm_services_list.ts +++ b/x-pack/plugins/apm/public/assistant_functions/get_apm_services_list.ts @@ -66,10 +66,10 @@ export function registerGetApmServicesListFunction({ } as const, }, async ({ arguments: args }, signal) => { - return callApmApi('GET /internal/apm/assistant/get_services_list', { + return callApmApi('POST /internal/apm/assistant/get_services_list', { signal, params: { - query: args, + body: args, }, }); } diff --git a/x-pack/plugins/apm/public/assistant_functions/get_apm_timeseries.tsx b/x-pack/plugins/apm/public/assistant_functions/get_apm_timeseries.tsx index 9bdfd4b4789d8..56269d884ad84 100644 --- a/x-pack/plugins/apm/public/assistant_functions/get_apm_timeseries.tsx +++ b/x-pack/plugins/apm/public/assistant_functions/get_apm_timeseries.tsx @@ -140,9 +140,8 @@ export function registerGetApmTimeseriesFunction({ description: 'The name of the service', }, 'service.environment': { - ...NON_EMPTY_STRING, description: - 'The environment that the service is running in.', + 'The environment that the service is running in. If undefined, all environments will be included. Only use this if you have confirmed the environment that the service is running in.', }, filter: { type: 'string', @@ -160,12 +159,7 @@ export function registerGetApmTimeseriesFunction({ 'The offset. Right: 15m. 8h. 1d. Wrong: -15m. -8h. -1d.', }, }, - required: [ - 'service.name', - 'service.environment', - 'timeseries', - 'title', - ], + required: ['service.name', 'timeseries', 'title'], }, }, }, diff --git a/x-pack/plugins/apm/public/components/app/service_map/index.tsx b/x-pack/plugins/apm/public/components/app/service_map/index.tsx index d3422fac11546..b9a286ac05187 100644 --- a/x-pack/plugins/apm/public/components/app/service_map/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_map/index.tsx @@ -213,7 +213,7 @@ export function ServiceMap({
diff --git a/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_error_document/index.ts b/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_error_document/index.ts index c460acf4c3b3f..ffb1158270455 100644 --- a/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_error_document/index.ts +++ b/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_error_document/index.ts @@ -54,14 +54,14 @@ export async function getApmErrorDocument({ }, }); - const error = response.hits.hits[0]?._source as APMError; + const errorDoc = response.hits.hits[0]?._source as APMError; - if (!error) { + if (!errorDoc) { return undefined; } - return pick( - error, + const formattedResponse = pick( + errorDoc, 'message', 'error', '@timestamp', @@ -71,4 +71,11 @@ export async function getApmErrorDocument({ 'span.type', 'span.subtype' ); + + const { error, ...rest } = formattedResponse; + + return { + ...rest, + errorDoc: formattedResponse.error, + }; } diff --git a/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_timeseries/index.ts b/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_timeseries/index.ts index 0c95cf0231368..7d0b4e2c3a434 100644 --- a/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_timeseries/index.ts +++ b/x-pack/plugins/apm/server/routes/assistant_functions/get_apm_timeseries/index.ts @@ -14,7 +14,6 @@ import { environmentQuery } from '../../../../common/utils/environment_query'; import { getBucketSize } from '../../../../common/utils/get_bucket_size'; import { termQuery } from '../../../../common/utils/term_query'; import { APMEventClient } from '../../../lib/helpers/create_es_client/create_apm_event_client'; -import { environmentRt } from '../../default_api_types'; import { getErrorEventRate } from './get_error_event_rate'; import { getExitSpanFailureRate } from './get_exit_span_failure_rate'; import { getExitSpanLatency } from './get_exit_span_latency'; @@ -37,7 +36,6 @@ export const getApmTimeseriesRt = t.type({ stats: t.array( t.intersection([ t.type({ - 'service.environment': environmentRt.props.environment, 'service.name': t.string, title: t.string, timeseries: t.union([ @@ -85,6 +83,7 @@ export const getApmTimeseriesRt = t.type({ t.partial({ filter: t.string, offset: t.string, + 'service.environment': t.string, }), ]) ), diff --git a/x-pack/plugins/apm/server/routes/assistant_functions/route.ts b/x-pack/plugins/apm/server/routes/assistant_functions/route.ts index 486fdb57fca84..436f514e423ff 100644 --- a/x-pack/plugins/apm/server/routes/assistant_functions/route.ts +++ b/x-pack/plugins/apm/server/routes/assistant_functions/route.ts @@ -18,7 +18,6 @@ import { getApmEventClient } from '../../lib/helpers/get_apm_event_client'; import { getMlClient } from '../../lib/helpers/get_ml_client'; import { getRandomSampler } from '../../lib/helpers/get_random_sampler'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; -import { environmentRt } from '../default_api_types'; import { getServicesItems } from '../services/get_services/get_services_items'; import { CorrelationValue, @@ -26,20 +25,20 @@ import { getApmCorrelationValues, } from './get_apm_correlation_values'; import { - type APMDownstreamDependency, downstreamDependenciesRouteRt, getAssistantDownstreamDependencies, + type APMDownstreamDependency, } from './get_apm_downstream_dependencies'; import { errorRouteRt, getApmErrorDocument } from './get_apm_error_document'; import { getApmServiceSummary, - type ServiceSummary, serviceSummaryRouteRt, + type ServiceSummary, } from './get_apm_service_summary'; import { - type ApmTimeseries, getApmTimeseries, getApmTimeseriesRt, + type ApmTimeseries, } from './get_apm_timeseries'; const getApmTimeSeriesRoute = createApmServerRoute({ @@ -204,15 +203,15 @@ interface ApmServicesListItem { type ApmServicesListContent = ApmServicesListItem[]; const getApmServicesListRoute = createApmServerRoute({ - endpoint: 'GET /internal/apm/assistant/get_services_list', + endpoint: 'POST /internal/apm/assistant/get_services_list', params: t.type({ - query: t.intersection([ + body: t.intersection([ t.type({ start: t.string, end: t.string, }), t.partial({ - 'service.environment': environmentRt.props.environment, + 'service.environment': t.string, healthStatus: t.array( t.union([ t.literal(ServiceHealthStatus.unknown), @@ -229,9 +228,9 @@ const getApmServicesListRoute = createApmServerRoute({ }, handler: async (resources): Promise<{ content: ApmServicesListContent }> => { const { params } = resources; - const { query } = params; + const { body } = params; - const { healthStatus } = query; + const { healthStatus } = body; const [apmEventClient, apmAlertsClient, mlClient, randomSampler] = await Promise.all([ @@ -245,8 +244,8 @@ const getApmServicesListRoute = createApmServerRoute({ }), ]); - const start = datemath.parse(query.start)?.valueOf()!; - const end = datemath.parse(query.end)?.valueOf()!; + const start = datemath.parse(body.start)?.valueOf()!; + const end = datemath.parse(body.end)?.valueOf()!; const serviceItems = await getServicesItems({ apmAlertsClient, @@ -254,7 +253,7 @@ const getApmServicesListRoute = createApmServerRoute({ documentType: ApmDocumentType.TransactionMetric, start, end, - environment: query['service.environment'] ?? ENVIRONMENT_ALL.value, + environment: body['service.environment'] || ENVIRONMENT_ALL.value, kuery: '', logger: resources.logger, randomSampler, diff --git a/x-pack/plugins/apm/server/routes/fleet/source_maps.ts b/x-pack/plugins/apm/server/routes/fleet/source_maps.ts index 4eb0b011cef3c..ad2bc870c7f33 100644 --- a/x-pack/plugins/apm/server/routes/fleet/source_maps.ts +++ b/x-pack/plugins/apm/server/routes/fleet/source_maps.ts @@ -19,18 +19,12 @@ import { getPackagePolicyWithSourceMap } from './get_package_policy_decorators'; const doUnzip = promisify(unzip); -interface ApmMapArtifactBody { +interface ApmSourceMapArtifactBody { serviceName: string; serviceVersion: string; bundleFilepath: string; - sourceMap: string; -} - -interface ApmSourceMapArtifactBody - extends Omit { sourceMap: SourceMap; } - export type ArtifactSourceMap = Omit & { body: ApmSourceMapArtifactBody; }; @@ -110,23 +104,6 @@ export async function createFleetSourceMapArtifact({ }); } -export async function createFleetAndroidMapArtifact({ - apmArtifactBody, - fleetPluginStart, -}: { - apmArtifactBody: ApmMapArtifactBody; - fleetPluginStart: FleetPluginStart; -}) { - const apmArtifactClient = getApmArtifactClient(fleetPluginStart); - const identifier = `${apmArtifactBody.serviceName}-${apmArtifactBody.serviceVersion}-android`; - - return apmArtifactClient.createArtifact({ - type: 'sourcemap', - identifier, - content: JSON.stringify(apmArtifactBody), - }); -} - export async function deleteFleetSourcemapArtifact({ id, fleetPluginStart, diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/route.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/route.ts index 434ae4785ce5a..3698a13a1f2a6 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/route.ts +++ b/x-pack/plugins/apm/server/routes/settings/apm_indices/route.ts @@ -8,12 +8,12 @@ import * as t from 'io-ts'; import { SavedObject } from '@kbn/core/server'; import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; +import { saveApmIndices } from '@kbn/apm-data-access-plugin/server/saved_objects/apm_indices'; import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; import { getApmIndexSettings, ApmIndexSettingsResponse, } from './get_apm_indices'; -import { saveApmIndices } from './save_apm_indices'; // get list of apm indices and values const apmIndexSettingsRoute = createApmServerRoute({ diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts b/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts deleted file mode 100644 index e9d2bd5fbea92..0000000000000 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObjectsClientContract } from '@kbn/core/server'; -import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; -import { - APMIndicesSavedObjectBody, - APM_INDEX_SETTINGS_SAVED_OBJECT_ID, - APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, -} from '@kbn/apm-data-access-plugin/server/saved_objects/apm_indices'; -import { withApmSpan } from '../../../utils/with_apm_span'; - -export function saveApmIndices( - savedObjectsClient: SavedObjectsClientContract, - apmIndices: Partial -) { - return withApmSpan('save_apm_indices', () => - savedObjectsClient.create( - APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, - { apmIndices: removeEmpty(apmIndices), isSpaceAware: true }, - { id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, overwrite: true } - ) - ); -} - -// remove empty/undefined values -function removeEmpty(apmIndices: Partial) { - return Object.entries(apmIndices) - .map(([key, value]) => [key, value?.trim()]) - .filter(([_, value]) => !!value) - .reduce((obj, [key, value]) => { - obj[key] = value; - return obj; - }, {} as Record); -} diff --git a/x-pack/plugins/apm/server/routes/source_maps/bulk_create_apm_source_maps.ts b/x-pack/plugins/apm/server/routes/source_maps/bulk_create_apm_source_maps.ts index 3aa5c9a780aa3..1495f89f0fceb 100644 --- a/x-pack/plugins/apm/server/routes/source_maps/bulk_create_apm_source_maps.ts +++ b/x-pack/plugins/apm/server/routes/source_maps/bulk_create_apm_source_maps.ts @@ -10,7 +10,7 @@ import { Artifact } from '@kbn/fleet-plugin/server'; import { getUnzippedArtifactBody } from '../fleet/source_maps'; import { APM_SOURCE_MAP_INDEX } from '../settings/apm_indices/apm_system_index_constants'; import { ApmSourceMap } from './create_apm_source_map_index_template'; -import { getEncodedSourceMapContent, getSourceMapId } from './sourcemap_utils'; +import { getEncodedContent, getSourceMapId } from './sourcemap_utils'; export async function bulkCreateApmSourceMaps({ artifacts, @@ -24,7 +24,7 @@ export async function bulkCreateApmSourceMaps({ const { serviceName, serviceVersion, bundleFilepath, sourceMap } = await getUnzippedArtifactBody(artifact.body); - const { contentEncoded, contentHash } = await getEncodedSourceMapContent( + const { contentEncoded, contentHash } = await getEncodedContent( sourceMap ); diff --git a/x-pack/plugins/apm/server/routes/source_maps/create_apm_source_map.ts b/x-pack/plugins/apm/server/routes/source_maps/create_apm_source_map.ts index bda2601080434..95614778024fa 100644 --- a/x-pack/plugins/apm/server/routes/source_maps/create_apm_source_map.ts +++ b/x-pack/plugins/apm/server/routes/source_maps/create_apm_source_map.ts @@ -10,11 +10,7 @@ import { Logger } from '@kbn/core/server'; import { APM_SOURCE_MAP_INDEX } from '../settings/apm_indices/apm_system_index_constants'; import { ApmSourceMap } from './create_apm_source_map_index_template'; import { SourceMap } from './route'; -import { - getEncodedSourceMapContent, - getEncodedContent, - getSourceMapId, -} from './sourcemap_utils'; +import { getEncodedContent, getSourceMapId } from './sourcemap_utils'; export async function createApmSourceMap({ internalESClient, @@ -35,75 +31,9 @@ export async function createApmSourceMap({ serviceName: string; serviceVersion: string; }) { - const { contentEncoded, contentHash } = await getEncodedSourceMapContent( + const { contentEncoded, contentHash } = await getEncodedContent( sourceMapContent ); - return await doCreateApmMap({ - internalESClient, - logger, - fleetId, - created, - bundleFilepath, - serviceName, - serviceVersion, - contentEncoded, - contentHash, - }); -} - -export async function createApmAndroidMap({ - internalESClient, - logger, - fleetId, - created, - mapContent, - bundleFilepath, - serviceName, - serviceVersion, -}: { - internalESClient: ElasticsearchClient; - logger: Logger; - fleetId: string; - created: string; - mapContent: string; - bundleFilepath: string; - serviceName: string; - serviceVersion: string; -}) { - const { contentEncoded, contentHash } = await getEncodedContent(mapContent); - return await doCreateApmMap({ - internalESClient, - logger, - fleetId, - created, - bundleFilepath, - serviceName, - serviceVersion, - contentEncoded, - contentHash, - }); -} -async function doCreateApmMap({ - internalESClient, - logger, - fleetId, - created, - bundleFilepath, - serviceName, - serviceVersion, - contentEncoded, - contentHash, -}: { - internalESClient: ElasticsearchClient; - logger: Logger; - fleetId: string; - created: string; - bundleFilepath: string; - serviceName: string; - serviceVersion: string; - contentEncoded: string; - contentHash: string; -}) { const doc: ApmSourceMap = { fleet_id: fleetId, created, diff --git a/x-pack/plugins/apm/server/routes/source_maps/route.ts b/x-pack/plugins/apm/server/routes/source_maps/route.ts index c0cc2404af492..ae29267644668 100644 --- a/x-pack/plugins/apm/server/routes/source_maps/route.ts +++ b/x-pack/plugins/apm/server/routes/source_maps/route.ts @@ -9,24 +9,19 @@ import { SavedObjectsClientContract } from '@kbn/core/server'; import { Artifact } from '@kbn/fleet-plugin/server'; import { jsonRt, toNumberRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; -import { either } from 'fp-ts/lib/Either'; import { ApmFeatureFlags } from '../../../common/apm_feature_flags'; import { getInternalSavedObjectsClient } from '../../lib/helpers/get_internal_saved_objects_client'; import { stringFromBufferRt } from '../../utils/string_from_buffer_rt'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { createFleetSourceMapArtifact, - createFleetAndroidMapArtifact, deleteFleetSourcemapArtifact, getCleanedBundleFilePath, listSourceMapArtifacts, ListSourceMapArtifactsResponse, updateSourceMapsOnFleetPolicies, } from '../fleet/source_maps'; -import { - createApmSourceMap, - createApmAndroidMap, -} from './create_apm_source_map'; +import { createApmSourceMap } from './create_apm_source_map'; import { deleteApmSourceMap } from './delete_apm_sourcemap'; import { runFleetSourcemapArtifactsMigration } from './schedule_source_map_migration'; @@ -46,24 +41,6 @@ export const sourceMapRt = t.intersection([ export type SourceMap = t.TypeOf; -const androidMapValidation = new t.Type( - 'ANDROID_MAP_VALIDATION', - t.string.is, - (input, context): t.Validation => - either.chain( - t.string.validate(input, context), - (str): t.Validation => { - const firstLine = str.split('\n', 1)[0]; - if (firstLine.trim() === '# compiler: R8') { - return t.success(str); - } else { - return t.failure(input, context); - } - } - ), - (a): string => a -); - function throwNotImplementedIfSourceMapNotAvailable( featureFlags: ApmFeatureFlags ): void { @@ -114,7 +91,7 @@ const uploadSourceMapRoute = createApmServerRoute({ endpoint: 'POST /api/apm/sourcemaps 2023-10-31', options: { tags: ['access:apm', 'access:apm_write'], - body: { accepts: ['multipart/form-data'], maxBytes: 100 * 1024 * 1024 }, + body: { accepts: ['multipart/form-data'] }, }, params: t.type({ body: t.type({ @@ -192,85 +169,6 @@ const uploadSourceMapRoute = createApmServerRoute({ }, }); -const uploadAndroidMapRoute = createApmServerRoute({ - endpoint: 'POST /api/apm/androidmaps 2023-10-31', - options: { - tags: ['access:apm', 'access:apm_write'], - body: { accepts: ['multipart/form-data'], maxBytes: 100 * 1024 * 1024 }, - }, - params: t.type({ - body: t.type({ - service_name: t.string, - service_version: t.string, - map_file: t - .union([t.string, stringFromBufferRt]) - .pipe(androidMapValidation), - }), - }), - handler: async ({ - params, - plugins, - core, - logger, - featureFlags, - }): Promise => { - throwNotImplementedIfSourceMapNotAvailable(featureFlags); - - const { - service_name: serviceName, - service_version: serviceVersion, - map_file: sourceMapContent, - } = params.body; - const bundleFilepath = 'android'; - const fleetPluginStart = await plugins.fleet?.start(); - const coreStart = await core.start(); - const internalESClient = coreStart.elasticsearch.client.asInternalUser; - const savedObjectsClient = await getInternalSavedObjectsClient(coreStart); - try { - if (fleetPluginStart) { - // create source map as fleet artifact - const artifact = await createFleetAndroidMapArtifact({ - fleetPluginStart, - apmArtifactBody: { - serviceName, - serviceVersion, - bundleFilepath, - sourceMap: sourceMapContent, - }, - }); - - // sync source map to APM managed index - await createApmAndroidMap({ - internalESClient, - logger, - fleetId: artifact.id, - created: artifact.created, - mapContent: sourceMapContent, - bundleFilepath, - serviceName, - serviceVersion, - }); - - // sync source map to fleet policy - await updateSourceMapsOnFleetPolicies({ - coreStart, - fleetPluginStart, - savedObjectsClient: - savedObjectsClient as unknown as SavedObjectsClientContract, - internalESClient, - }); - - return artifact; - } - } catch (e) { - throw Boom.internal( - 'Something went wrong while creating a new android map', - e - ); - } - }, -}); - const deleteSourceMapRoute = createApmServerRoute({ endpoint: 'DELETE /api/apm/sourcemaps/{id} 2023-10-31', options: { tags: ['access:apm', 'access:apm_write'] }, @@ -332,6 +230,5 @@ export const sourceMapsRouteRepository = { ...listSourceMapRoute, ...uploadSourceMapRoute, ...deleteSourceMapRoute, - ...uploadAndroidMapRoute, ...migrateFleetArtifactsSourceMapRoute, }; diff --git a/x-pack/plugins/apm/server/routes/source_maps/sourcemap_utils.ts b/x-pack/plugins/apm/server/routes/source_maps/sourcemap_utils.ts index 408d1b98f9c5a..20ff2fa4bd41c 100644 --- a/x-pack/plugins/apm/server/routes/source_maps/sourcemap_utils.ts +++ b/x-pack/plugins/apm/server/routes/source_maps/sourcemap_utils.ts @@ -16,11 +16,8 @@ function asSha256Encoded(content: BinaryLike): string { return createHash('sha256').update(content).digest('hex'); } -export async function getEncodedSourceMapContent(sourceMapContent: SourceMap) { - return getEncodedContent(JSON.stringify(sourceMapContent)); -} -export async function getEncodedContent(textContent: string) { - const contentBuffer = Buffer.from(textContent); +export async function getEncodedContent(sourceMapContent: SourceMap) { + const contentBuffer = Buffer.from(JSON.stringify(sourceMapContent)); const contentZipped = await deflateAsync(contentBuffer); const contentEncoded = contentZipped.toString('base64'); const contentHash = asSha256Encoded(contentZipped); diff --git a/x-pack/plugins/apm_data_access/server/saved_objects/apm_indices.ts b/x-pack/plugins/apm_data_access/server/saved_objects/apm_indices.ts index 7ab90ef0a605c..96b9c31d6b91c 100644 --- a/x-pack/plugins/apm_data_access/server/saved_objects/apm_indices.ts +++ b/x-pack/plugins/apm_data_access/server/saved_objects/apm_indices.ts @@ -11,6 +11,7 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { SavedObjectsClientContract } from '@kbn/core/server'; import { updateApmOssIndexPaths } from './migrations/update_apm_oss_index_paths'; +import { APMIndices } from '..'; export const APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE = 'apm-indices'; export const APM_INDEX_SETTINGS_SAVED_OBJECT_ID = 'apm-indices'; @@ -73,6 +74,28 @@ export const apmIndicesSavedObjectDefinition: SavedObjectsType = { }, }; +export function saveApmIndices( + savedObjectsClient: SavedObjectsClientContract, + apmIndices: Partial +) { + return savedObjectsClient.create( + APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE, + { apmIndices: removeEmpty(apmIndices), isSpaceAware: true }, + { id: APM_INDEX_SETTINGS_SAVED_OBJECT_ID, overwrite: true } + ); +} + +// remove empty/undefined values +function removeEmpty(apmIndices: Partial) { + return Object.entries(apmIndices) + .map(([key, value]) => [key, value?.trim()]) + .filter(([_, value]) => !!value) + .reduce((obj, [key, value]) => { + obj[key] = value; + return obj; + }, {} as Record); +} + export async function getApmIndicesSavedObject(savedObjectsClient: SavedObjectsClientContract) { try { const apmIndicesSavedObject = await savedObjectsClient.get>( diff --git a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts b/x-pack/plugins/apm_data_access/server/saved_objects/save_apm_indices.test.ts similarity index 95% rename from x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts rename to x-pack/plugins/apm_data_access/server/saved_objects/save_apm_indices.test.ts index e72282ba6275a..22278e6c16b56 100644 --- a/x-pack/plugins/apm/server/routes/settings/apm_indices/save_apm_indices.test.ts +++ b/x-pack/plugins/apm_data_access/server/saved_objects/save_apm_indices.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { saveApmIndices } from './save_apm_indices'; +import { saveApmIndices } from './apm_indices'; import { SavedObjectsClientContract } from '@kbn/core/server'; describe('saveApmIndices', () => { diff --git a/x-pack/plugins/cloud_security_posture/server/config.ts b/x-pack/plugins/cloud_security_posture/server/config.ts index 472f66c78be8c..735cdb3cbe00f 100644 --- a/x-pack/plugins/cloud_security_posture/server/config.ts +++ b/x-pack/plugins/cloud_security_posture/server/config.ts @@ -4,14 +4,23 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { schema, type TypeOf } from '@kbn/config-schema'; import type { PluginConfigDescriptor } from '@kbn/core/server'; +import { schema, offeringBasedSchema, type TypeOf } from '@kbn/config-schema'; + const configSchema = schema.object({ enabled: schema.boolean({ defaultValue: true }), + + // Setting only allowed in the Serverless offering + serverless: schema.object({ + enabled: offeringBasedSchema({ + serverless: schema.literal(true), + options: { defaultValue: schema.contextRef('serverless') }, + }), + }), }); -type CloudSecurityPostureConfig = TypeOf; + +export type CloudSecurityPostureConfig = TypeOf; export const config: PluginConfigDescriptor = { schema: configSchema, diff --git a/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts b/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts index c269e201f4243..06e13248fa1c5 100644 --- a/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts +++ b/x-pack/plugins/cloud_security_posture/server/create_indices/create_indices.ts @@ -4,10 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { errors } from '@elastic/elasticsearch'; import type { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types'; - +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import { BENCHMARK_SCORE_INDEX_DEFAULT_NS, BENCHMARK_SCORE_INDEX_PATTERN, @@ -20,8 +19,21 @@ import { latestFindingsPipelineIngestConfig, scorePipelineIngestConfig } from '. import { latestIndexConfigs } from './latest_indices'; import { IndexConfig, IndexTemplateParams } from './types'; +import { CloudSecurityPostureConfig } from '../config'; + +interface IndexTemplateSettings { + index: { + default_pipeline: string; + }; + lifecycle?: { name: string }; +} + // TODO: Add integration tests -export const initializeCspIndices = async (esClient: ElasticsearchClient, logger: Logger) => { +export const initializeCspIndices = async ( + esClient: ElasticsearchClient, + cloudSecurityPostureConfig: CloudSecurityPostureConfig, + logger: Logger +) => { await Promise.allSettled([ createPipelineIfNotExists(esClient, scorePipelineIngestConfig, logger), createPipelineIfNotExists(esClient, latestFindingsPipelineIngestConfig, logger), @@ -32,9 +44,14 @@ export const initializeCspIndices = async (esClient: ElasticsearchClient, logger createVulnerabilitiesLatestIndexPromise, createBenchmarkScoreIndexPromise, ] = await Promise.allSettled([ - createLatestIndex(esClient, logger, latestIndexConfigs.findings), - createLatestIndex(esClient, logger, latestIndexConfigs.vulnerabilities), - createBenchmarkScoreIndex(esClient, logger), + createLatestIndex(esClient, latestIndexConfigs.findings, cloudSecurityPostureConfig, logger), + createLatestIndex( + esClient, + latestIndexConfigs.vulnerabilities, + cloudSecurityPostureConfig, + logger + ), + createBenchmarkScoreIndex(esClient, cloudSecurityPostureConfig, logger), ]); if (createFindingsLatestIndexPromise.status === 'rejected') { @@ -48,25 +65,31 @@ export const initializeCspIndices = async (esClient: ElasticsearchClient, logger } }; -const createBenchmarkScoreIndex = async (esClient: ElasticsearchClient, logger: Logger) => { +const createBenchmarkScoreIndex = async ( + esClient: ElasticsearchClient, + cloudSecurityPostureConfig: CloudSecurityPostureConfig, + logger: Logger +) => { try { // Deletes old assets from previous versions as part of upgrade process const INDEX_TEMPLATE_V830 = 'cloud_security_posture.scores'; await deleteIndexTemplateSafe(esClient, logger, INDEX_TEMPLATE_V830); + const settings: IndexTemplateSettings = { + index: { + default_pipeline: latestFindingsPipelineIngestConfig.id, + }, + lifecycle: { name: '' }, + }; + if (cloudSecurityPostureConfig.serverless.enabled) delete settings.lifecycle; + // We always want to keep the index template updated await esClient.indices.putIndexTemplate({ name: BENCHMARK_SCORE_INDEX_TEMPLATE_NAME, index_patterns: BENCHMARK_SCORE_INDEX_PATTERN, template: { mappings: benchmarkScoreMapping, - settings: { - default_pipeline: scorePipelineIngestConfig.id, - // TODO: once we will convert the score index to datastream we will no longer override the ilm to be empty - lifecycle: { - name: '', - }, - }, + settings, }, _meta: { package: { @@ -98,8 +121,9 @@ const createBenchmarkScoreIndex = async (esClient: ElasticsearchClient, logger: const createLatestIndex = async ( esClient: ElasticsearchClient, - logger: Logger, - indexConfig: IndexConfig + indexConfig: IndexConfig, + cloudSecurityPostureConfig: CloudSecurityPostureConfig, + logger: Logger ) => { const { indexName, indexPattern, indexTemplateName, indexDefaultName } = indexConfig; try { @@ -121,7 +145,7 @@ const createLatestIndex = async ( }; // We always want to keep the index template updated - await updateIndexTemplate(esClient, logger, indexTemplateParams); + await updateIndexTemplate(esClient, indexTemplateParams, cloudSecurityPostureConfig, logger); const result = await createIndexSafe(esClient, logger, indexDefaultName); @@ -192,10 +216,21 @@ const createIndexSafe = async (esClient: ElasticsearchClient, logger: Logger, in const updateIndexTemplate = async ( esClient: ElasticsearchClient, - logger: Logger, - indexTemplateParams: IndexTemplateParams + indexTemplateParams: IndexTemplateParams, + cloudSecurityPostureConfig: CloudSecurityPostureConfig, + logger: Logger ) => { const { indexTemplateName, indexPattern, template, composedOf, _meta } = indexTemplateParams; + + const settings: IndexTemplateSettings = { + ...template?.settings, // nothing inside + index: { + default_pipeline: latestFindingsPipelineIngestConfig.id, + }, + lifecycle: { name: '' }, + }; + if (cloudSecurityPostureConfig.serverless.enabled) delete settings.lifecycle; + try { await esClient.indices.putIndexTemplate({ name: indexTemplateName, @@ -203,18 +238,13 @@ const updateIndexTemplate = async ( priority: 500, template: { mappings: template?.mappings, - settings: { - ...template?.settings, - default_pipeline: latestFindingsPipelineIngestConfig.id, - lifecycle: { - name: '', - }, - }, + settings, aliases: template?.aliases, }, _meta, composed_of: composedOf, }); + logger.info(`Updated index template successfully [Name: ${indexTemplateName}]`); } catch (e) { logger.error(`Failed to update index template [Name: ${indexTemplateName}]`); diff --git a/x-pack/plugins/cloud_security_posture/server/plugin.ts b/x-pack/plugins/cloud_security_posture/server/plugin.ts index 30ff887a354ca..8b77581efd39d 100755 --- a/x-pack/plugins/cloud_security_posture/server/plugin.ts +++ b/x-pack/plugins/cloud_security_posture/server/plugin.ts @@ -49,6 +49,7 @@ import { setupFindingsStatsTask, } from './tasks/findings_stats_task'; import { registerCspmUsageCollector } from './lib/telemetry/collectors/register'; +import { CloudSecurityPostureConfig } from './config'; export class CspPlugin implements @@ -60,6 +61,7 @@ export class CspPlugin > { private readonly logger: Logger; + private readonly config: CloudSecurityPostureConfig; private isCloudEnabled?: boolean; /** @@ -69,8 +71,9 @@ export class CspPlugin */ #isInitialized: boolean = false; - constructor(initializerContext: PluginInitializerContext) { + constructor(initializerContext: PluginInitializerContext) { this.logger = initializerContext.logger.get(); + this.config = initializerContext.config.get(); } public setup( @@ -203,7 +206,7 @@ export class CspPlugin async initialize(core: CoreStart, taskManager: TaskManagerStartContract): Promise { this.logger.debug('initialize'); const esClient = core.elasticsearch.client.asInternalUser; - await initializeCspIndices(esClient, this.logger); + await initializeCspIndices(esClient, this.config, this.logger); await initializeCspTransforms(esClient, this.logger); await scheduleFindingsStatsTask(taskManager, this.logger); this.#isInitialized = true; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/pipelines/fetch_index_pipeline_parameters.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/pipelines/fetch_index_pipeline_parameters.test.ts new file mode 100644 index 0000000000000..9290289a76b72 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/pipelines/fetch_index_pipeline_parameters.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { mockHttpValues } from '../../../__mocks__/kea_logic'; + +import { nextTick } from '@kbn/test-jest-helpers'; + +import { fetchIndexPipelineParams } from './fetch_index_pipeline_parameters'; + +describe('FetchIndexPipelineParametersApiLogic', () => { + const { http } = mockHttpValues; + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('fetchIndexPipelineParams', () => { + it('calls correct api', async () => { + const response = { + 'pipeline-name': {}, + }; + const promise = Promise.resolve(response); + http.get.mockReturnValue(promise); + const result = fetchIndexPipelineParams({ indexName: 'index-name' }); + await nextTick(); + expect(http.get).toHaveBeenCalledWith( + '/internal/enterprise_search/indices/index-name/pipeline_parameters' + ); + await expect(result).resolves.toEqual(response); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/pipelines/fetch_index_pipeline_parameters.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/pipelines/fetch_index_pipeline_parameters.ts new file mode 100644 index 0000000000000..901a40e5c9e23 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/pipelines/fetch_index_pipeline_parameters.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IngestPipelineParams } from '../../../../../common/types/connectors'; +import { Actions, createApiLogic } from '../../../shared/api_logic/create_api_logic'; +import { HttpLogic } from '../../../shared/http'; + +export interface FetchIndexPipelineParametersArgs { + indexName: string; +} +export type FetchIndexPipelineParametersResponse = IngestPipelineParams; + +export const fetchIndexPipelineParams = async ({ indexName }: FetchIndexPipelineParametersArgs) => { + const route = `/internal/enterprise_search/indices/${indexName}/pipeline_parameters`; + + return await HttpLogic.values.http.get(route); +}; + +export const FetchIndexPipelineParametersApiLogic = createApiLogic( + ['fetch_index_pipeline_params_api_logic'], + fetchIndexPipelineParams, + { + showErrorFlash: false, + } +); + +export type FetchIndexPipelineParametersApiLogicActions = Actions< + FetchIndexPipelineParametersArgs, + FetchIndexPipelineParametersResponse +>; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/getting_started.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/getting_started.tsx index 804dd5f09eee1..37f96921227e7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/getting_started.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/getting_started.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { css } from '@emotion/react'; import dedent from 'dedent'; @@ -29,6 +29,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import { SelectClientPanel, LanguageDefinition, + LanguageDefinitionSnippetArguments, LanguageClientPanel, InstallClientPanel, OverviewPanel, @@ -50,6 +51,7 @@ import { IndexViewLogic } from '../../index_view_logic'; import { OverviewLogic } from '../../overview.logic'; import { GenerateApiKeyModal } from '../generate_api_key_modal/modal'; +import { consoleDefinition } from './languages/console'; import { javascriptDefinition } from './languages/javascript'; import { languageDefinitions } from './languages/languages'; @@ -57,17 +59,28 @@ const DEFAULT_URL = 'https://localhost:9200'; export const APIGettingStarted = () => { const { http } = useValues(HttpLogic); - const { apiKey, isGenerateModalOpen } = useValues(OverviewLogic); - const { openGenerateModal, closeGenerateModal } = useActions(OverviewLogic); + const { apiKey, isGenerateModalOpen, indexPipelineParameters } = useValues(OverviewLogic); + const { fetchIndexPipelineParameters, openGenerateModal, closeGenerateModal } = + useActions(OverviewLogic); const { indexName } = useValues(IndexViewLogic); const { services } = useKibana(); const cloudContext = useCloudDetails(); - const codeArgs = { + useEffect(() => { + fetchIndexPipelineParameters({ indexName }); + }, [indexName]); + + const codeArgs: LanguageDefinitionSnippetArguments = { apiKey, cloudId: cloudContext.cloudId, + extraIngestDocumentValues: { + _extract_binary_content: indexPipelineParameters.extract_binary_content, + _reduce_whitespace: indexPipelineParameters.reduce_whitespace, + _run_ml_inference: indexPipelineParameters.run_ml_inference, + }, indexName, + ingestPipeline: indexPipelineParameters.name, url: cloudContext.elasticsearchUrl || DEFAULT_URL, }; const assetBasePath = http.basePath.prepend(`/plugins/${PLUGIN_ID}/assets/client_libraries/`); @@ -344,7 +357,11 @@ export const APIGettingStarted = () => { { 'buildSearchQuery', codeArgs )} - consoleRequest={getConsoleRequest('buildSearchQuery')} + consoleRequest={getLanguageDefinitionCodeSnippet( + consoleDefinition, + 'buildSearchQuery', + codeArgs + )} selectedLanguage={selectedLanguage} setSelectedLanguage={setSelectedLanguage} assetBasePath={assetBasePath} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/console.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/console.ts new file mode 100644 index 0000000000000..9d395b0a68c67 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/console.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LanguageDefinition } from '@kbn/search-api-panels'; + +import { ingestKeysToJSON } from './helpers'; + +export const consoleDefinition: Partial = { + buildSearchQuery: ({ indexName }) => `POST /${indexName ?? 'books'}/_search?pretty + { + "query": { + "query_string": { + "query": "snow" + } + } + }`, + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; + return `POST _bulk?pretty${ingestPipeline ? `&pipeline=${ingestPipeline}` : ''} + { "index" : { "_index" : "${indexName}" } } + {"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470${ingestDocumentKeys}} + { "index" : { "_index" : "${indexName}" } } + {"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585${ingestDocumentKeys}} + { "index" : { "_index" : "${indexName}" } } + {"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328${ingestDocumentKeys}} + { "index" : { "_index" : "${indexName}" } } + {"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227${ingestDocumentKeys}} + { "index" : { "_index" : "${indexName}" } } + {"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268${ingestDocumentKeys}} + { "index" : { "_index" : "${indexName}" } } + {"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311${ingestDocumentKeys}}`; + }, +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/curl.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/curl.ts index 45c67a02798ec..8bac32d754064 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/curl.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/curl.ts @@ -10,6 +10,8 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels'; import { docLinks } from '../../../../../../shared/doc_links'; +import { ingestKeysToJSON } from './helpers'; + export const curlDefinition: LanguageDefinition = { buildSearchQuery: ({ indexName }) => `curl -X POST "\$\{ES_URL\}/${indexName}/_search?pretty" \\ -H "Authorization: ApiKey "\$\{API_KEY\}"" \\ @@ -33,23 +35,28 @@ export API_KEY="${apiKey}"`, }, iconType: 'curl.svg', id: Languages.CURL, - ingestData: ({ indexName }) => `curl -X POST "\$\{ES_URL\}/_bulk?pretty" \\ + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; + return `curl -X POST "\$\{ES_URL\}/_bulk?pretty${ + ingestPipeline ? `&pipeline=${ingestPipeline}` : '' + }" \\ -H "Authorization: ApiKey "\$\{API_KEY\}"" \\ -H "Content-Type: application/json" \\ -d' { "index" : { "_index" : "${indexName}" } } -{"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470} +{"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470${ingestDocumentKeys}} { "index" : { "_index" : "${indexName}" } } -{"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585} +{"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585${ingestDocumentKeys}} { "index" : { "_index" : "${indexName}" } } -{"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328} +{"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328${ingestDocumentKeys}} { "index" : { "_index" : "${indexName}" } } -{"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227} +{"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227${ingestDocumentKeys}} { "index" : { "_index" : "${indexName}" } } -{"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268} +{"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268${ingestDocumentKeys}} { "index" : { "_index" : "${indexName}" } } -{"name": "The Handmaid'"'"'s Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311} -'`, +{"name": "The Handmaid'"'"'s Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311${ingestDocumentKeys}} +'`; + }, ingestDataIndex: '', installClient: `# if cURL is not already installed on your system # then install it with the package manager of your choice diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/go.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/go.ts index fc3d8226f9a0c..6c504bba26bdc 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/go.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/go.ts @@ -10,6 +10,8 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels'; import { docLinks } from '../../../../../../shared/doc_links'; +import { ingestKeysToJSON } from './helpers'; + export const goDefinition: LanguageDefinition = { buildSearchQuery: ({ indexName }) => `searchResp, err := es.Search( es.Search.WithContext(context.Background()), @@ -56,27 +58,32 @@ if err != nil { }, iconType: 'go.svg', id: Languages.GO, - ingestData: ({ indexName }) => `buf := bytes.NewBufferString(\` + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; + return `buf := bytes.NewBufferString(\` {"index":{"_id":"9780553351927"}} -{"name":"Snow Crash","author":"Neal Stephenson","release_date":"1992-06-01","page_count": 470} +{"name":"Snow Crash","author":"Neal Stephenson","release_date":"1992-06-01","page_count": 470${ingestDocumentKeys}} { "index": { "_id": "9780441017225"}} -{"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585} +{"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585${ingestDocumentKeys}} { "index": { "_id": "9780451524935"}} -{"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328} +{"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328${ingestDocumentKeys}} { "index": { "_id": "9781451673319"}} -{"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227} +{"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227${ingestDocumentKeys}} { "index": { "_id": "9780060850524"}} -{"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268} +{"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268${ingestDocumentKeys}} { "index": { "_id": "9780385490818"}} -{"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311} +{"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311${ingestDocumentKeys}} \`) ingestResult, err := es.Bulk( bytes.NewReader(buf.Bytes()), - es.Bulk.WithIndex("${indexName}"), + es.Bulk.WithIndex("${indexName}"),${ + ingestPipeline ? `\n es.Bulk.WithPipeline("${ingestPipeline}"),` : '' + } ) -fmt.Println(ingestResult, err)`, +fmt.Println(ingestResult, err)`; + }, ingestDataIndex: '', installClient: 'go get github.com/elastic/go-elasticsearch/v8@latest', name: i18n.translate('xpack.enterpriseSearch.languages.go', { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/helpers.test.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/helpers.test.ts new file mode 100644 index 0000000000000..df13ea273061e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/helpers.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ingestKeysToJSON, ingestKeysToPHP, ingestKeysToRuby } from './helpers'; + +describe('getting started language helpers', () => { + describe('ingestKeysToJSON', () => { + it('return empty string when given undefined', () => { + expect(ingestKeysToJSON(undefined)).toEqual(''); + }); + it('return json keys with quotes when given expected data', () => { + expect(ingestKeysToJSON({ _foo: true, _bar: false })).toEqual( + ', "_foo": true, "_bar": false' + ); + }); + }); + describe('ingestKeysToPHP', () => { + it('return empty string when given undefined', () => { + expect(ingestKeysToPHP(undefined)).toEqual(''); + }); + it('return json keys with quotes when given expected data', () => { + expect(ingestKeysToPHP({ _foo: true, _bar: false })).toEqual( + `\n '_foo' => true,\n '_bar' => false,` + ); + }); + }); + describe('ingestKeysToRuby', () => { + it('return empty string when given undefined', () => { + expect(ingestKeysToRuby(undefined)).toEqual(''); + }); + it('return json keys with quotes when given expected data', () => { + expect(ingestKeysToRuby({ _foo: true, _bar: false })).toEqual(', _foo: true, _bar: false'); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/helpers.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/helpers.ts new file mode 100644 index 0000000000000..5d98779a851b3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/helpers.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { LanguageDefinitionSnippetArguments } from '@kbn/search-api-panels'; + +export const ingestKeysToJSON = ( + extraIngestDocumentValues: LanguageDefinitionSnippetArguments['extraIngestDocumentValues'] +) => + extraIngestDocumentValues + ? Object.entries(extraIngestDocumentValues).reduce((result, value) => { + result += `, "${value[0]}": ${value[1]}`; + return result; + }, '') + : ''; + +export const ingestKeysToPHP = ( + extraIngestDocumentValues: LanguageDefinitionSnippetArguments['extraIngestDocumentValues'] +) => + extraIngestDocumentValues + ? Object.entries(extraIngestDocumentValues).reduce((result, value) => { + result += `\n '${value[0]}' => ${value[1]},`; + return result; + }, '') + : ''; + +export const ingestKeysToRuby = ( + extraIngestDocumentValues: LanguageDefinitionSnippetArguments['extraIngestDocumentValues'] +) => + extraIngestDocumentValues + ? Object.entries(extraIngestDocumentValues).reduce((result, value) => { + result += `, ${value[0]}: ${value[1]}`; + return result; + }, '') + : ''; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/javascript.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/javascript.ts index c73461a1aa396..51d7e4ef68625 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/javascript.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/javascript.ts @@ -10,11 +10,13 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels'; import { docLinks } from '../../../../../../shared/doc_links'; +import { ingestKeysToJSON } from './helpers'; + export const javascriptDefinition: LanguageDefinition = { buildSearchQuery: ({ indexName }) => `// Let's search! const searchResult = await client.search({ index: '${indexName}', - q: '9HY9SWR' + q: 'snow' }); console.log(searchResult.hits.hits) @@ -35,34 +37,38 @@ const client = new Client({ }, iconType: 'javascript.svg', id: Languages.JAVASCRIPT, - ingestData: ({ indexName }) => `// Sample flight data + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; + return `// Sample data books const dataset = [ - {'flight': '9HY9SWR', 'price': 841.2656419677076, 'delayed': false}, - {'flight': 'X98CCZO', 'price': 882.9826615595518, 'delayed': false}, - {'flight': 'UFK2WIZ', 'price': 190.6369038508356, 'delayed': true}, + {"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470${ingestDocumentKeys}}, + {"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585${ingestDocumentKeys}}, + {"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328${ingestDocumentKeys}}, + {"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227${ingestDocumentKeys}}, + {"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268${ingestDocumentKeys}}, + {"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311${ingestDocumentKeys}}, ]; // Index with the bulk helper const result = await client.helpers.bulk({ - datasource: dataset, - onDocument (doc) { - return { index: { _index: '${indexName}' }}; - } + datasource: dataset,${ingestPipeline ? `\n pipeline: "${ingestPipeline}",` : ''} + onDocument: (doc) => ({ index: { _index: '${indexName}' }}), }); console.log(result); /** { - total: 3, + total: 6, failed: 0, retry: 0, - successful: 3, + successful: 6, noop: 0, - time: 421, - bytes: 293, + time: 82, + bytes: 1273, aborted: false } -*/`, +*/`; + }, ingestDataIndex: '', installClient: 'npm install @elastic/elasticsearch@8', name: i18n.translate('xpack.enterpriseSearch.languages.javascript', { @@ -80,10 +86,10 @@ console.log(resp); version: { build_flavor: 'default', build_type: 'docker', - build_hash: 'c94b4700cda13820dad5aa74fae6db185ca5c304', - build_date: '2022-10-24T16:54:16.433628434Z', - build_snapshot: false, - lucene_version: '9.4.1', + build_hash: 'ca3dc3a882d76f14d2765906ce3b1cf421948d19', + build_date: '2023-08-28T11:24:16.383660553Z', + build_snapshot: true, + lucene_version: '9.7.0', minimum_wire_compatibility_version: '7.17.0', minimum_index_compatibility_version: '7.0.0' }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/php.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/php.ts index 51ea055c23ae8..3146ca60af306 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/php.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/php.ts @@ -10,6 +10,8 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels'; import { docLinks } from '../../../../../../shared/doc_links'; +import { ingestKeysToPHP } from './helpers'; + export const phpDefinition: LanguageDefinition = { buildSearchQuery: ({ indexName }) => `$params = [ 'index' => '${indexName}', @@ -33,7 +35,9 @@ print_r($response->asArray());`, }, iconType: 'php.svg', id: Languages.PHP, - ingestData: ({ indexName }) => `$params = [ + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToPHP(extraIngestDocumentValues) : ''; + return `$params = [${ingestPipeline ? `\n 'pipeline' => '${ingestPipeline}',` : ''} 'body' => [ [ 'index' => [ @@ -45,7 +49,7 @@ print_r($response->asArray());`, 'name' => 'Snow Crash', 'author' => 'Neal Stephenson', 'release_date' => '1992-06-01', - 'page_count' => 470, + 'page_count' => 470,${ingestDocumentKeys} ], [ 'index' => [ @@ -57,7 +61,7 @@ print_r($response->asArray());`, 'name' => 'Revelation Space', 'author' => 'Alastair Reynolds', 'release_date' => '2000-03-15', - 'page_count' => 585, + 'page_count' => 585,${ingestDocumentKeys} ], [ 'index' => [ @@ -69,7 +73,7 @@ print_r($response->asArray());`, 'name' => '1984', 'author' => 'George Orwell', 'release_date' => '1985-06-01', - 'page_count' => 328, + 'page_count' => 328,${ingestDocumentKeys} ], [ 'index' => [ @@ -81,7 +85,7 @@ print_r($response->asArray());`, 'name' => 'Fahrenheit 451', 'author' => 'Ray Bradbury', 'release_date' => '1953-10-15', - 'page_count' => 227, + 'page_count' => 227,${ingestDocumentKeys} ], [ 'index' => [ @@ -93,7 +97,7 @@ print_r($response->asArray());`, 'name' => 'Brave New World', 'author' => 'Aldous Huxley', 'release_date' => '1932-06-01', - 'page_count' => 268, + 'page_count' => 268,${ingestDocumentKeys} ], [ 'index' => [ @@ -102,17 +106,18 @@ print_r($response->asArray());`, ], ], [ - 'name' => 'The Handmaid\'s Tale', + 'name' => 'The Handmaid\\'s Tale', 'author' => 'Margaret Atwood', 'release_date' => '1985-06-01', - 'page_count' => 311, + 'page_count' => 311,${ingestDocumentKeys} ], ], ]; $response = $client->bulk($params); echo $response->getStatusCode(); - echo (string) $response->getBody();`, + echo (string) $response->getBody();`; + }, ingestDataIndex: '', installClient: 'composer require elasticsearch/elasticsearch', name: i18n.translate('xpack.enterpriseSearch.languages.php', { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/python.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/python.ts index 79fb811185f18..24723ba3632da 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/python.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/python.ts @@ -10,6 +10,8 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels'; import { docLinks } from '../../../../../../shared/doc_links'; +import { ingestKeysToJSON } from './helpers'; + export const pythonDefinition: LanguageDefinition = { buildSearchQuery: ({ indexName }) => `client.search(index="${indexName}", q="snow")`, configureClient: ({ url, apiKey }) => `from elasticsearch import Elasticsearch @@ -27,22 +29,25 @@ client = Elasticsearch( }, iconType: 'python.svg', id: Languages.PYTHON, - ingestData: ({ indexName }) => `documents = [ + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToJSON(extraIngestDocumentValues) : ''; + return `documents = [ { "index": { "_index": "${indexName}", "_id": "9780553351927"}}, - {"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470}, + {"name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470${ingestDocumentKeys}}, { "index": { "_index": "${indexName}", "_id": "9780441017225"}}, - {"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585}, + {"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585${ingestDocumentKeys}}, { "index": { "_index": "${indexName}", "_id": "9780451524935"}}, - {"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328}, + {"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328${ingestDocumentKeys}}, { "index": { "_index": "${indexName}", "_id": "9781451673319"}}, - {"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227}, + {"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227${ingestDocumentKeys}}, { "index": { "_index": "${indexName}", "_id": "9780060850524"}}, - {"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268}, + {"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268${ingestDocumentKeys}}, { "index": { "_index": "${indexName}", "_id": "9780385490818"}}, - {"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311}, + {"name": "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311${ingestDocumentKeys}}, ] -client.bulk(operations=documents)`, +client.bulk(operations=documents${ingestPipeline ? `, pipeline="${ingestPipeline}"` : ''})`; + }, ingestDataIndex: '', installClient: `python -m pip install elasticsearch diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/ruby.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/ruby.ts index 779aa3a99f1fb..43a104b0f7a8b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/ruby.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/getting_started/languages/ruby.ts @@ -10,6 +10,8 @@ import { Languages, LanguageDefinition } from '@kbn/search-api-panels'; import { docLinks } from '../../../../../../shared/doc_links'; +import { ingestKeysToRuby } from './helpers'; + export const rubyDefinition: LanguageDefinition = { buildSearchQuery: ({ indexName }) => `client.search(index: '${indexName}', q: 'snow')`, configureClient: ({ url, apiKey, cloudId }) => `client = Elasticsearch::Client.new( @@ -26,15 +28,18 @@ export const rubyDefinition: LanguageDefinition = { }, iconType: 'ruby.svg', id: Languages.RUBY, - ingestData: ({ indexName }) => `documents = [ - { index: { _index: '${indexName}', data: {name: "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470} } }, - { index: { _index: '${indexName}', data: {name: "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585} } }, - { index: { _index: '${indexName}', data: {name: "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328} } }, - { index: { _index: '${indexName}', data: {name: "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227} } }, - { index: { _index: '${indexName}', data: {name: "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268} } }, - { index: { _index: '${indexName}', data: {name: "The Handmaid's Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311} } } + ingestData: ({ indexName, ingestPipeline, extraIngestDocumentValues }) => { + const ingestDocumentKeys = ingestPipeline ? ingestKeysToRuby(extraIngestDocumentValues) : ''; + return `documents = [ + { index: { _index: '${indexName}', data: {name: "Snow Crash", author: "Neal Stephenson", release_date: "1992-06-01", page_count: 470${ingestDocumentKeys}} } }, + { index: { _index: '${indexName}', data: {name: "Revelation Space", author: "Alastair Reynolds", release_date: "2000-03-15", page_count: 585${ingestDocumentKeys}} } }, + { index: { _index: '${indexName}', data: {name: "1984", author: "George Orwell", release_date: "1985-06-01", page_count: 328${ingestDocumentKeys}} } }, + { index: { _index: '${indexName}', data: {name: "Fahrenheit 451", author: "Ray Bradbury", release_date: "1953-10-15", page_count: 227${ingestDocumentKeys}} } }, + { index: { _index: '${indexName}', data: {name: "Brave New World", author: "Aldous Huxley", release_date: "1932-06-01", page_count: 268${ingestDocumentKeys}} } }, + { index: { _index: '${indexName}', data: {name: "The Handmaid's Tale", author: "Margaret Atwood", release_date: "1985-06-01", page_count: 311${ingestDocumentKeys}} } } ] -client.bulk(body: documents)`, +client.bulk(body: documents${ingestPipeline ? `, pipeline: "${ingestPipeline}"` : ''})`; + }, ingestDataIndex: '', installClient: `$ gem install elasticsearch`, name: i18n.translate('xpack.enterpriseSearch.languages.ruby', { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/overview.logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/overview.logic.ts index 34584d394b93a..dbe0610b4a855 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/overview.logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/overview.logic.ts @@ -7,7 +7,9 @@ import { kea, MakeLogicType } from 'kea'; +import { DEFAULT_PIPELINE_VALUES } from '../../../../../common/constants'; import { Status } from '../../../../../common/types/api'; +import { IngestPipelineParams } from '../../../../../common/types/connectors'; import { KibanaLogic } from '../../../shared/kibana'; import { GenerateApiKeyLogic } from '../../api/generate_api_key/generate_api_key_logic'; @@ -15,6 +17,10 @@ import { CachedFetchIndexApiLogic, CachedFetchIndexApiLogicActions, } from '../../api/index/cached_fetch_index_api_logic'; +import { + FetchIndexPipelineParametersApiLogic, + FetchIndexPipelineParametersApiLogicActions, +} from '../../api/pipelines/fetch_index_pipeline_parameters'; import { SEARCH_INDICES_PATH } from '../../routes'; @@ -22,6 +28,7 @@ interface OverviewLogicActions { apiError: CachedFetchIndexApiLogicActions['apiError']; apiReset: typeof GenerateApiKeyLogic.actions.apiReset; closeGenerateModal: void; + fetchIndexPipelineParameters: FetchIndexPipelineParametersApiLogicActions['makeRequest']; openGenerateModal: void; toggleClientsPopover: void; toggleManageApiKeyPopover: void; @@ -32,6 +39,8 @@ interface OverviewLogicValues { apiKeyData: typeof GenerateApiKeyLogic.values.data; apiKeyStatus: typeof GenerateApiKeyLogic.values.status; indexData: typeof CachedFetchIndexApiLogic.values.indexData; + indexPipelineData: typeof FetchIndexPipelineParametersApiLogic.values.data; + indexPipelineParameters: IngestPipelineParams; isClientsPopoverOpen: boolean; isError: boolean; isGenerateModalOpen: boolean; @@ -48,12 +57,21 @@ export const OverviewLogic = kea ({ @@ -95,6 +113,11 @@ export const OverviewLogic = kea apiKeyStatus === Status.SUCCESS ? apiKeyData.apiKey.encoded : '', ], + indexPipelineParameters: [ + () => [selectors.indexPipelineData], + (indexPipelineData: typeof FetchIndexPipelineParametersApiLogic.values.data) => + indexPipelineData ?? DEFAULT_PIPELINE_VALUES, + ], isError: [() => [selectors.status], (status) => status === Status.ERROR], isLoading: [ () => [selectors.status, selectors.indexData], diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/get_index_pipeline.test.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_index_pipeline.test.ts new file mode 100644 index 0000000000000..58476ed18b741 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_index_pipeline.test.ts @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { IScopedClusterClient } from '@kbn/core/server'; + +import { DEFAULT_PIPELINE_VALUES } from '../../../common/constants'; + +import { getIndexPipelineParameters } from './get_index_pipeline'; + +describe('getIndexPipelineParameters', () => { + const defaultMockClient = () => ({ + asCurrentUser: { + get: jest.fn().mockResolvedValue({}), + indices: { + getMapping: jest.fn().mockResolvedValue({}), + }, + ingest: { + getPipeline: jest.fn().mockRejectedValue('Pipeline not found'), + }, + search: jest.fn().mockResolvedValue({ + hits: { + hits: [], + }, + }), + }, + }); + let mockClient = defaultMockClient(); + let client: IScopedClusterClient; + beforeEach(() => { + jest.resetAllMocks(); + + mockClient = defaultMockClient(); + client = mockClient as unknown as IScopedClusterClient; + }); + it('returns default pipeline if custom not found', async () => { + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual( + DEFAULT_PIPELINE_VALUES + ); + }); + it('returns connector pipeline params if found', async () => { + mockClient.asCurrentUser.search = jest.fn().mockResolvedValue({ + hits: { + hits: [ + { + _id: 'unit-test', + _source: {}, + }, + ], + }, + }); + mockClient.asCurrentUser.get = jest.fn().mockResolvedValue({ + _id: 'unit-test', + _source: { + pipeline: { + extract_binary_content: false, + name: 'unit-test-pipeline', + reduce_whitespace: true, + run_ml_inference: true, + }, + }, + }); + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual({ + extract_binary_content: false, + name: 'unit-test-pipeline', + reduce_whitespace: true, + run_ml_inference: true, + }); + }); + it('returns default pipeline if fetch custom throws', async () => { + mockClient.asCurrentUser.ingest.getPipeline = jest.fn().mockRejectedValue('Boom'); + + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual( + DEFAULT_PIPELINE_VALUES + ); + }); + it('returns custom pipeline if found', async () => { + mockClient.asCurrentUser.ingest.getPipeline = jest.fn().mockResolvedValueOnce({ + 'my-index': { + fake: 'ingest-pipeline', + }, + }); + + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual({ + extract_binary_content: true, + name: 'my-index', + reduce_whitespace: true, + run_ml_inference: false, + }); + }); + it('returns default connector index pipeline if found in mapping', async () => { + mockClient.asCurrentUser.indices.getMapping = jest.fn().mockResolvedValueOnce({ + '.elastic-connectors-v1': { + mappings: { + _meta: { + pipeline: { + default_extract_binary_content: false, + default_name: 'my-unit-test-index', + default_reduce_whitespace: false, + default_run_ml_inference: true, + }, + }, + }, + }, + }); + + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual({ + extract_binary_content: false, + name: 'my-unit-test-index', + reduce_whitespace: false, + run_ml_inference: true, + }); + }); + it('returns connector params with custom pipeline name', async () => { + mockClient.asCurrentUser.indices.getMapping = jest.fn().mockResolvedValueOnce({ + '.elastic-connectors-v1': { + mappings: { + _meta: { + pipeline: { + default_extract_binary_content: false, + default_name: 'my-unit-test-index', + default_reduce_whitespace: false, + default_run_ml_inference: true, + }, + }, + }, + }, + }); + mockClient.asCurrentUser.ingest.getPipeline = jest.fn().mockResolvedValueOnce({ + 'my-index': { + fake: 'ingest-pipeline', + }, + }); + + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual({ + extract_binary_content: false, + name: 'my-index', + reduce_whitespace: false, + run_ml_inference: true, + }); + }); + it('returns defaults if get mapping fails with IndexNotFoundException', async () => { + mockClient.asCurrentUser.indices.getMapping = jest.fn().mockRejectedValue({ + meta: { + body: { + error: { + type: 'index_not_found_exception', + }, + }, + }, + }); + + await expect(getIndexPipelineParameters('my-index', client)).resolves.toEqual( + DEFAULT_PIPELINE_VALUES + ); + }); + it('throws if get mapping fails with non-IndexNotFoundException', async () => { + mockClient.asCurrentUser.indices.getMapping = jest.fn().mockRejectedValue('Boom'); + + await expect(getIndexPipelineParameters('my-index', client)).rejects.toEqual('Boom'); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/lib/pipelines/get_index_pipeline.ts b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_index_pipeline.ts new file mode 100644 index 0000000000000..45813a109de76 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/lib/pipelines/get_index_pipeline.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. + */ + +import { IScopedClusterClient } from '@kbn/core/server'; + +import { IngestPipelineParams } from '../../../common/types/connectors'; +import { fetchConnectorByIndexName } from '../connectors/fetch_connectors'; + +import { getDefaultPipeline } from './get_default_pipeline'; + +export const getIndexPipelineParameters = async ( + indexName: string, + client: IScopedClusterClient +): Promise => { + // Get the default pipeline data and check for a custom pipeline in parallel + // we want to throw the error if getDefaultPipeline() fails so we're not catching it on purpose + const [defaultPipeline, connector, customPipelineResp] = await Promise.all([ + getDefaultPipeline(client), + fetchConnectorByIndexName(client, indexName), + client.asCurrentUser.ingest + .getPipeline({ + id: `${indexName}`, + }) + .catch(() => null), + ]); + if (connector && connector.pipeline) { + return connector.pipeline; + } + let pipelineName = defaultPipeline.name; + + if (customPipelineResp && customPipelineResp[indexName]) { + pipelineName = indexName; + } + + return { + ...defaultPipeline, + name: pipelineName, + }; +}; diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts index b41f391fd66f6..25342217e5192 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.ts @@ -44,6 +44,7 @@ import { startMlModelDownload } from '../../lib/ml/start_ml_model_download'; import { createIndexPipelineDefinitions } from '../../lib/pipelines/create_pipeline_definitions'; import { deleteIndexPipelines } from '../../lib/pipelines/delete_pipelines'; import { getCustomPipelines } from '../../lib/pipelines/get_custom_pipelines'; +import { getIndexPipelineParameters } from '../../lib/pipelines/get_index_pipeline'; import { getPipeline } from '../../lib/pipelines/get_pipeline'; import { getMlInferencePipelines } from '../../lib/pipelines/ml_inference/get_ml_inference_pipelines'; import { revertCustomPipeline } from '../../lib/pipelines/revert_custom_pipeline'; @@ -354,6 +355,26 @@ export function registerIndexRoutes({ }) ); + router.get( + { + path: '/internal/enterprise_search/indices/{indexName}/pipeline_parameters', + validate: { + params: schema.object({ + indexName: schema.string(), + }), + }, + }, + elasticsearchErrorHandler(log, async (context, request, response) => { + const indexName = decodeURIComponent(request.params.indexName); + const { client } = (await context.core).elasticsearch; + const body = await getIndexPipelineParameters(indexName, client); + return response.ok({ + body, + headers: { 'content-type': 'application/json' }, + }); + }) + ); + router.get( { path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors', diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx index f4a6d6d13a4f9..0e85390a4b327 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx @@ -47,14 +47,6 @@ const VirtualizedRow: React.FC<{ ); }; -const CARD_CSS = css` - & > .euiPopover, - & > .euiPopover > .euiPopover__anchor, - & > .euiPopover > .euiPopover__anchor > .euiCard { - height: 100%; - } -`; - export const GridColumn = ({ list, showMissingIntegrationMessage = false, @@ -131,7 +123,13 @@ export const GridColumn = ({ .euiPopover, + & > .euiPopover > .euiPopover__anchor, + & > .euiPopover > .euiPopover__anchor > .euiCard { + height: 100%; + } + `} > diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/search_box.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/search_box.tsx index 593ad3e60e82b..9206de2d48f17 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/search_box.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/search_box.tsx @@ -54,6 +54,24 @@ export const SearchBox: FunctionComponent = ({ }); }; + const onCategoryButtonClick = () => { + if (selectedSubCategory) { + if (setSelectedSubCategory) setSelectedSubCategory(undefined); + setUrlandReplaceHistory({ + categoryId: selectedCategory, + subCategoryId: '', + }); + } else { + setCategory(''); + if (setSelectedSubCategory) setSelectedSubCategory(undefined); + setUrlandReplaceHistory({ + searchString: '', + categoryId: '', + subCategoryId: '', + }); + } + }; + const selectedCategoryTitle = selectedCategory ? categories.find((category) => category.id === selectedCategory)?.title : undefined; @@ -100,15 +118,7 @@ export const SearchBox: FunctionComponent = ({ {getCategoriesLabel}
+ ), + panel: 1, + }, + { + name: ( + + + {i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.knowledgeBase', + { + defaultMessage: 'Knowledge base', + } + )} + + + {knowledgeBase.status.loading || knowledgeBase.isInstalling ? ( + + ) : knowledgeBase.status.value?.ready ? ( + + ) : ( + + )} + + + ), + panel: 2, + }, + { + name: i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.copyConversation', + { + defaultMessage: 'Copy conversation', + } + ), + disabled: !conversationId, + onClick: () => { + toggleActionsMenu(); + onCopyConversationClick(); + }, + }, + ], + }, + { + id: 1, + width: 256, + title: i18n.translate('xpack.observabilityAiAssistant.chatHeader.actions.connector', { + defaultMessage: 'Connector', + }), + content: ( + + + + + {i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.connectorManagement.button', + { + defaultMessage: 'Manage connectors', + } + )} + + + ), + }, + { + id: 2, + width: 256, + title: i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.knowledgeBase.title', + { + defaultMessage: 'Knowledge base', + } + ), + content: ( + + +

+ {i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.knowledgeBase.description.paragraph', + { + defaultMessage: + 'Using a knowledge base is optional but improves the experience of using the Assistant significantly.', + } + )}{' '} + + {i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.knowledgeBase.elser.learnMore', + { + defaultMessage: 'Learn more', + } + )} + +

+
+ + + {knowledgeBase.isInstalling || knowledgeBase.status.loading ? ( + + ) : ( + <> + { + if (e.target.checked) { + knowledgeBase.install(); + } + }} + /> + + + + + {i18n.translate( + 'xpack.observabilityAiAssistant.chatHeader.actions.connectorManagement', + { + defaultMessage: 'Go to Machine Learning', + } + )} + + + )} +
+ ), + }, + ]} + /> + + ); +} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx index 14e9df56935dd..8a6227829c855 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { last } from 'lodash'; import { EuiFlexGroup, @@ -24,19 +24,14 @@ import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; import { useTimeline } from '../../hooks/use_timeline'; import { useLicense } from '../../hooks/use_license'; import { useObservabilityAIAssistantChatService } from '../../hooks/use_observability_ai_assistant_chat_service'; -import { MissingCredentialsCallout } from '../missing_credentials_callout'; import { ExperimentalFeatureBanner } from './experimental_feature_banner'; +import { InitialSetupPanel } from './initial_setup_panel'; import { IncorrectLicensePanel } from './incorrect_license_panel'; import { ChatHeader } from './chat_header'; import { ChatPromptEditor } from './chat_prompt_editor'; import { ChatTimeline } from './chat_timeline'; import { StartedFrom } from '../../utils/get_timeline_items_from_conversation'; -const containerClassName = css` - max-height: 100%; - max-width: ${1200 - 250}px; // page template max width - conversation list width. -`; - const timelineClassName = css` overflow-y: auto; `; @@ -57,6 +52,7 @@ export function ChatBody({ connectors, knowledgeBase, connectorsManagementHref, + modelsManagementHref, conversationId, currentUser, startedFrom, @@ -70,6 +66,7 @@ export function ChatBody({ connectors: UseGenAIConnectorsResult; knowledgeBase: UseKnowledgeBaseResult; connectorsManagementHref: string; + modelsManagementHref: string; conversationId?: string; currentUser?: Pick; startedFrom?: StartedFrom; @@ -83,10 +80,10 @@ export function ChatBody({ const chatService = useObservabilityAIAssistantChatService(); const timeline = useTimeline({ - messages, + chatService, connectors, currentUser, - chatService, + messages, startedFrom, onChatUpdate, onChatComplete, @@ -100,49 +97,53 @@ export function ChatBody({ connectors.loading || knowledgeBase.status.loading || last(timeline.items)?.loading ); + const containerClassName = css` + max-height: 100%; + max-width: ${startedFrom === 'conversationView' + ? 1200 - 250 + 'px' // page template max width - conversation list width. + : '100%'}; + `; + + const [stickToBottom, setStickToBottom] = useState(true); + + const isAtBottom = (parent: HTMLElement) => + parent.scrollTop + parent.clientHeight >= parent.scrollHeight; + useEffect(() => { const parent = timelineContainerRef.current?.parentElement; if (!parent) { return; } - let rafId: number | undefined; - - const isAtBottom = () => parent.scrollTop >= parent.scrollHeight - parent.offsetHeight; - - const stick = () => { - if (!isAtBottom()) { - parent.scrollTop = parent.scrollHeight - parent.offsetHeight; - } - rafId = requestAnimationFrame(stick); - }; - - const unstick = () => { - if (rafId) { - cancelAnimationFrame(rafId); - rafId = undefined; - } - }; - - const onScroll = (event: Event) => { - if (isAtBottom()) { - stick(); - } else { - unstick(); - } - }; + function onScroll() { + setStickToBottom(isAtBottom(parent!)); + } parent.addEventListener('scroll', onScroll); - stick(); - return () => { - unstick(); parent.removeEventListener('scroll', onScroll); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [timelineContainerRef.current]); + useEffect(() => { + const parent = timelineContainerRef.current?.parentElement; + if (!parent) { + return; + } + + if (stickToBottom) { + parent.scrollTop = parent.scrollHeight; + } + }); + + const handleCopyConversation = () => { + const content = JSON.stringify({ title, messages }); + + navigator.clipboard?.writeText(content || ''); + }; + if (!hasCorrectLicense && !conversationId) { footer = ( <> @@ -166,12 +167,14 @@ export function ChatBody({ ); - } else if (connectors.connectors?.length === 0) { + } else if (connectors.connectors?.length === 0 && !conversationId) { footer = ( - <> - - - + ); } else { footer = ( @@ -181,6 +184,7 @@ export function ChatBody({ { + setStickToBottom(true); + return timeline.onSubmit(message); + }} /> @@ -208,16 +215,24 @@ export function ChatBody({ return ( - - - + {connectors.selectedConnector ? ( + + + + ) : null} + diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx index 7f8924995f07b..ef4635d873e8a 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_flyout.tsx @@ -15,6 +15,7 @@ import { useKibana } from '../../hooks/use_kibana'; import { useKnowledgeBase } from '../../hooks/use_knowledge_base'; import { useObservabilityAIAssistantRouter } from '../../hooks/use_observability_ai_assistant_router'; import { getConnectorsManagementHref } from '../../utils/get_connectors_management_href'; +import { getModelsManagementHref } from '../../utils/get_models_management_href'; import { StartedFrom } from '../../utils/get_timeline_items_from_conversation'; import { ChatBody } from './chat_body'; @@ -77,6 +78,7 @@ export function ChatFlyout({ > {conversationId ? ( ) : ( - + {i18n.translate('xpack.observabilityAiAssistant.conversationListDeepLinkLabel', { defaultMessage: 'Go to conversations', })} @@ -102,6 +107,8 @@ export function ChatFlyout({ messages={messages} currentUser={currentUser} connectorsManagementHref={getConnectorsManagementHref(http)} + modelsManagementHref={getModelsManagementHref(http)} + conversationId={conversationId} knowledgeBase={knowledgeBase} startedFrom={startedFrom} onChatUpdate={(nextMessages) => { diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx index 0314380a87657..0630f9c36d9dd 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_header.tsx @@ -16,12 +16,12 @@ import { import { i18n } from '@kbn/i18n'; import { css } from '@emotion/css'; import { AssistantAvatar } from '../assistant_avatar'; -import { ConnectorSelectorBase } from '../connector_selector/connector_selector_base'; -import { EMPTY_CONVERSATION_TITLE, UPGRADE_LICENSE_TITLE } from '../../i18n'; -import { KnowledgeBaseCallout } from './knowledge_base_callout'; +import { ChatActionsMenu } from './chat_actions_menu'; +import { ASSISTANT_SETUP_TITLE, EMPTY_CONVERSATION_TITLE, UPGRADE_LICENSE_TITLE } from '../../i18n'; import { useUnmountAndRemountWhenPropChanges } from '../../hooks/use_unmount_and_remount_when_prop_changes'; import type { UseGenAIConnectorsResult } from '../../hooks/use_genai_connectors'; import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; +import { StartedFrom } from '../../utils/get_timeline_items_from_conversation'; // needed to prevent InlineTextEdit component from expanding container const minWidthClassName = css` @@ -33,19 +33,33 @@ export function ChatHeader({ loading, licenseInvalid, connectors, + connectorsManagementHref, + modelsManagementHref, + conversationId, knowledgeBase, + startedFrom, onSaveTitle, + onCopyConversation, }: { title: string; loading: boolean; licenseInvalid: boolean; connectors: UseGenAIConnectorsResult; + connectorsManagementHref: string; + modelsManagementHref: string; + conversationId?: string; knowledgeBase: UseKnowledgeBaseResult; + startedFrom?: StartedFrom; + onCopyConversation: () => void; onSaveTitle?: (title: string) => void; }) { const hasTitle = !!title; - const displayedTitle = licenseInvalid ? UPGRADE_LICENSE_TITLE : title || EMPTY_CONVERSATION_TITLE; + const displayedTitle = !connectors.selectedConnector + ? ASSISTANT_SETUP_TITLE + : licenseInvalid + ? UPGRADE_LICENSE_TITLE + : title || EMPTY_CONVERSATION_TITLE; const theme = useEuiTheme(); @@ -57,45 +71,41 @@ export function ChatHeader({ return ( - + {loading ? : } - - - {shouldRender ? ( - - ) : null} - - - - - - - - {!licenseInvalid ? : null} - - - - + {shouldRender ? ( + + ) : null} + + + diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_actions.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_actions.tsx index 79240a03bb314..64585d2f52ecc 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_actions.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_item_actions.tsx @@ -53,6 +53,7 @@ export function ChatItemActions({ } )} color="text" + data-test-subj="observabilityAiAssistantChatItemActionsEditPromptButton" display={editing ? 'fill' : 'empty'} iconType="documentEdit" onClick={onToggleEdit} @@ -68,6 +69,7 @@ export function ChatItemActions({ } )} color="text" + data-test-subj="observabilityAiAssistantChatItemActionsInspectPromptButton" display={expanded ? 'fill' : 'empty'} iconType={expanded ? 'eyeClosed' : 'eye'} onClick={onToggleExpand} @@ -85,6 +87,7 @@ export function ChatItemActions({ } )} color="text" + data-test-subj="observabilityAiAssistantChatItemActionsCopyMessageButton" iconType="copyClipboard" display={isPopoverOpen === 'copy' ? 'fill' : 'empty'} onClick={() => { diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx index 174a2048bf290..7033e1b48c47c 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_prompt_editor.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { EuiButtonEmpty, EuiButtonIcon, @@ -18,7 +19,6 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { CodeEditor } from '@kbn/kibana-react-plugin/public'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; import { MessageRole, type Message } from '../../../common'; import { useJsonEditorModel } from '../../hooks/use_json_editor_model'; import { FunctionListPopover } from './function_list_popover'; @@ -51,6 +51,7 @@ export function ChatPromptEditor({ const [functionPayload, setFunctionPayload] = useState( initialFunctionPayload ); + const [functionEditorLineCount, setFunctionEditorLineCount] = useState(0); const { model, initialJsonString } = useJsonEditorModel({ functionName: selectedFunctionName, @@ -59,9 +60,12 @@ export function ChatPromptEditor({ const textAreaRef = useRef(null); - useEffect(() => { - setFunctionPayload(initialJsonString); - }, [initialJsonString, selectedFunctionName]); + const recalculateFunctionEditorLineCount = useCallback(() => { + const newLineCount = model?.getLineCount() || 0; + if (newLineCount !== functionEditorLineCount) { + setFunctionEditorLineCount(newLineCount); + } + }, [functionEditorLineCount, model]); const handleChange = (event: React.ChangeEvent) => { setPrompt(event.currentTarget.value); @@ -69,6 +73,7 @@ export function ChatPromptEditor({ const handleChangeFunctionPayload = (params: string) => { setFunctionPayload(params); + recalculateFunctionEditorLineCount(); }; const handleClearSelection = () => { @@ -91,7 +96,7 @@ export function ChatPromptEditor({ }; const handleSubmit = useCallback(async () => { - if (loading) { + if (loading || !prompt?.trim()) { return; } const currentPrompt = prompt; @@ -129,6 +134,14 @@ export function ChatPromptEditor({ } }, [functionPayload, loading, onSubmit, prompt, selectedFunctionName]); + useEffect(() => { + setFunctionPayload(initialJsonString); + }, [initialJsonString, selectedFunctionName]); + + useEffect(() => { + recalculateFunctionEditorLineCount(); + }, [model, recalculateFunctionEditorLineCount]); + useEffect(() => { const keyboardListener = (event: KeyboardEvent) => { if (!event.shiftKey && event.key === keys.ENTER && (prompt || selectedFunctionName)) { @@ -174,6 +187,7 @@ export function ChatPromptEditor({ {selectedFunctionName ? ( 8 ? '200px' : '120px'} languageId="json" isCopyable languageConfiguration={{ @@ -238,6 +253,8 @@ export function ChatPromptEditor({
) : ( = (props: ChatTimelineProps) => setCount(count >= 0 && count < props.items.length - 1 ? count + 1 : 0)} > Add message @@ -48,6 +49,18 @@ const Template: ComponentStory = (props: ChatTimelineProps) => }; const defaultProps: ComponentProps = { + knowledgeBase: { + status: { + loading: false, + value: { + ready: true, + }, + refresh: () => {}, + }, + isInstalling: false, + installError: undefined, + install: async () => {}, + }, items: [ buildChatInitItem(), buildUserChatItem(), diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx index f471fa6768c70..8e50f11842e5d 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_timeline.tsx @@ -14,6 +14,7 @@ import { ChatItem } from './chat_item'; import { ChatWelcomePanel } from './chat_welcome_panel'; import type { Feedback } from '../feedback_buttons'; import type { Message } from '../../../common'; +import { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; export interface ChatTimelineItem extends Pick { @@ -37,6 +38,7 @@ export interface ChatTimelineItem export interface ChatTimelineProps { items: ChatTimelineItem[]; + knowledgeBase: UseKnowledgeBaseResult; onEdit: (item: ChatTimelineItem, message: Message) => Promise; onFeedback: (item: ChatTimelineItem, feedback: Feedback) => void; onRegenerate: (item: ChatTimelineItem) => void; @@ -45,6 +47,7 @@ export interface ChatTimelineProps { export function ChatTimeline({ items = [], + knowledgeBase, onEdit, onFeedback, onRegenerate, @@ -77,7 +80,7 @@ export function ChatTimeline({ /> )) )} - {filteredItems.length === 1 ? : null} + {filteredItems.length === 1 ? : null} ); } diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_welcome_panel.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_welcome_panel.tsx index 32fba0b72a828..8240c6fef4054 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_welcome_panel.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_welcome_panel.tsx @@ -6,18 +6,19 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiImage, EuiPanel, EuiText, EuiTitle } from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiImage, EuiPanel, EuiText, EuiTitle } from '@elastic/eui'; import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; import { euiThemeVars } from '@kbn/ui-theme'; import ctaImage from '../../assets/elastic_ai_assistant.png'; +import type { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; const incorrectLicenseContainer = css` height: 100%; padding: ${euiThemeVars.euiPanelPaddingModifiers.paddingMedium}; `; -export function ChatWelcomePanel() { +export function ChatWelcomePanel({ knowledgeBase }: { knowledgeBase: UseKnowledgeBaseResult }) { return ( - +

{i18n.translate('xpack.observabilityAiAssistant.chatWelcomePanel.title', { @@ -36,12 +37,35 @@ export function ChatWelcomePanel() {

- {i18n.translate('xpack.observabilityAiAssistant.chatWelcomePanel.body', { - defaultMessage: - 'Elastic AI Assistant is an experimental feature. Make sure to provide feedback when you interact with it.', - })} + {knowledgeBase.status.value?.ready + ? i18n.translate('xpack.observabilityAiAssistant.chatWelcomePanel.body.kbReady', { + defaultMessage: + 'Keep in mind that Elastic AI Assistant is a technical preview feature. Please provide feedback at any time.', + }) + : i18n.translate('xpack.observabilityAiAssistant.chatWelcomePanel.body.kbNotReady', { + defaultMessage: + 'We recommend you enable the knowledge base for a better experience. It will provide the assistant with the ability to learn from your interaction with it. Keep in mind that Elastic AI Assistant is a technical preview feature. Please provide feedback at any time.', + })}

+ + {!knowledgeBase.status.value?.ready ? ( + + {i18n.translate( + 'xpack.observabilityAiAssistant.chatWelcomePanel.knowledgeBase.buttonLabel.notInstalledYet', + { + defaultMessage: 'Set up knowledge base', + } + )} + + ) : null} ); diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/experimental_feature_banner.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/experimental_feature_banner.tsx index 48935a49ccf02..8ec5346283365 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/experimental_feature_banner.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/experimental_feature_banner.tsx @@ -16,24 +16,18 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import illustration from '../../assets/illustration.svg'; +import illustration from '../../assets/illustration.png'; export function ExperimentalFeatureBanner() { return ( - <> +
- + - + - + {i18n.translate( 'xpack.observabilityAiAssistant.experimentalFunctionBanner.feedbackButton', { defaultMessage: 'Give feedback' } @@ -52,6 +51,6 @@ export function ExperimentalFeatureBanner() { - +
); } diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx index f0684daece223..72dac17c71c2a 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/function_list_popover.tsx @@ -109,6 +109,7 @@ export function FunctionListPopover({ anchorPosition="downLeft" button={ - +

{UPGRADE_LICENSE_TITLE}

{i18n.translate('xpack.observabilityAiAssistant.incorrectLicense.body', { - defaultMessage: 'You need a Platinum license to use the Elastic AI Assistant.', + defaultMessage: 'You need an Enterprise license to use the Elastic AI Assistant.', })}

- + {i18n.translate( 'xpack.observabilityAiAssistant.incorrectLicense.subscriptionPlansButton', { @@ -63,7 +68,10 @@ export function IncorrectLicensePanel() { - + {i18n.translate('xpack.observabilityAiAssistant.incorrectLicense.manageLicense', { defaultMessage: 'Manage license', })} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/initial_setup_panel.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/initial_setup_panel.tsx new file mode 100644 index 0000000000000..281cf46c972bb --- /dev/null +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/initial_setup_panel.tsx @@ -0,0 +1,225 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { + EuiBetaBadge, + EuiButton, + EuiCallOut, + EuiCard, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiPanel, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ConnectorSelectorBase } from '../connector_selector/connector_selector_base'; +import type { UseGenAIConnectorsResult } from '../../hooks/use_genai_connectors'; +import { ExperimentalFeatureBanner } from './experimental_feature_banner'; +import { UseKnowledgeBaseResult } from '../../hooks/use_knowledge_base'; +import { StartedFrom } from '../../utils/get_timeline_items_from_conversation'; + +export function InitialSetupPanel({ + connectors, + connectorsManagementHref, + knowledgeBase, + startedFrom, +}: { + connectors: UseGenAIConnectorsResult; + connectorsManagementHref: string; + knowledgeBase: UseKnowledgeBaseResult; + startedFrom?: StartedFrom; +}) { + return ( + <> + + + + + + +

+ {i18n.translate('xpack.observabilityAiAssistant.initialSetupPanel.title', { + defaultMessage: + 'Start your Al experience with Elastic by completing the steps below.', + })} +

+
+ + + + + + } + title={i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.knowledgeBase.title', + { + defaultMessage: 'Knowledge Base', + } + )} + description={ + +

+ {i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.knowledgeBase.description.paragraph1', + { + defaultMessage: + 'We recommend you enable the knowledge base for a better experience. It will provide the assistant with the ability to learn from your interaction with it.', + } + )} +

+

+ {i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.knowledgeBase.description.paragraph2', + { + defaultMessage: 'This step is optional, you can always do it later.', + } + )} +

+
+ } + footer={ + knowledgeBase.status.value?.ready ? ( + + ) : ( + + {knowledgeBase.isInstalling || knowledgeBase.status.loading + ? i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.knowledgeBase.buttonLabel.installingKb', + { + defaultMessage: 'Installing knowledge base', + } + ) + : i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.knowledgeBase.buttonLabel.kbNotInstalledYet', + { + defaultMessage: 'Set up knowledge base', + } + )} + + ) + } + /> +
+ + + } + title={i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.setupConnector.title', + { + defaultMessage: 'Connector setup', + } + )} + description={ + !connectors.connectors?.length ? ( + +

+ {i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.setupConnector.description1', + { + defaultMessage: 'Set up a Generative AI connector with your AI provider.', + } + )} +

+ +

+ {i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.setupConnector.description2', + { + defaultMessage: + 'The Generative AI model needs to support function calls. We strongly recommend using GPT4.', + } + )} + +

+
+ ) : connectors.connectors.length && !connectors.selectedConnector ? ( + +

+ {i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.setupConnector.description', + { + defaultMessage: 'Please select a provider.', + } + )} +

+
+ ) : ( + '' + ) + } + footer={ + !connectors.connectors?.length ? ( + + {i18n.translate( + 'xpack.observabilityAiAssistant.initialSetupPanel.setupConnector.buttonLabel', + { + defaultMessage: 'Set up Generative AI connector', + } + )} + + ) : connectors.connectors.length && !connectors.selectedConnector ? ( + + ) : null + } + /> +
+
+ + + + +

+ {i18n.translate('xpack.observabilityAiAssistant.initialSetupPanel.disclaimer', { + defaultMessage: + 'The AI provider that is configured may collect telemetry when using the Elastic AI Assistant. Contact your AI provider for information on how data is collected.', + })} +

+
+
+ + ); +} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/knowledge_base_callout.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/knowledge_base_callout.tsx index b8f3b8bd7ef82..36d6842286aa8 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/knowledge_base_callout.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/knowledge_base_callout.tsx @@ -89,6 +89,7 @@ export function KnowledgeBaseCallout({ knowledgeBase }: { knowledgeBase: UseKnow } else if (!knowledgeBase.status.value?.ready && !knowledgeBase.status.error) { content = ( { knowledgeBase.install(); }} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/feedback_buttons.tsx b/x-pack/plugins/observability_ai_assistant/public/components/feedback_buttons.tsx index 08b58a85bfadf..2b55e3d8cac35 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/feedback_buttons.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/feedback_buttons.tsx @@ -32,6 +32,7 @@ export function FeedbackButtons({ onClickFeedback }: FeedbackButtonsProps) { - + {i18n.translate('xpack.observabilityAiAssistant.insight.error.buttonLabel', { defaultMessage: 'Regenerate', })} diff --git a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx index 6fd9a1c70923d..d82e76ef5001f 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/message_panel/message_text.tsx @@ -16,7 +16,6 @@ import classNames from 'classnames'; import type { Code, InlineCode, Parent, Text } from 'mdast'; import React, { useMemo } from 'react'; import type { Node } from 'unist'; -import { v4 } from 'uuid'; interface Props { content: string; @@ -48,7 +47,10 @@ const cursorCss = css` const Cursor = () => ; -const CURSOR = `{{${v4()}}}`; +// a weird combination of different whitespace chars to make sure it stays +// invisible even when we cannot properly parse the text while still being +// unique +const CURSOR = ` ᠎  `; const loadingCursorPlugin = () => { const visitor = (node: Node, parent?: Parent) => { diff --git a/x-pack/plugins/observability_ai_assistant/public/components/missing_credentials_callout.tsx b/x-pack/plugins/observability_ai_assistant/public/components/missing_credentials_callout.tsx index 20c8257b8721f..3cf5511a042e2 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/missing_credentials_callout.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/missing_credentials_callout.tsx @@ -29,7 +29,12 @@ export function MissingCredentialsCallout(props: Props) { - + {i18n.translate('xpack.observabilityAiAssistant.missingCredentialsCallout.buttonLabel', { defaultMessage: 'Connect Assistant', })} diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/index.ts b/x-pack/plugins/observability_ai_assistant/public/functions/index.ts index f0a676a5c221d..a0c1a264bfb51 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/index.ts +++ b/x-pack/plugins/observability_ai_assistant/public/functions/index.ts @@ -14,7 +14,7 @@ import { registerElasticsearchFunction } from './elasticsearch'; import { registerKibanaFunction } from './kibana'; import { registerLensFunction } from './lens'; import { registerRecallFunction } from './recall'; -import { registerSummarisationFunction } from './summarise'; +import { registerSummarizationFunction } from './summarize'; import { registerAlertsFunction } from './alerts'; export async function registerFunctions({ @@ -49,11 +49,14 @@ export async function registerFunctions({ In KQL, escaping happens with double quotes, not single quotes. Some characters that need escaping are: ':()\\\ /\". Always put a field value in double quotes. Best: service.name:\"opbeans-go\". Wrong: service.name:opbeans-go. This is very important! - You can use Github-flavored Markdown in your responses. If a function returns an array, consider using a Markdown table to format the response.` + You can use Github-flavored Markdown in your responses. If a function returns an array, consider using a Markdown table to format the response. + + If multiple functions are suitable, use the most specific and easy one. E.g., when the user asks to visualise APM data, use the APM functions (if available) rather than Lens. + ` ); if (isReady) { - description += `You can use the "summarise" functions to store new information you have learned in a knowledge database. Once you have established that you did not know the answer to a question, and the user gave you this information, it's important that you create a summarisation of what you have learned and store it in the knowledge database. + description += `You can use the "summarize" functions to store new information you have learned in a knowledge database. Once you have established that you did not know the answer to a question, and the user gave you this information, it's important that you create a summarisation of what you have learned and store it in the knowledge database. Don't create a new summarization if you see a similar summarization in the conversation, instead, update the existing one by re-using its ID. Additionally, you can use the "recall" function to retrieve relevant information from the knowledge database. `; @@ -64,9 +67,9 @@ export async function registerFunctions({ - ALWAYS query the knowledge base, using the recall function, when a user starts a chat, no matter how confident you are in your ability to answer the question. - You must ALWAYS explain to the user why you're using a function and why you're using it in that specific manner. - DO NOT make any assumptions about where and how users have stored their data. - - ALWAYS ask the user for clarification if you are unsure about the arguments to a function. When given this clarification, you MUST use the summarise function to store what you have learned. + - ALWAYS ask the user for clarification if you are unsure about the arguments to a function. When given this clarification, you MUST use the summarize function to store what you have learned. `; - registerSummarisationFunction({ service, registerFunction }); + registerSummarizationFunction({ service, registerFunction }); registerRecallFunction({ service, registerFunction }); registerLensFunction({ service, pluginsStart, registerFunction }); } else { diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/kibana.ts b/x-pack/plugins/observability_ai_assistant/public/functions/kibana.ts index 5ad877b2c2bff..a47acdb02d433 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/kibana.ts +++ b/x-pack/plugins/observability_ai_assistant/public/functions/kibana.ts @@ -50,7 +50,7 @@ export function registerKibanaFunction({ description: 'The body of the request', }, }, - required: ['method', 'pathname', 'body'] as const, + required: ['method', 'pathname'] as const, }, }, ({ arguments: { method, pathname, body, query } }, signal) => { diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/lens.tsx b/x-pack/plugins/observability_ai_assistant/public/functions/lens.tsx index d12b8e3334318..efacbe07816e1 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/lens.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/functions/lens.tsx @@ -4,13 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiLoadingSpinner } from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types'; import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; import { LensAttributesBuilder, XYChart, XYDataLayer } from '@kbn/lens-embeddable-utils'; -import type { LensPublicStart } from '@kbn/lens-plugin/public'; -import React from 'react'; +import type { LensEmbeddableInput, LensPublicStart } from '@kbn/lens-plugin/public'; +import React, { useState } from 'react'; import useAsync from 'react-use/lib/useAsync'; +import { i18n } from '@kbn/i18n'; +import { Assign } from 'utility-types'; import type { RegisterFunctionDefinition } from '../../common/types'; import type { ObservabilityAIAssistantPluginStartDependencies, @@ -56,6 +58,8 @@ function Lens({ }); }, [indexPattern]); + const [isSaveModalOpen, setIsSaveModalOpen] = useState(false); + if (!formulaAsync.value || !dataViewAsync.value) { return ; } @@ -68,19 +72,65 @@ function Lens({ }), }).build(); + const lensEmbeddableInput: Assign = { + id: indexPattern, + attributes, + timeRange: { + from: start, + to: end, + mode: 'relative' as const, + }, + }; + return ( - + <> + + + + + { + lens.navigateToPrefilledEditor(lensEmbeddableInput); + }} + > + {i18n.translate('xpack.observabilityAiAssistant.lensFunction.openInLens', { + defaultMessage: 'Open in Lens', + })} + + + + { + setIsSaveModalOpen(() => true); + }} + > + {i18n.translate('xpack.observabilityAiAssistant.lensFunction.save', { + defaultMessage: 'Save', + })} + + + + + + + + + {isSaveModalOpen ? ( + { + setIsSaveModalOpen(() => false); + }} + /> + ) : null} + ); } @@ -98,9 +148,9 @@ export function registerLensFunction({ name: 'lens', contexts: ['core'], description: - "Use this function to create custom visualisations, using Lens, that can be saved to dashboards. When using this function, make sure to use the recall function to get more information about how to use it, with how you want to use it. Make sure the query also contains information about the user's request. The visualisation is displayed to the user above your reply, DO NOT try to generate or display an image yourself.", + "Use this function to create custom visualizations, using Lens, that can be saved to dashboards. This function does not return data to the assistant, it only shows it to the user. When using this function, make sure to use the recall function to get more information about how to use it, with how you want to use it. Make sure the query also contains information about the user's request. The visualisation is displayed to the user above your reply, DO NOT try to generate or display an image yourself.", descriptionForUser: - 'Use this function to create custom visualisations, using Lens, that can be saved to dashboards.', + 'Use this function to create custom visualizations, using Lens, that can be saved to dashboards.', parameters: { type: 'object', additionalProperties: false, diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts b/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts index 8f85a9e03a069..f07cf43e1c282 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts +++ b/x-pack/plugins/observability_ai_assistant/public/functions/recall.ts @@ -6,7 +6,7 @@ */ import type { Serializable } from '@kbn/utility-types'; -import type { RegisterFunctionDefinition } from '../../common/types'; +import { MessageRole, RegisterFunctionDefinition } from '../../common/types'; import type { ObservabilityAIAssistantService } from '../types'; export function registerRecallFunction({ @@ -20,24 +20,19 @@ export function registerRecallFunction({ { name: 'recall', contexts: ['core'], - description: `Use this function to recall earlier learnings. Anything you will summarise can be retrieved again later via this function. This is semantic/vector search so there's no need for an exact match. + description: `Use this function to recall earlier learnings. Anything you will summarize can be retrieved again later via this function. Make sure the query covers the following aspects: - - The user's prompt, verbatim - Anything you've inferred from the user's request, but is not mentioned in the user's request - The functions you think might be suitable for answering the user's request. If there are multiple functions that seem suitable, create multiple queries. Use the function name in the query. + + DO NOT include the user's request. It will be added internally. - Q: "can you visualise the average request duration for opbeans-go over the last 7 days?" - A: -"can you visualise the average request duration for opbeans-go over the last 7 days?" + The user asks: "can you visualise the average request duration for opbeans-go over the last 7 days?" + You recall: - "APM service" - "lens function usage" - - "get_apm_timeseries function usage" - - Q: "what alerts are active?" - A: - "what alerts are active?" - - "alerts function usage" - - `, + - "get_apm_timeseries function usage"`, descriptionForUser: 'This function allows the assistant to recall previous learnings.', parameters: { type: 'object', @@ -53,15 +48,21 @@ export function registerRecallFunction({ }, }, }, - required: ['queries' as const], - }, + required: ['queries'], + } as const, }, - ({ arguments: { queries } }, signal) => { + ({ arguments: { queries }, messages }, signal) => { + const userMessages = messages.filter((message) => message.message.role === MessageRole.User); + + const userPrompt = userMessages[userMessages.length - 1]?.message.content; + + const queriesWithUserPrompt = userPrompt ? [userPrompt, ...queries] : queries; + return service .callApi('POST /internal/observability_ai_assistant/functions/recall', { params: { body: { - queries, + queries: queriesWithUserPrompt, }, }, signal, diff --git a/x-pack/plugins/observability_ai_assistant/public/functions/summarise.ts b/x-pack/plugins/observability_ai_assistant/public/functions/summarize.ts similarity index 93% rename from x-pack/plugins/observability_ai_assistant/public/functions/summarise.ts rename to x-pack/plugins/observability_ai_assistant/public/functions/summarize.ts index 7bef0e6399c3a..14f637591e613 100644 --- a/x-pack/plugins/observability_ai_assistant/public/functions/summarise.ts +++ b/x-pack/plugins/observability_ai_assistant/public/functions/summarize.ts @@ -8,7 +8,7 @@ import type { RegisterFunctionDefinition } from '../../common/types'; import type { ObservabilityAIAssistantService } from '../types'; -export function registerSummarisationFunction({ +export function registerSummarizationFunction({ service, registerFunction, }: { @@ -17,12 +17,12 @@ export function registerSummarisationFunction({ }) { registerFunction( { - name: 'summarise', + name: 'summarize', contexts: ['core'], description: - "Use this function to summarise things learned from the conversation. You can score the learnings with a confidence metric, whether it is a correction on a previous learning. An embedding will be created that you can recall later with a semantic search. There is no need to ask the user for permission to store something you have learned, unless you do not feel confident. When you create this summarisation, make sure you craft it in a way that can be recalled with a semantic search later, and that it would have answered the user's original request.", + "Use this function to summarize things learned from the conversation. You can score the learnings with a confidence metric, whether it is a correction on a previous learning. An embedding will be created that you can recall later with a semantic search. There is no need to ask the user for permission to store something you have learned, unless you do not feel confident. When you create this summarisation, make sure you craft it in a way that can be recalled with a semantic search later, and that it would have answered the user's original request.", descriptionForUser: - 'This function allows the Elastic Assistant to summarise things from the conversation.', + 'This function allows the Elastic Assistant to summarize things from the conversation.', parameters: { type: 'object', additionalProperties: false, @@ -66,7 +66,7 @@ export function registerSummarisationFunction({ signal ) => { return service - .callApi('POST /internal/observability_ai_assistant/functions/summarise', { + .callApi('POST /internal/observability_ai_assistant/functions/summarize', { params: { body: { id, diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts index 3284cdf66e99f..829594b8261d8 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts @@ -434,11 +434,20 @@ describe('useTimeline', () => { expect(props.onChatComplete).not.toHaveBeenCalled(); - expect(props.chatService.executeFunction).toHaveBeenCalledWith( - 'my_function', - '{}', - expect.any(Object) - ); + expect(props.chatService.executeFunction).toHaveBeenCalledWith({ + name: 'my_function', + args: '{}', + messages: [ + { + '@timestamp': expect.any(String), + message: { + content: 'Hello', + role: 'user', + }, + }, + ], + signal: expect.any(Object), + }); act(() => { subject.next({ diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts index 77c7a202754d9..3182fe5c19535 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts @@ -182,11 +182,12 @@ export function useTimeline({ const name = lastMessage.message.function_call.name; try { - const message = await chatService!.executeFunction( + const message = await chatService!.executeFunction({ name, - lastMessage.message.function_call.arguments, - controller.signal - ); + args: lastMessage.message.function_call.arguments, + messages: messagesAfterChat.slice(0, -1), + signal: controller.signal, + }); return await chat( messagesAfterChat.concat({ diff --git a/x-pack/plugins/observability_ai_assistant/public/i18n.ts b/x-pack/plugins/observability_ai_assistant/public/i18n.ts index 533e0fff950b9..dcc28d7ff531a 100644 --- a/x-pack/plugins/observability_ai_assistant/public/i18n.ts +++ b/x-pack/plugins/observability_ai_assistant/public/i18n.ts @@ -7,6 +7,13 @@ import { i18n } from '@kbn/i18n'; +export const ASSISTANT_SETUP_TITLE = i18n.translate( + 'xpack.observabilityAiAssistant.assistantSetup.title', + { + defaultMessage: 'Welcome to Elastic AI Assistant', + } +); + export const EMPTY_CONVERSATION_TITLE = i18n.translate( 'xpack.observabilityAiAssistant.emptyConversationTitle', { defaultMessage: 'New conversation' } diff --git a/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx b/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx index c9331f75244b7..5af2e740deb9b 100644 --- a/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/routes/conversations/conversation_view.tsx @@ -23,6 +23,7 @@ import { useObservabilityAIAssistant } from '../../hooks/use_observability_ai_as import { useObservabilityAIAssistantParams } from '../../hooks/use_observability_ai_assistant_params'; import { useObservabilityAIAssistantRouter } from '../../hooks/use_observability_ai_assistant_router'; import { getConnectorsManagementHref } from '../../utils/get_connectors_management_href'; +import { getModelsManagementHref } from '../../utils/get_models_management_href'; import { EMPTY_CONVERSATION_TITLE } from '../../i18n'; const containerClassName = css` @@ -230,10 +231,12 @@ export function ConversationView() { currentUser={currentUser} connectors={connectors} connectorsManagementHref={getConnectorsManagementHref(http)} + modelsManagementHref={getModelsManagementHref(http)} conversationId={conversationId} knowledgeBase={knowledgeBase} messages={displayedMessages} title={conversation.value.conversation.title} + startedFrom="conversationView" onChatUpdate={(messages) => { setDisplayedMessages(messages); }} diff --git a/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts b/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts index 7f04c25ac0b01..1c109be6baaf2 100644 --- a/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts +++ b/x-pack/plugins/observability_ai_assistant/public/service/create_chat_service.ts @@ -74,7 +74,7 @@ export async function createChatService({ }; const registerFunction: RegisterFunctionDefinition = (def, respond, render) => { - validators.set(def.name, new Validator(def.parameters as Schema, '2020-12', false)); + validators.set(def.name, new Validator(def.parameters as Schema, '2020-12', true)); functionRegistry.set(def.name, { options: def, respond, render }); }; @@ -112,7 +112,7 @@ export async function createChatService({ } return { - executeFunction: async (name, args, signal) => { + executeFunction: async ({ name, args, signal, messages }) => { const fn = functionRegistry.get(name); if (!fn) { @@ -123,7 +123,7 @@ export async function createChatService({ validate(name, parsedArguments); - return await fn.respond({ arguments: parsedArguments }, signal); + return await fn.respond({ arguments: parsedArguments, messages }, signal); }, renderFunction: (name, args, response) => { const fn = functionRegistry.get(name); diff --git a/x-pack/plugins/observability_ai_assistant/public/types.ts b/x-pack/plugins/observability_ai_assistant/public/types.ts index 6883a33309fcb..d1a71f6933126 100644 --- a/x-pack/plugins/observability_ai_assistant/public/types.ts +++ b/x-pack/plugins/observability_ai_assistant/public/types.ts @@ -65,11 +65,12 @@ export interface ObservabilityAIAssistantChatService { getContexts: () => ContextDefinition[]; getFunctions: (options?: { contexts?: string[]; filter?: string }) => FunctionDefinition[]; hasRenderFunction: (name: string) => boolean; - executeFunction: ( - name: string, - args: string | undefined, - signal: AbortSignal - ) => Promise<{ content?: Serializable; data?: Serializable }>; + executeFunction: ({}: { + name: string; + args: string | undefined; + messages: Message[]; + signal: AbortSignal; + }) => Promise<{ content?: Serializable; data?: Serializable }>; renderFunction: ( name: string, args: string | undefined, diff --git a/x-pack/plugins/transform/common/types/privileges.ts b/x-pack/plugins/observability_ai_assistant/public/utils/get_models_management_href.ts similarity index 59% rename from x-pack/plugins/transform/common/types/privileges.ts rename to x-pack/plugins/observability_ai_assistant/public/utils/get_models_management_href.ts index 702b62210d062..8ff585e005f95 100644 --- a/x-pack/plugins/transform/common/types/privileges.ts +++ b/x-pack/plugins/observability_ai_assistant/public/utils/get_models_management_href.ts @@ -5,11 +5,8 @@ * 2.0. */ -export interface MissingPrivileges { - [key: string]: string[] | undefined; -} +import { HttpStart } from '@kbn/core/public'; -export interface Privileges { - hasAllPrivileges: boolean; - missingPrivileges: MissingPrivileges; +export function getModelsManagementHref(http: HttpStart) { + return http!.basePath.prepend(`/app/ml/trained_models`); } diff --git a/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx b/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx index 657de54b11f3f..3c4dc569ab5e5 100644 --- a/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/utils/storybook_decorator.tsx @@ -25,11 +25,12 @@ const chatService: ObservabilityAIAssistantChatService = { chat: (options: { messages: Message[]; connectorId: string }) => new Observable(), getContexts: () => [], getFunctions: () => [buildFunctionElasticsearch(), buildFunctionServiceSummary()], - executeFunction: async ( - name: string, - args: string | undefined, - signal: AbortSignal - ): Promise<{ content?: Serializable; data?: Serializable }> => ({}), + executeFunction: async ({}: { + name: string; + args: string | undefined; + messages: Message[]; + signal: AbortSignal; + }): Promise<{ content?: Serializable; data?: Serializable }> => ({}), renderFunction: (name: string, args: string | undefined, response: {}) => (
Hello! {name}
), diff --git a/x-pack/plugins/observability_ai_assistant/server/plugin.ts b/x-pack/plugins/observability_ai_assistant/server/plugin.ts index 01bd4fafb71c7..7aa6ddeeef7da 100644 --- a/x-pack/plugins/observability_ai_assistant/server/plugin.ts +++ b/x-pack/plugins/observability_ai_assistant/server/plugin.ts @@ -62,9 +62,6 @@ export class ObservabilityAIAssistantPlugin category: DEFAULT_APP_CATEGORIES.observability, app: [OBSERVABILITY_AI_ASSISTANT_FEATURE_ID, 'kibana'], catalogue: [OBSERVABILITY_AI_ASSISTANT_FEATURE_ID], - management: { - insightsAndAlerting: ['triggersActionsConnectors'], - }, minimumLicense: 'enterprise', // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { @@ -80,9 +77,6 @@ export class ObservabilityAIAssistantPlugin ], read: [], }, - management: { - insightsAndAlerting: ['triggersActionsConnectors'], - }, ui: ['show'], }, read: { diff --git a/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts b/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts index 2d44307147a52..6716da98d78a5 100644 --- a/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts +++ b/x-pack/plugins/observability_ai_assistant/server/routes/chat/route.ts @@ -4,12 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import * as t from 'io-ts'; -import { IncomingMessage } from 'http'; import { notImplemented } from '@hapi/boom'; +import { IncomingMessage } from 'http'; +import * as t from 'io-ts'; +import { MessageRole } from '../../../common'; import { createObservabilityAIAssistantServerRoute } from '../create_observability_ai_assistant_server_route'; import { messageRt } from '../runtime_types'; -import { MessageRole } from '../../../common'; const chatRoute = createObservabilityAIAssistantServerRoute({ endpoint: 'POST /internal/observability_ai_assistant/chat', @@ -47,13 +47,15 @@ const chatRoute = createObservabilityAIAssistantServerRoute({ const isRecallFunctionAvailable = functions.some((fn) => fn.name === 'recall') === true; + const willUseRecall = isStartOfConversation && isRecallFunctionAvailable; + return client.chat({ messages, connectorId, ...(functions.length ? { functions, - functionCall: isStartOfConversation && isRecallFunctionAvailable ? 'recall' : undefined, + functionCall: willUseRecall ? 'recall' : undefined, } : {}), }); diff --git a/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts b/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts index 8c732ee00c462..d58c84a603fc1 100644 --- a/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts +++ b/x-pack/plugins/observability_ai_assistant/server/routes/functions/route.ts @@ -178,7 +178,7 @@ const functionRecallRoute = createObservabilityAIAssistantServerRoute({ }); const functionSummariseRoute = createObservabilityAIAssistantServerRoute({ - endpoint: 'POST /internal/observability_ai_assistant/functions/summarise', + endpoint: 'POST /internal/observability_ai_assistant/functions/summarize', params: t.type({ body: t.type({ id: t.string, @@ -208,7 +208,7 @@ const functionSummariseRoute = createObservabilityAIAssistantServerRoute({ labels, } = resources.params.body; - return client.summarise({ + return client.summarize({ entry: { confidence, id, diff --git a/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts index dd256c4784831..ce3f3c39ad1a9 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts @@ -246,9 +246,17 @@ export class ObservabilityAIAssistantClient { }); if ('object' in response && response.object === 'chat.completion') { - const title = - response.choices[0].message?.content?.slice(1, -1) || - `Conversation on ${conversation['@timestamp']}`; + const input = + response.choices[0].message?.content || `Conversation on ${conversation['@timestamp']}`; + + // This regular expression captures a string enclosed in single or double quotes. + // It extracts the string content without the quotes. + // Example matches: + // - "Hello, World!" => Captures: Hello, World! + // - 'Another Example' => Captures: Another Example + // - JustTextWithoutQuotes => Captures: JustTextWithoutQuotes + const match = input.match(/^["']?([^"']+)["']?$/); + const title = match ? match[1] : input; const updatedConversation: Conversation = merge( {}, @@ -325,12 +333,12 @@ export class ObservabilityAIAssistantClient { }); }; - summarise = async ({ + summarize = async ({ entry, }: { entry: Omit; }): Promise => { - return this.dependencies.knowledgeBaseService.summarise({ + return this.dependencies.knowledgeBaseService.summarize({ namespace: this.dependencies.namespace, user: this.dependencies.user, entry, diff --git a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts index eab3a0a2fbe57..f2e0b41f092c9 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts @@ -112,7 +112,7 @@ export class KnowledgeBaseService { return; } - await this.summarise({ + await this.summarize({ entry: operation.document, }); } @@ -223,7 +223,7 @@ export class KnowledgeBaseService { } }; - summarise = async ({ + summarize = async ({ entry: { id, ...document }, user, namespace, diff --git a/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/logs/feedback.cy.ts b/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/logs/feedback.cy.ts new file mode 100644 index 0000000000000..495fd5672bfb9 --- /dev/null +++ b/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/logs/feedback.cy.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. + */ + +describe('[Logs onboarding] Give Feedback', () => { + beforeEach(() => { + cy.loginAsElastic(); + cy.visitKibana('/app/observabilityOnboarding'); + }); + + it('feedback button is present in system logs onboarding', () => { + cy.getByTestSubj('obltOnboardingHomeStartSystemLogStream').click(); + cy.getByTestSubj('observabilityOnboardingPageGiveFeedback').should('exist'); + }); + + it('feedback button is present in custom logs onboarding', () => { + cy.getByTestSubj('obltOnboardingHomeStartLogFileStream').click(); + cy.getByTestSubj('observabilityOnboardingPageGiveFeedback').should('exist'); + }); + + it('feedback button is not present in the landing page', () => { + cy.getByTestSubj('observabilityOnboardingPageGiveFeedback').should( + 'not.exist' + ); + }); +}); diff --git a/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/logs/system_logs.cy.ts b/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/logs/system_logs.cy.ts new file mode 100644 index 0000000000000..3497ac145eaf3 --- /dev/null +++ b/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/logs/system_logs.cy.ts @@ -0,0 +1,657 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +describe('[Logs onboarding] System logs', () => { + describe('System integration', () => { + beforeEach(() => { + cy.deleteIntegration('system'); + }); + + describe('when user is missing privileges', () => { + beforeEach(() => { + cy.loginAsViewerUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + }); + + it('installation fails', () => { + cy.getByTestSubj( + 'obltOnboardingSystemLogsIntegrationInstallationFailed' + ).should('exist'); + }); + }); + + describe('when user has proper privileges', () => { + beforeEach(() => { + cy.loginAsEditorUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + }); + + after(() => { + cy.deleteIntegration('system'); + }); + + it('installation succeed', () => { + cy.getByTestSubj('obltOnboardingSystemLogsIntegrationInstalled').should( + 'exist' + ); + }); + + it('show link to navigate to system integration when clicking info icon', () => { + cy.getByTestSubj('obltOnboardingSystemLogsIntegrationInstalled').should( + 'exist' + ); + cy.getByTestSubj('obltOnboardingSystemLogsIntegrationInfo') + .should('exist') + .click(); + cy.getByTestSubj( + 'observabilityOnboardingSystemIntegrationLearnMore' + ).should('exist'); + }); + }); + }); + + describe('ApiKey generation', () => { + describe('when user is missing privileges', () => { + it('apiKey is not generated', () => { + cy.loginAsEditorUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + + cy.getByTestSubj('obltOnboardingLogsApiKeyCreationNoPrivileges').should( + 'exist' + ); + }); + }); + + describe('when user has proper privileges', () => { + beforeEach(() => { + cy.loginAsLogMonitoringUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + }); + + it('apiKey is generated', () => { + cy.getByTestSubj('obltOnboardingLogsApiKeyCreated').should('exist'); + }); + }); + + describe('when an error occurred on creation', () => { + before(() => { + cy.intercept('/internal/observability_onboarding/logs/flow', { + statusCode: 500, + body: { + message: 'Internal error', + }, + }); + + cy.loginAsLogMonitoringUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + }); + + it('apiKey is not generated', () => { + cy.getByTestSubj('obltOnboardingLogsApiKeyCreationFailed').should( + 'exist' + ); + }); + }); + }); + + describe('Install the Elastic Agent step', () => { + beforeEach(() => { + cy.intercept('POST', '/internal/observability_onboarding/logs/flow').as( + 'createOnboardingFlow' + ); + cy.loginAsLogMonitoringUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + }); + + describe('When user select Linux OS', () => { + it('Auto download config to host is disabled by default', () => { + cy.get('.euiButtonGroup').contains('Linux').click(); + cy.getByTestSubj('obltOnboardingInstallElasticAgentAutoDownloadConfig') + .should('be.enabled') + .should('not.be.checked'); + }); + + it('Installation script is shown', () => { + cy.getByTestSubj('obltOnboardingInstallElasticAgentStep') + .get('.euiCodeBlock') + .should('exist'); + }); + }); + + describe('When user select Mac OS', () => { + beforeEach(() => { + cy.get('.euiButtonGroup').contains('MacOS').click(); + }); + + it('Auto download config to host is disabled by default', () => { + cy.getByTestSubj('obltOnboardingInstallElasticAgentAutoDownloadConfig') + .should('be.enabled') + .should('not.be.checked'); + }); + + it('Installation script is shown', () => { + cy.getByTestSubj('obltOnboardingInstallElasticAgentStep') + .get('.euiCodeBlock') + .should('exist'); + }); + }); + + describe('When user select Windows OS', () => { + beforeEach(() => { + cy.get('.euiButtonGroup').contains('Windows').click(); + }); + + it('Auto download config to host is disabled by default', () => { + cy.getByTestSubj('obltOnboardingInstallElasticAgentAutoDownloadConfig') + .should('be.disabled') + .should('not.be.checked'); + }); + + it('A link to the documentation is shown instead of installation script', () => { + cy.getByTestSubj( + 'obltOnboardingInstallElasticAgentWindowsDocsLink' + ).should('exist'); + + cy.getByTestSubj('obltOnboardingInstallElasticAgentStep') + .get('.euiCodeBlock') + .should('not.exist'); + }); + }); + + describe('When Auto download config', () => { + describe('is selected', () => { + it('autoDownloadConfig flag is added to installation script', () => { + cy.getByTestSubj( + 'obltOnboardingInstallElasticAgentAutoDownloadConfig' + ).click(); + cy.getByTestSubj( + 'obltOnboardingInstallElasticAgentAutoDownloadConfigCallout' + ).should('exist'); + cy.getByTestSubj('obltOnboardingInstallElasticAgentStep') + .get('.euiCodeBlock') + .should('contain', 'autoDownloadConfig=1'); + }); + + it('Download config button is disabled', () => { + cy.getByTestSubj( + 'obltOnboardingInstallElasticAgentAutoDownloadConfig' + ).click(); + cy.getByTestSubj( + 'obltOnboardingConfigureElasticAgentStepDownloadConfig' + ).should('be.disabled'); + }); + }); + + it('is not selected autoDownloadConfig flag is not added to installation script', () => { + cy.getByTestSubj('obltOnboardingInstallElasticAgentStep') + .get('.euiCodeBlock') + .should('not.contain', 'autoDownloadConfig=1'); + }); + }); + + describe('When user executes the installation script in the host', () => { + let onboardingId: string; + + describe('updates on steps are shown in the flow', () => { + beforeEach(() => { + cy.wait('@createOnboardingFlow') + .its('response.body') + .then((body) => { + onboardingId = body.onboardingId; + }); + }); + + describe('Download elastic Agent step', () => { + it('shows a loading callout when elastic agent is downloading', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'loading' + ); + cy.getByTestSubj('obltOnboardingStepStatus-loading') + .contains('Downloading Elastic Agent') + .should('exist'); + }); + + it('shows a success callout when elastic agent is downloaded', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.getByTestSubj('obltOnboardingStepStatus-complete') + .contains('Elastic Agent downloaded') + .should('exist'); + }); + + it('shows a danger callout when elastic agent was not downloaded', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'danger' + ); + cy.getByTestSubj('obltOnboardingStepStatus-danger') + .contains('Download Elastic Agent') + .should('exist'); + }); + }); + + describe('Extract elastic Agent step', () => { + beforeEach(() => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + }); + + it('shows a loading callout when elastic agent is extracting', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'loading' + ); + cy.getByTestSubj('obltOnboardingStepStatus-loading') + .contains('Extracting Elastic Agent') + .should('exist'); + }); + + it('shows a success callout when elastic agent is extracted', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + cy.getByTestSubj('obltOnboardingStepStatus-complete') + .contains('Elastic Agent extracted') + .should('exist'); + }); + + it('shows a danger callout when elastic agent was not extracted', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'danger' + ); + cy.getByTestSubj('obltOnboardingStepStatus-danger') + .contains('Extract Elastic Agent') + .should('exist'); + }); + }); + + describe('Install elastic Agent step', () => { + beforeEach(() => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + }); + + it('shows a loading callout when elastic agent is installing', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'loading' + ); + cy.getByTestSubj('obltOnboardingStepStatus-loading') + .contains('Installing Elastic Agent') + .should('exist'); + }); + + it('shows a success callout when elastic agent is installed', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); + cy.getByTestSubj('obltOnboardingStepStatus-complete') + .contains('Elastic Agent installed') + .should('exist'); + }); + + it('shows a danger callout when elastic agent was not installed', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'danger' + ); + cy.getByTestSubj('obltOnboardingStepStatus-danger') + .contains('Install Elastic Agent') + .should('exist'); + }); + }); + + describe('Check elastic Agent status step', () => { + beforeEach(() => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); + }); + + it('shows a loading callout when getting elastic agent status', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'loading' + ); + cy.getByTestSubj('obltOnboardingStepStatus-loading') + .contains('Connecting to the Elastic Agent') + .should('exist'); + }); + + it('shows a success callout when elastic agent status is healthy', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'complete' + ); + cy.getByTestSubj('obltOnboardingStepStatus-complete') + .contains('Connected to the Elastic Agent') + .should('exist'); + }); + + it('shows a warning callout when elastic agent status is not healthy', () => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'warning' + ); + cy.getByTestSubj('obltOnboardingStepStatus-warning') + .contains('Connect to the Elastic Agent') + .should('exist'); + }); + }); + }); + }); + }); + + describe('Configure Elastic Agent step', () => { + let onboardingId: string; + + beforeEach(() => { + cy.intercept('POST', '/internal/observability_onboarding/logs/flow').as( + 'createOnboardingFlow' + ); + cy.loginAsLogMonitoringUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + cy.wait('@createOnboardingFlow') + .its('response.body') + .then((body) => { + onboardingId = body.onboardingId; + }); + }); + + describe('When user select Linux OS', () => { + beforeEach(() => { + cy.getByTestSubj( + 'obltOnboardingInstallElasticAgentAutoDownloadConfig' + ).click(); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.updateInstallationStepStatus(onboardingId, 'ea-extract', 'complete'); + cy.updateInstallationStepStatus(onboardingId, 'ea-install', 'complete'); + cy.updateInstallationStepStatus(onboardingId, 'ea-status', 'complete'); + }); + + it('shows loading callout when config is being downloaded to the host', () => { + cy.updateInstallationStepStatus(onboardingId, 'ea-config', 'loading'); + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-loading"]' + ).should('exist'); + cy.getByTestSubj('obltOnboardingStepStatus-loading') + .contains('Downloading Elastic Agent config') + .should('exist'); + }); + + it('shows success callout when the configuration has been written to the host', () => { + cy.updateInstallationStepStatus(onboardingId, 'ea-config', 'complete'); + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-complete"]' + ).should('exist'); + cy.getByTestSubj('obltOnboardingStepStatus-complete') + .contains( + 'Elastic Agent config written to /opt/Elastic/Agent/elastic-agent.yml' + ) + .should('exist'); + }); + + it('shows warning callout when the configuration was not written in the host', () => { + cy.updateInstallationStepStatus(onboardingId, 'ea-config', 'warning'); + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-warning"]' + ).should('exist'); + cy.getByTestSubj('obltOnboardingStepStatus-warning') + .contains('Configure the agent') + .should('exist'); + }); + }); + + describe('When user select Mac OS', () => { + beforeEach(() => { + cy.get('.euiButtonGroup').contains('MacOS').click(); + cy.getByTestSubj( + 'obltOnboardingInstallElasticAgentAutoDownloadConfig' + ).click(); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.updateInstallationStepStatus(onboardingId, 'ea-extract', 'complete'); + cy.updateInstallationStepStatus(onboardingId, 'ea-install', 'complete'); + cy.updateInstallationStepStatus(onboardingId, 'ea-status', 'complete'); + }); + + it('shows loading callout when config is being downloaded to the host', () => { + cy.updateInstallationStepStatus(onboardingId, 'ea-config', 'loading'); + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-loading"]' + ).should('exist'); + cy.getByTestSubj('obltOnboardingStepStatus-loading') + .contains('Downloading Elastic Agent config') + .should('exist'); + }); + + it('shows success callout when the configuration has been written to the host', () => { + cy.updateInstallationStepStatus(onboardingId, 'ea-config', 'complete'); + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-complete"]' + ).should('exist'); + cy.getByTestSubj('obltOnboardingStepStatus-complete') + .contains( + 'Elastic Agent config written to /Library/Elastic/Agent/elastic-agent.yml' + ) + .should('exist'); + }); + + it('shows warning callout when the configuration was not written in the host', () => { + cy.updateInstallationStepStatus(onboardingId, 'ea-config', 'warning'); + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-warning"]' + ).should('exist'); + cy.getByTestSubj('obltOnboardingStepStatus-warning') + .contains('Configure the agent') + .should('exist'); + }); + }); + + describe('When user select Windows', () => { + beforeEach(() => { + cy.get('.euiButtonGroup').contains('Windows').click(); + }); + + it('step is disabled', () => { + cy.get( + '[data-test-subj="obltOnboardingConfigureElasticAgentStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-disabled"]' + ).should('exist'); + }); + }); + }); + + describe('Check logs step', () => { + let onboardingId: string; + + beforeEach(() => { + cy.intercept('POST', '/internal/observability_onboarding/logs/flow').as( + 'createOnboardingFlow' + ); + cy.loginAsLogMonitoringUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + cy.wait('@createOnboardingFlow') + .its('response.body') + .then((body) => { + onboardingId = body.onboardingId; + }); + }); + + describe('When user select Linux OS or MacOS', () => { + describe('When configure Elastic Agent step is not finished', () => { + beforeEach(() => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); + cy.updateInstallationStepStatus(onboardingId, 'ea-status', 'loading'); + }); + + it('check logs is not triggered', () => { + cy.get( + '[data-test-subj="obltOnboardingCheckLogsStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-incomplete"]' + ).should('exist'); + cy.get('.euiStep__title') + .contains('Ship logs to Elastic Observability') + .should('exist'); + }); + }); + + describe('When configure Elastic Agent step has finished', () => { + beforeEach(() => { + cy.updateInstallationStepStatus( + onboardingId, + 'ea-download', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-extract', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-install', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-status', + 'complete' + ); + cy.updateInstallationStepStatus( + onboardingId, + 'ea-config', + 'complete' + ); + }); + + it('shows loading callout when logs are being checked', () => { + cy.get( + '[data-test-subj="obltOnboardingCheckLogsStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-loading"]' + ).should('exist'); + cy.get('.euiStep__title') + .contains('Waiting for logs to be shipped...') + .should('exist'); + }); + }); + }); + + describe('When user select Windows', () => { + beforeEach(() => { + cy.get('.euiButtonGroup').contains('Windows').click(); + }); + + it('step is disabled', () => { + cy.get( + '[data-test-subj="obltOnboardingCheckLogsStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-disabled"]' + ).should('exist'); + }); + }); + }); + + describe('When logs are being shipped', () => { + beforeEach(() => { + cy.intercept('GET', '**/progress', { + status: 200, + body: { + progress: { + 'ea-download': { status: 'complete' }, + 'ea-extract': { status: 'complete' }, + 'ea-install': { status: 'complete' }, + 'ea-status': { status: 'complete' }, + 'ea-config': { status: 'complete' }, + 'logs-ingest': { status: 'complete' }, + }, + }, + }).as('checkOnboardingProgress'); + cy.intercept('GET', '/api/fleet/epm/packages/system').as( + 'systemIntegrationInstall' + ); + cy.loginAsLogMonitoringUser(); + cy.visitKibana('/app/observabilityOnboarding/systemLogs'); + }); + + it('shows success callout when logs has arrived to elastic', () => { + cy.wait('@checkOnboardingProgress'); + cy.get( + '[data-test-subj="obltOnboardingCheckLogsStep"] .euiStep__titleWrapper [class$="euiStepNumber-s-complete"]' + ).should('exist'); + cy.get('.euiStep__title') + .contains('Logs are being shipped!') + .should('exist'); + }); + + it('when user clicks on Explore Logs it navigates to discover', () => { + cy.wait('@systemIntegrationInstall'); + cy.wait('@checkOnboardingProgress'); + cy.getByTestSubj('obltOnboardingExploreLogs').should('exist').click(); + cy.url().should('include', '/app/discover'); + + cy.get('button[title="logs-*"]').should('exist'); + }); + }); +}); diff --git a/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/navigation.cy.ts b/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/navigation.cy.ts new file mode 100644 index 0000000000000..cc5d0e2500ad1 --- /dev/null +++ b/x-pack/plugins/observability_onboarding/e2e/cypress/e2e/navigation.cy.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +describe('[Observability onboarding] Navigation', () => { + beforeEach(() => { + cy.loginAsElastic(); + cy.visitKibana('/app/observabilityOnboarding/'); + }); + + describe('When user clicks on the card', () => { + it('navigates to system logs onboarding', () => { + cy.getByTestSubj('obltOnboardingHomeStartSystemLogStream').click(); + + cy.url().should('include', '/app/observabilityOnboarding/systemLogs'); + }); + + it('navigates to custom logs onboarding', () => { + cy.getByTestSubj('obltOnboardingHomeStartLogFileStream').click(); + + cy.url().should('include', '/app/observabilityOnboarding/customLogs'); + }); + + it('navigates to apm tutorial', () => { + cy.getByTestSubj('obltOnboardingHomeStartApmTutorial').click(); + + cy.url().should('include', '/app/home#/tutorial/apm'); + }); + + it('navigates to kubernetes integration', () => { + cy.getByTestSubj('obltOnboardingHomeGoToKubernetesIntegration').click(); + + cy.url().should( + 'include', + '/app/integrations/detail/kubernetes/overview' + ); + }); + + it('navigates to integrations', () => { + cy.getByTestSubj('obltOnboardingHomeExploreIntegrations').click(); + + cy.url().should('include', '/app/integrations/browse'); + }); + }); + + describe('When user clicks on Quick links', () => { + it('navigates to use sample data', () => { + cy.getByTestSubj('obltOnboardingHomeUseSampleData').click(); + + cy.url().should('include', '/app/home#/tutorial_directory/sampleData'); + }); + + it('navigates to upload a file', () => { + cy.getByTestSubj('obltOnboardingHomeUploadAFile').click(); + + cy.url().should('include', '/app/home#/tutorial_directory/fileDataViz'); + }); + }); +}); diff --git a/x-pack/plugins/observability_onboarding/e2e/cypress/support/commands.ts b/x-pack/plugins/observability_onboarding/e2e/cypress/support/commands.ts index 299729f1d8fa7..ea321f48a0bae 100644 --- a/x-pack/plugins/observability_onboarding/e2e/cypress/support/commands.ts +++ b/x-pack/plugins/observability_onboarding/e2e/cypress/support/commands.ts @@ -6,6 +6,51 @@ */ import URL from 'url'; +import { ObservabilityOnboardingUsername } from '../../../server/test_helpers/create_observability_onboarding_users/authentication'; + +export type InstallationStep = + | 'ea-download' + | 'ea-extract' + | 'ea-install' + | 'ea-status' + | 'ea-config'; + +export type InstallationStepStatus = + | 'incomplete' + | 'complete' + | 'disabled' + | 'loading' + | 'warning' + | 'danger' + | 'current'; + +Cypress.Commands.add('loginAsViewerUser', () => { + return cy.loginAs({ + username: ObservabilityOnboardingUsername.viewerUser, + password: 'changeme', + }); +}); + +Cypress.Commands.add('loginAsEditorUser', () => { + return cy.loginAs({ + username: ObservabilityOnboardingUsername.editorUser, + password: 'changeme', + }); +}); + +Cypress.Commands.add('loginAsLogMonitoringUser', () => { + return cy.loginAs({ + username: ObservabilityOnboardingUsername.logMonitoringUser, + password: 'changeme', + }); +}); + +Cypress.Commands.add('loginAsElastic', () => { + return cy.loginAs({ + username: 'elastic', + password: 'changeme', + }); +}); Cypress.Commands.add( 'loginAs', @@ -31,13 +76,6 @@ Cypress.Commands.add( } ); -Cypress.Commands.add('loginAsElastic', () => { - return cy.loginAs({ - username: 'elastic', - password: 'changeme', - }); -}); - Cypress.Commands.add('getByTestSubj', (selector: string) => { return cy.get(`[data-test-subj="${selector}"]`); }); @@ -57,3 +95,59 @@ Cypress.Commands.add( }); } ); + +Cypress.Commands.add('deleteIntegration', (integrationName: string) => { + const kibanaUrl = Cypress.env('KIBANA_URL'); + + cy.request({ + log: false, + method: 'GET', + url: `${kibanaUrl}/api/fleet/epm/packages/${integrationName}`, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + auth: { user: 'editor', pass: 'changeme' }, + }).then((response) => { + const status = response.body.item.status; + if (status === 'installed') { + cy.request({ + log: false, + method: 'DELETE', + url: `${kibanaUrl}/api/fleet/epm/packages/${integrationName}`, + body: { + force: false, + }, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + auth: { user: 'editor', pass: 'changeme' }, + }); + } + }); +}); + +Cypress.Commands.add( + 'updateInstallationStepStatus', + ( + onboardingId: string, + step: InstallationStep, + status: InstallationStepStatus + ) => { + const kibanaUrl = Cypress.env('KIBANA_URL'); + + cy.log(onboardingId, step, status); + + cy.request({ + log: false, + method: 'POST', + url: `${kibanaUrl}/internal/observability_onboarding/flow/${onboardingId}/step/${step}`, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + auth: { user: 'editor', pass: 'changeme' }, + body: { + status, + }, + }); + } +); diff --git a/x-pack/plugins/observability_onboarding/e2e/cypress/support/types.d.ts b/x-pack/plugins/observability_onboarding/e2e/cypress/support/types.d.ts index 8db14ad70561a..6b5695d159d76 100644 --- a/x-pack/plugins/observability_onboarding/e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/observability_onboarding/e2e/cypress/support/types.d.ts @@ -11,8 +11,17 @@ declare namespace Cypress { username: string; password: string; }): Cypress.Chainable>; + loginAsViewerUser(): Cypress.Chainable>; + loginAsEditorUser(): Cypress.Chainable>; + loginAsLogMonitoringUser(): Cypress.Chainable>; loginAsElastic(): Cypress.Chainable>; getByTestSubj(selector: string): Chainable>; visitKibana(url: string, rangeFrom?: string, rangeTo?: string): void; + deleteIntegration(integrationName: string): void; + updateInstallationStepStatus( + onboardingId: string, + step: InstallationStep, + status: InstallationStepStatus + ): void; } } diff --git a/x-pack/plugins/observability_onboarding/e2e/cypress_test_runner.ts b/x-pack/plugins/observability_onboarding/e2e/cypress_test_runner.ts index 1d056897a6d02..34765a892cc1c 100644 --- a/x-pack/plugins/observability_onboarding/e2e/cypress_test_runner.ts +++ b/x-pack/plugins/observability_onboarding/e2e/cypress_test_runner.ts @@ -9,6 +9,7 @@ import cypress from 'cypress'; import path from 'path'; import Url from 'url'; import { FtrProviderContext } from './ftr_provider_context'; +import { createObservabilityOnboardingUsers } from '../server/test_helpers/create_observability_onboarding_users'; export async function cypressTestRunner({ ftrProviderContext: { getService }, @@ -22,6 +23,13 @@ export async function cypressTestRunner({ const username = config.get('servers.elasticsearch.username'); const password = config.get('servers.elasticsearch.password'); + const kibanaUrl = Url.format({ + protocol: config.get('servers.kibana.protocol'), + hostname: config.get('servers.kibana.hostname'), + port: config.get('servers.kibana.port'), + auth: `${username}:${password}`, + }); + const esNode = Url.format({ protocol: config.get('servers.elasticsearch.protocol'), port: config.get('servers.elasticsearch.port'), @@ -29,6 +37,12 @@ export async function cypressTestRunner({ auth: `${username}:${password}`, }); + // Creates ObservabilityOnboarding users + await createObservabilityOnboardingUsers({ + elasticsearch: { node: esNode, username, password }, + kibana: { hostname: kibanaUrl }, + }); + const esRequestTimeout = config.get('timeouts.esRequestTimeout'); const kibanaUrlWithoutAuth = Url.format({ diff --git a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx index 57a7ba7b4cab1..c55f554fc4845 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/custom_logs/wizard/api_key_banner.tsx @@ -54,6 +54,7 @@ export function ApiKeyBanner({
} color="primary" + data-test-subj="obltOnboardingLogsCreatingApiKey" /> ); @@ -67,6 +68,7 @@ export function ApiKeyBanner({ )} color="success" iconType="check" + data-test-subj="obltOnboardingLogsApiKeyCreated" >

{i18n.translate( @@ -123,6 +125,7 @@ export function ApiKeyBanner({ )} color="danger" iconType="error" + data-test-subj="obltOnboardingLogsApiKeyCreationFailed" >

{i18n.translate( @@ -148,6 +151,7 @@ export function ApiKeyBanner({ )} color="warning" iconType="warning" + data-test-subj="obltOnboardingLogsApiKeyCreationNoPrivileges" >

{i18n.translate( diff --git a/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx b/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx index 27a44e94f07b6..6dcb343b222cb 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/home/index.tsx @@ -123,7 +123,12 @@ export function Home() { { defaultMessage: 'Stream host system logs' } )} footer={ - + {getStartedLabel} } @@ -216,7 +221,11 @@ export function Home() { } )} footer={ - + {getStartedLabel} } @@ -245,6 +254,7 @@ export function Home() { {getStartedLabel} @@ -282,7 +292,11 @@ export function Home() { )} footer={ <> - + {i18n.translate( 'xpack.observability_onboarding.card.integrations.start', { defaultMessage: 'Start exploring' } @@ -298,14 +312,20 @@ export function Home() { - + {i18n.translate( 'xpack.observability_onboarding.card.integrations.sampleData', { defaultMessage: 'Use sample data' } )} - + {i18n.translate( 'xpack.observability_onboarding.card.integrations.uploadFile', { defaultMessage: 'Upload a file' } diff --git a/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx b/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx index 5a71c588c0711..4c7e7fd63625e 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/system_logs/install_elastic_agent.tsx @@ -171,7 +171,11 @@ export function InstallElasticAgent() { : stepStatus === 'complete' ? CHECK_LOGS_LABELS.completed : CHECK_LOGS_LABELS.incomplete; - return { title, status: stepStatus }; + return { + title, + status: stepStatus, + 'data-test-subj': 'obltOnboardingCheckLogsStep', + }; } return { title: CHECK_LOGS_LABELS.incomplete, @@ -203,6 +207,7 @@ export function InstallElasticAgent() { fill iconType="magnifyWithPlus" onClick={onContinue} + data-test-subj="obltOnboardingExploreLogs" > {i18n.translate( 'xpack.observability_onboarding.steps.exploreLogs', diff --git a/x-pack/plugins/observability_onboarding/public/components/app/system_logs/system_integration_banner.tsx b/x-pack/plugins/observability_onboarding/public/components/app/system_logs/system_integration_banner.tsx index d567a13f3d3a4..61ebaca8056ea 100644 --- a/x-pack/plugins/observability_onboarding/public/components/app/system_logs/system_integration_banner.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/app/system_logs/system_integration_banner.tsx @@ -74,6 +74,7 @@ export function SystemIntegrationBanner() { } color="primary" + data-test-subj="obltOnboardingSystemLogsInstallingIntegration" /> ); } @@ -89,6 +90,7 @@ export function SystemIntegrationBanner() { )} color="warning" iconType="warning" + data-test-subj="obltOnboardingSystemLogsIntegrationInstallationFailed" > {error?.message} @@ -106,6 +108,7 @@ export function SystemIntegrationBanner() { values={{ systemIntegrationTooltip: ( ); diff --git a/x-pack/plugins/observability_onboarding/public/components/shared/install_elastic_agent_steps.tsx b/x-pack/plugins/observability_onboarding/public/components/shared/install_elastic_agent_steps.tsx index 16996a18d05b0..282591e0a1487 100644 --- a/x-pack/plugins/observability_onboarding/public/components/shared/install_elastic_agent_steps.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/shared/install_elastic_agent_steps.tsx @@ -111,12 +111,7 @@ export function InstallElasticAgentSteps({ selectedPlatform ); return ( - + ); })} @@ -184,6 +179,7 @@ export function InstallElasticAgentSteps({ download="elastic-agent.yml" target="_blank" isDisabled={autoDownloadConfig} + data-test-subj="obltOnboardingConfigureElasticAgentStepDownloadConfig" > {i18n.translate( 'xpack.observability_onboarding.installElasticAgent.configStep.downloadConfigButton', @@ -209,6 +205,7 @@ export function InstallElasticAgentSteps({ ({ checked={autoDownloadConfig} onChange={onToggleAutoDownloadConfig} disabled={disableSteps || isInstallStarted} + data-test-subj="obltOnboardingInstallElasticAgentAutoDownloadConfig" /> {autoDownloadConfig && ( @@ -288,6 +286,7 @@ export function InstallElasticAgentSteps({ )} color="warning" iconType="warning" + data-test-subj="obltOnboardingInstallElasticAgentAutoDownloadConfigCallout" /> @@ -318,6 +317,7 @@ export function InstallElasticAgentSteps({ ), }, { + 'data-test-subj': 'obltOnboardingConfigureElasticAgentStep', title: i18n.translate( 'xpack.observability_onboarding.installElasticAgent.configureStep.title', { defaultMessage: 'Configure the Elastic agent' } @@ -329,6 +329,7 @@ export function InstallElasticAgentSteps({ children: null, ...euiStep, status: disableSteps ? 'disabled' : euiStep.status, + 'data-test-subj': euiStep['data-test-subj'], })), ]} /> diff --git a/x-pack/plugins/observability_onboarding/public/components/shared/popover_tooltip.tsx b/x-pack/plugins/observability_onboarding/public/components/shared/popover_tooltip.tsx index 66165edc8e133..8a0e8b53e7350 100644 --- a/x-pack/plugins/observability_onboarding/public/components/shared/popover_tooltip.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/shared/popover_tooltip.tsx @@ -13,6 +13,7 @@ interface PopoverTooltipProps { iconType?: string; title?: string; children: React.ReactNode; + dataTestSubj: string; } export function PopoverTooltip({ @@ -20,6 +21,7 @@ export function PopoverTooltip({ iconType = 'iInCircle', title, children, + dataTestSubj, }: PopoverTooltipProps) { const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -32,6 +34,7 @@ export function PopoverTooltip({ style={{ margin: '-5px 0 0 -5px' }} button={ ) => { setIsPopoverOpen(!isPopoverOpen); diff --git a/x-pack/plugins/observability_onboarding/public/components/shared/step_status.tsx b/x-pack/plugins/observability_onboarding/public/components/shared/step_status.tsx index 59ad5d202cf89..d2a5341fda731 100644 --- a/x-pack/plugins/observability_onboarding/public/components/shared/step_status.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/shared/step_status.tsx @@ -27,7 +27,7 @@ export function StepStatus({ }) { if (status === 'loading') { return ( - + @@ -43,7 +43,7 @@ export function StepStatus({ } if (status === 'complete') { return ( - + {message} @@ -52,7 +52,7 @@ export function StepStatus({ } if (status === 'danger') { return ( - + {message} @@ -61,7 +61,7 @@ export function StepStatus({ } if (status === 'warning') { return ( - + {message} diff --git a/x-pack/plugins/observability_onboarding/public/components/shared/windows_install_step.tsx b/x-pack/plugins/observability_onboarding/public/components/shared/windows_install_step.tsx index 42677924a4706..6784095d4e516 100644 --- a/x-pack/plugins/observability_onboarding/public/components/shared/windows_install_step.tsx +++ b/x-pack/plugins/observability_onboarding/public/components/shared/windows_install_step.tsx @@ -40,6 +40,7 @@ export function WindowsInstallStep({ href={docsLink} target="_blank" style={{ width: 'fit-content' }} + data-test-subj="obltOnboardingInstallElasticAgentWindowsDocsLink" > {i18n.translate( 'xpack.observability_onboarding.windows.installStep.link.label', diff --git a/x-pack/plugins/observability_onboarding/server/routes/logs/route.ts b/x-pack/plugins/observability_onboarding/server/routes/logs/route.ts index c28c393382930..085f7cece0d8a 100644 --- a/x-pack/plugins/observability_onboarding/server/routes/logs/route.ts +++ b/x-pack/plugins/observability_onboarding/server/routes/logs/route.ts @@ -40,7 +40,7 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({ scriptDownloadUrl: string; elasticAgentVersion: string; }> { - const { core, plugins, kibanaVersion } = resources; + const { core, plugins } = resources; const coreStart = await core.start(); const kibanaUrl = @@ -53,7 +53,7 @@ const installShipperSetupRoute = createObservabilityOnboardingServerRoute({ return { apiEndpoint, scriptDownloadUrl, - elasticAgentVersion: kibanaVersion, + elasticAgentVersion: '8.9.1', }; }, }); diff --git a/x-pack/plugins/osquery/common/api/model/schema/common_attributes.schema.yaml b/x-pack/plugins/osquery/common/api/model/schema/common_attributes.schema.yaml index f0408cad9929a..ba236b8601e7d 100644 --- a/x-pack/plugins/osquery/common/api/model/schema/common_attributes.schema.yaml +++ b/x-pack/plugins/osquery/common/api/model/schema/common_attributes.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Common Osquery Attributes - version: '2023-10-31 + version: '2023-10-31' paths: { } components: schemas: diff --git a/x-pack/plugins/osquery/common/api/packs/create_pack.schema.yaml b/x-pack/plugins/osquery/common/api/packs/create_pack.schema.yaml index 5176992407877..da04d037b1d56 100644 --- a/x-pack/plugins/osquery/common/api/packs/create_pack.schema.yaml +++ b/x-pack/plugins/osquery/common/api/packs/create_pack.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Create Pack Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: schemas: diff --git a/x-pack/plugins/osquery/common/api/packs/delete_packs.schema.yaml b/x-pack/plugins/osquery/common/api/packs/delete_packs.schema.yaml index e84a2672e5be0..3286aa0b1bb7a 100644 --- a/x-pack/plugins/osquery/common/api/packs/delete_packs.schema.yaml +++ b/x-pack/plugins/osquery/common/api/packs/delete_packs.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Delete Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/packs/find_packs.schema.yaml b/x-pack/plugins/osquery/common/api/packs/find_packs.schema.yaml index ead543e842703..4cd1c222bc6d2 100644 --- a/x-pack/plugins/osquery/common/api/packs/find_packs.schema.yaml +++ b/x-pack/plugins/osquery/common/api/packs/find_packs.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Find Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/packs/packs.schema.yaml b/x-pack/plugins/osquery/common/api/packs/packs.schema.yaml index d35d849497dcc..64e0ed0e4ffe3 100644 --- a/x-pack/plugins/osquery/common/api/packs/packs.schema.yaml +++ b/x-pack/plugins/osquery/common/api/packs/packs.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Packs Schema - version: '2023-10-31 + version: '2023-10-31' paths: /api/osquery/packs: get: diff --git a/x-pack/plugins/osquery/common/api/packs/read_packs.schema.yaml b/x-pack/plugins/osquery/common/api/packs/read_packs.schema.yaml index 4929cc3e61848..8cfe415848c92 100644 --- a/x-pack/plugins/osquery/common/api/packs/read_packs.schema.yaml +++ b/x-pack/plugins/osquery/common/api/packs/read_packs.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Read Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/packs/update_packs.schema.yaml b/x-pack/plugins/osquery/common/api/packs/update_packs.schema.yaml index 7632f21f2cb69..344cb88fad7d4 100644 --- a/x-pack/plugins/osquery/common/api/packs/update_packs.schema.yaml +++ b/x-pack/plugins/osquery/common/api/packs/update_packs.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Update Saved Query Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/saved_query/create_saved_query.schema.yaml b/x-pack/plugins/osquery/common/api/saved_query/create_saved_query.schema.yaml index 6fd278383e680..9735b0139754e 100644 --- a/x-pack/plugins/osquery/common/api/saved_query/create_saved_query.schema.yaml +++ b/x-pack/plugins/osquery/common/api/saved_query/create_saved_query.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Create Saved Query Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: schemas: diff --git a/x-pack/plugins/osquery/common/api/saved_query/delete_saved_query.schema.yaml b/x-pack/plugins/osquery/common/api/saved_query/delete_saved_query.schema.yaml index 39cb1b8ef71f5..7a180c542aa23 100644 --- a/x-pack/plugins/osquery/common/api/saved_query/delete_saved_query.schema.yaml +++ b/x-pack/plugins/osquery/common/api/saved_query/delete_saved_query.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Delete Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/saved_query/find_saved_query.schema.yaml b/x-pack/plugins/osquery/common/api/saved_query/find_saved_query.schema.yaml index 3b1300825ee12..dbebf003a4696 100644 --- a/x-pack/plugins/osquery/common/api/saved_query/find_saved_query.schema.yaml +++ b/x-pack/plugins/osquery/common/api/saved_query/find_saved_query.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Find Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/saved_query/read_saved_query.schema.yaml b/x-pack/plugins/osquery/common/api/saved_query/read_saved_query.schema.yaml index cac351670b65f..a5fed00a37e0c 100644 --- a/x-pack/plugins/osquery/common/api/saved_query/read_saved_query.schema.yaml +++ b/x-pack/plugins/osquery/common/api/saved_query/read_saved_query.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Read Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/common/api/saved_query/saved_query.schema.yaml b/x-pack/plugins/osquery/common/api/saved_query/saved_query.schema.yaml index 8a846cf874a55..1cd832370c0cd 100644 --- a/x-pack/plugins/osquery/common/api/saved_query/saved_query.schema.yaml +++ b/x-pack/plugins/osquery/common/api/saved_query/saved_query.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Saved Queries Schema - version: '2023-10-31 + version: '2023-10-31' paths: /api/osquery/saved_queries: get: diff --git a/x-pack/plugins/osquery/common/api/saved_query/update_saved_query.schema.yaml b/x-pack/plugins/osquery/common/api/saved_query/update_saved_query.schema.yaml index 3f87f3fa14d66..c7004a72adee2 100644 --- a/x-pack/plugins/osquery/common/api/saved_query/update_saved_query.schema.yaml +++ b/x-pack/plugins/osquery/common/api/saved_query/update_saved_query.schema.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: Update Saved Query Schema - version: '2023-10-31 + version: '2023-10-31' paths: { } components: parameters: diff --git a/x-pack/plugins/osquery/cypress/e2e/all/add_integration.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/add_integration.cy.ts index 4011d2db427a2..a84cdb5013047 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/add_integration.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/add_integration.cy.ts @@ -111,6 +111,7 @@ describe('ALL - Add Integration', { tags: ['@ess', '@brokenInServerless'] }, () cy.getBySel('createAgentPolicyFlyoutBtn').click(); cy.getBySel('agentPolicyNameLink').contains(policyName).click(); cy.getBySel('addPackagePolicyButton').click(); + cy.getBySel('epmList.searchBar').type('osquery'); cy.getBySel('integration-card:epr:osquery_manager').click(); cy.getBySel('addIntegrationPolicyButton').click(); cy.getBySel('agentPolicySelect').within(() => { diff --git a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts index 96cf4a285ccc7..15fe843139174 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts @@ -55,6 +55,7 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => { cy.visit(FLEET_AGENT_POLICIES); cy.contains(AGENT_POLICY_NAME).click(); cy.contains('Add integration').click(); + cy.getBySel('epmList.searchBar').type('osquery'); cy.contains(integration).click(); addIntegration(AGENT_POLICY_NAME); cy.contains('Add Elastic Agent later').click(); @@ -221,6 +222,7 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => { cy.contains(`Agent policy '${agentPolicy}' created`).click(); cy.contains(agentPolicy).click(); cy.contains('Add integration').click(); + cy.getBySel('epmList.searchBar').type('osquery'); cy.contains(integration).click(); addIntegration(agentPolicy); cy.contains('Add Elastic Agent later').click(); diff --git a/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts b/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts index a6217f7c916fa..d60c7bae8d9b3 100644 --- a/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts +++ b/x-pack/plugins/osquery/server/handlers/action/create_action_handler.ts @@ -7,8 +7,7 @@ import { v4 as uuidv4 } from 'uuid'; import moment from 'moment'; -import { filter, flatten, isEmpty, map, omit, pick, pickBy, some } from 'lodash'; -import { AGENT_ACTIONS_INDEX } from '@kbn/fleet-plugin/common'; +import { filter, isEmpty, map, omit, pick, pickBy, some } from 'lodash'; import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import type { CreateLiveQueryRequestBodySchema } from '../../../common/api'; @@ -44,6 +43,7 @@ export const createActionHandler = async ( const internalSavedObjectsClient = await getInternalSavedObjectsClient( osqueryContext.getStartServices ); + const { soClient, metadata, alertData, error } = options; const savedObjectsClient = soClient ?? coreStartServices.savedObjects.createInternalRepository(); @@ -85,7 +85,7 @@ export const createActionHandler = async ( pack_id: params.pack_id, pack_name: packSO?.attributes?.name, pack_prebuilt: params.pack_id - ? !!some(packSO?.references, ['type', 'osquery-pack-asset']) + ? some(packSO?.references, ['type', 'osquery-pack-asset']) : undefined, queries: packSO ? map(convertSOQueriesToPack(packSO.attributes.queries), (packQuery, packQueryId) => { @@ -131,12 +131,7 @@ export const createActionHandler = async ( : []; if (fleetActions.length) { - await esClientInternal.bulk({ - refresh: 'wait_for', - body: flatten( - fleetActions.map((action) => [{ index: { _index: AGENT_ACTIONS_INDEX } }, action]) - ), - }); + await osqueryContext.service.getFleetActionsClient()?.bulkCreate(fleetActions); } const actionsComponentTemplateExists = await esClientInternal.indices.exists({ @@ -146,7 +141,7 @@ export const createActionHandler = async ( if (actionsComponentTemplateExists) { await esClientInternal.bulk({ refresh: 'wait_for', - body: [{ index: { _index: `${ACTIONS_INDEX}-default` } }, osqueryAction], + operations: [{ index: { _index: `${ACTIONS_INDEX}-default` } }, osqueryAction], }); } diff --git a/x-pack/plugins/osquery/server/lib/osquery_app_context_services.ts b/x-pack/plugins/osquery/server/lib/osquery_app_context_services.ts index 25d668c16d93a..779715ea48aea 100644 --- a/x-pack/plugins/osquery/server/lib/osquery_app_context_services.ts +++ b/x-pack/plugins/osquery/server/lib/osquery_app_context_services.ts @@ -16,13 +16,18 @@ import type { } from '@kbn/fleet-plugin/server'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; import type { LicensingPluginSetup } from '@kbn/licensing-plugin/server'; +import type { FleetActionsClientInterface } from '@kbn/fleet-plugin/server/services/actions'; import type { ConfigType } from '../../common/config'; import type { TelemetryEventsSender } from './telemetry/sender'; export type OsqueryAppContextServiceStartContract = Partial< Pick< FleetStartContract, - 'agentService' | 'packageService' | 'packagePolicyService' | 'agentPolicyService' + | 'agentService' + | 'packageService' + | 'packagePolicyService' + | 'agentPolicyService' + | 'createFleetActionsClient' > > & { logger: Logger; @@ -41,6 +46,7 @@ export class OsqueryAppContextService { private packagePolicyService: PackagePolicyClient | undefined; private agentPolicyService: AgentPolicyServiceInterface | undefined; private ruleRegistryService: RuleRegistryPluginStartContract | undefined; + private fleetActionsClient: FleetActionsClientInterface | undefined; public start(dependencies: OsqueryAppContextServiceStartContract) { this.agentService = dependencies.agentService; @@ -48,6 +54,7 @@ export class OsqueryAppContextService { this.packagePolicyService = dependencies.packagePolicyService; this.agentPolicyService = dependencies.agentPolicyService; this.ruleRegistryService = dependencies.ruleRegistryService; + this.fleetActionsClient = dependencies.createFleetActionsClient?.('osquery'); } // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -72,6 +79,10 @@ export class OsqueryAppContextService { public getRuleRegistryService(): RuleRegistryPluginStartContract | undefined { return this.ruleRegistryService; } + + public getFleetActionsClient(): FleetActionsClientInterface | undefined { + return this.fleetActionsClient; + } } /** diff --git a/x-pack/plugins/profiling/common/base64.ts b/x-pack/plugins/profiling/common/base64.ts deleted file mode 100644 index 0d724c142271a..0000000000000 --- a/x-pack/plugins/profiling/common/base64.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const safeBase64Decoder = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, - 0, 0, 0, 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, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0, -]; - -export const safeBase64Encoder = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234456789-_'; - -/* eslint no-bitwise: ["error", { "allow": ["&"] }] */ -export function charCodeAt(input: string, i: number): number { - return safeBase64Decoder[input.charCodeAt(i) & 0x7f]; -} diff --git a/x-pack/plugins/profiling/common/columnar_view_model.test.ts b/x-pack/plugins/profiling/common/columnar_view_model.test.ts index c43a1aa86ba63..d967650c76c7f 100644 --- a/x-pack/plugins/profiling/common/columnar_view_model.test.ts +++ b/x-pack/plugins/profiling/common/columnar_view_model.test.ts @@ -7,12 +7,14 @@ import { sum } from 'lodash'; -import { createCalleeTree } from './callee'; +import { createCalleeTree } from '@kbn/profiling-data-access-plugin/common/callee'; import { createColumnarViewModel } from './columnar_view_model'; -import { createBaseFlameGraph, createFlameGraph } from './flamegraph'; -import { decodeStackTraceResponse } from './stack_traces'; - -import { stackTraceFixtures } from './__fixtures__/stacktraces'; +import { + createBaseFlameGraph, + createFlameGraph, +} from '@kbn/profiling-data-access-plugin/common/flamegraph'; +import { decodeStackTraceResponse } from '@kbn/profiling-data-access-plugin/common/stack_traces'; +import { stackTraceFixtures } from '@kbn/profiling-data-access-plugin/common/__fixtures__/stacktraces'; describe('Columnar view model operations', () => { stackTraceFixtures.forEach(({ response, seconds, upsampledBy }) => { diff --git a/x-pack/plugins/profiling/common/columnar_view_model.ts b/x-pack/plugins/profiling/common/columnar_view_model.ts index 20bf2b2761855..e4d2386a0bd74 100644 --- a/x-pack/plugins/profiling/common/columnar_view_model.ts +++ b/x-pack/plugins/profiling/common/columnar_view_model.ts @@ -6,8 +6,7 @@ */ import { ColumnarViewModel } from '@elastic/charts'; - -import { ElasticFlameGraph } from './flamegraph'; +import { ElasticFlameGraph } from '@kbn/profiling-data-access-plugin/common/flamegraph'; import { frameTypeToRGB, rgbToRGBA } from './frame_type_colors'; function normalize(n: number, lower: number, upper: number): number { diff --git a/x-pack/plugins/profiling/common/frame_type_colors.ts b/x-pack/plugins/profiling/common/frame_type_colors.ts index 11c8cbaca9f30..59e8a6004c4e6 100644 --- a/x-pack/plugins/profiling/common/frame_type_colors.ts +++ b/x-pack/plugins/profiling/common/frame_type_colors.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FrameType } from './profiling'; +import { FrameType } from '@kbn/profiling-data-access-plugin/common/profiling'; /* * Helper to calculate the color of a given block to be drawn. The desirable outcomes of this are: diff --git a/x-pack/plugins/profiling/common/functions.test.ts b/x-pack/plugins/profiling/common/functions.test.ts index 1ba31d397a338..4c70cca80d7ba 100644 --- a/x-pack/plugins/profiling/common/functions.test.ts +++ b/x-pack/plugins/profiling/common/functions.test.ts @@ -6,11 +6,9 @@ */ import { sum } from 'lodash'; - import { createTopNFunctions } from './functions'; -import { decodeStackTraceResponse } from './stack_traces'; - -import { stackTraceFixtures } from './__fixtures__/stacktraces'; +import { decodeStackTraceResponse } from '@kbn/profiling-data-access-plugin/common/stack_traces'; +import { stackTraceFixtures } from '@kbn/profiling-data-access-plugin/common/__fixtures__/stacktraces'; describe('TopN function operations', () => { stackTraceFixtures.forEach(({ response, seconds, upsampledBy }) => { diff --git a/x-pack/plugins/profiling/common/functions.ts b/x-pack/plugins/profiling/common/functions.ts index 304c56b81e906..dac08c97abbf7 100644 --- a/x-pack/plugins/profiling/common/functions.ts +++ b/x-pack/plugins/profiling/common/functions.ts @@ -6,7 +6,10 @@ */ import * as t from 'io-ts'; import { sumBy } from 'lodash'; -import { createFrameGroupID, FrameGroupID } from './frame_group'; +import { + createFrameGroupID, + FrameGroupID, +} from '@kbn/profiling-data-access-plugin/common/frame_group'; import { createStackFrameMetadata, emptyExecutable, @@ -19,7 +22,7 @@ import { StackFrameMetadata, StackTrace, StackTraceID, -} from './profiling'; +} from '@kbn/profiling-data-access-plugin/common/profiling'; interface TopNFunctionAndFrameGroup { Frame: StackFrameMetadata; diff --git a/x-pack/plugins/profiling/common/index.ts b/x-pack/plugins/profiling/common/index.ts index 2713ed3f98a13..f6266b606ee5a 100644 --- a/x-pack/plugins/profiling/common/index.ts +++ b/x-pack/plugins/profiling/common/index.ts @@ -41,18 +41,6 @@ export function timeRangeFromRequest(request: any): [number, number] { return [timeFrom, timeTo]; } -// Converts from a Map object to a Record object since Map objects are not -// serializable to JSON by default -export function fromMapToRecord(m: Map): Record { - const output: Record = {}; - - for (const [key, value] of m) { - output[key] = value; - } - - return output; -} - export const NOT_AVAILABLE_LABEL = i18n.translate('xpack.profiling.notAvailableLabel', { defaultMessage: 'N/A', }); diff --git a/x-pack/plugins/profiling/common/run_length_encoding.test.ts b/x-pack/plugins/profiling/common/run_length_encoding.test.ts deleted file mode 100644 index 4831177075fc2..0000000000000 --- a/x-pack/plugins/profiling/common/run_length_encoding.test.ts +++ /dev/null @@ -1,170 +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 { runLengthDecode, runLengthDecodeBase64Url, runLengthEncode } from './run_length_encoding'; - -describe('Run-length encoding operations', () => { - test('run length is fully reversible', () => { - const tests: number[][] = [[], [0], [0, 1, 2, 3], [0, 1, 1, 2, 2, 2, 3, 3, 3, 3]]; - - for (const t of tests) { - expect(runLengthDecode(runLengthEncode(t))).toEqual(t); - } - }); - - test('runLengthDecode with optional parameter', () => { - const tests: Array<{ - bytes: Buffer; - expected: number[]; - }> = [ - { - bytes: Buffer.from([0x5, 0x0, 0x2, 0x2]), - expected: [0, 0, 0, 0, 0, 2, 2], - }, - { - bytes: Buffer.from([0x1, 0x8]), - expected: [8], - }, - ]; - - for (const t of tests) { - expect(runLengthDecode(t.bytes, t.expected.length)).toEqual(t.expected); - } - }); - - test('runLengthDecode with larger output than available input', () => { - const bytes = Buffer.from([0x5, 0x0, 0x2, 0x2]); - const decoded = [0, 0, 0, 0, 0, 2, 2]; - const expected = decoded.concat(Array(decoded.length).fill(0)); - - expect(runLengthDecode(bytes, expected.length)).toEqual(expected); - }); - - test('runLengthDecode without optional parameter', () => { - const tests: Array<{ - bytes: Buffer; - expected: number[]; - }> = [ - { - bytes: Buffer.from([0x5, 0x0, 0x2, 0x2]), - expected: [0, 0, 0, 0, 0, 2, 2], - }, - { - bytes: Buffer.from([0x1, 0x8]), - expected: [8], - }, - ]; - - for (const t of tests) { - expect(runLengthDecode(t.bytes)).toEqual(t.expected); - } - }); - - test('runLengthDecode works for very long runs', () => { - const tests: Array<{ - bytes: Buffer; - expected: number[]; - }> = [ - { - bytes: Buffer.from([0x5, 0x2, 0xff, 0x0]), - expected: [2, 2, 2, 2, 2].concat(Array(255).fill(0)), - }, - { - bytes: Buffer.from([0xff, 0x2, 0x1, 0x2]), - expected: Array(256).fill(2), - }, - ]; - - for (const t of tests) { - expect(runLengthDecode(t.bytes)).toEqual(t.expected); - } - }); - - test('runLengthEncode works for very long runs', () => { - const tests: Array<{ - numbers: number[]; - expected: Buffer; - }> = [ - { - numbers: [2, 2, 2, 2, 2].concat(Array(255).fill(0)), - expected: Buffer.from([0x5, 0x2, 0xff, 0x0]), - }, - { - numbers: Array(256).fill(2), - expected: Buffer.from([0xff, 0x2, 0x1, 0x2]), - }, - ]; - - for (const t of tests) { - expect(runLengthEncode(t.numbers)).toEqual(t.expected); - } - }); - - test('runLengthDecodeBase64Url', () => { - const tests: Array<{ - data: string; - expected: number[]; - }> = [ - { - data: 'CQM', - expected: [3, 3, 3, 3, 3, 3, 3, 3, 3], - }, - { - data: 'AQkBCAEHAQYBBQEEAQMBAgEBAQA', - expected: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0], - }, - { - data: 'EgMHBA', - expected: Array(18).fill(3).concat(Array(7).fill(4)), - }, - { - data: 'CAMfBQIDEAQ', - expected: Array(8) - .fill(3) - .concat(Array(31).fill(5)) - .concat([3, 3]) - .concat(Array(16).fill(4)), - }, - ]; - - for (const t of tests) { - expect(runLengthDecodeBase64Url(t.data, t.data.length, t.expected.length)).toEqual( - t.expected - ); - } - }); - - test('runLengthDecodeBase64Url with larger output than available input', () => { - const data = Buffer.from([0x5, 0x0, 0x3, 0x2]).toString('base64url'); - const decoded = [0, 0, 0, 0, 0, 2, 2, 2]; - const expected = decoded.concat(Array(decoded.length).fill(0)); - - expect(runLengthDecodeBase64Url(data, data.length, expected.length)).toEqual(expected); - }); - - test('runLengthDecodeBase64Url works for very long runs', () => { - const tests: Array<{ - data: string; - expected: number[]; - }> = [ - { - data: Buffer.from([0x5, 0x2, 0xff, 0x0]).toString('base64url'), - expected: [2, 2, 2, 2, 2].concat(Array(255).fill(0)), - }, - { - data: Buffer.from([0xff, 0x2, 0x1, 0x2]).toString('base64url'), - expected: Array(256).fill(2), - }, - ]; - - for (const t of tests) { - expect(runLengthDecodeBase64Url(t.data, t.data.length, t.expected.length)).toEqual( - t.expected - ); - } - }); -}); diff --git a/x-pack/plugins/profiling/common/run_length_encoding.ts b/x-pack/plugins/profiling/common/run_length_encoding.ts deleted file mode 100644 index 813c46eb09d91..0000000000000 --- a/x-pack/plugins/profiling/common/run_length_encoding.ts +++ /dev/null @@ -1,199 +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 { charCodeAt } from './base64'; - -// runLengthEncode run-length encodes the input array. -// -// The input is a list of uint8s. The output is a binary stream of -// 2-byte pairs (first byte is the length and the second byte is the -// binary representation of the object) in reverse order. -// -// E.g. uint8 array [0, 0, 0, 0, 0, 2, 2, 2] is converted into the byte -// array [5, 0, 3, 2]. -export function runLengthEncode(input: number[]): Buffer { - const output: number[] = []; - - if (input.length === 0) { - return Buffer.from(output); - } - - let count = 1; - let current = input[0]; - - for (let i = 1; i < input.length; i++) { - const next = input[i]; - - if (next === current && count < 255) { - count++; - continue; - } - - output.push(count, current); - - count = 1; - current = next; - } - - output.push(count, current); - - return Buffer.from(output); -} - -function copyNumber(target: number[], value: number, offset: number, end: number) { - for (let i = offset; i < end; i++) { - target[i] = value; - } -} - -// runLengthDecode decodes a run-length encoding for the input array. -// -// The input is a binary stream of 2-byte pairs (first byte is the length and the -// second byte is the binary representation of the object). The output is a list of -// uint8s. -// -// E.g. byte array [5, 0, 3, 2] is converted into an uint8 array like -// [0, 0, 0, 0, 0, 2, 2, 2]. -export function runLengthDecode(input: Buffer, outputSize?: number): number[] { - let size; - - if (typeof outputSize === 'undefined') { - size = 0; - for (let i = 0; i < input.length; i += 2) { - size += input[i]; - } - } else { - size = outputSize; - } - - const output: number[] = new Array(size); - - let idx = 0; - for (let i = 0; i < input.length; i += 2) { - for (let j = 0; j < input[i]; j++) { - output[idx] = input[i + 1]; - idx++; - } - } - - // Due to truncation of the frame types for stacktraces longer than 255, - // the expected output size and the actual decoded size can be different. - // Ordinarily, these two values should be the same. - // - // We have decided to fill in the remainder of the output array with zeroes - // as a reasonable default. Without this step, the output array would have - // undefined values. - copyNumber(output, 0, idx, size); - - return output; -} - -// runLengthDecodeBase64Url decodes a run-length encoding for the -// base64-encoded input string. -// -// The input is a base64-encoded string. The output is a list of uint8s. -// -// E.g. string 'BQADAg' is converted into an uint8 array like -// [0, 0, 0, 0, 0, 2, 2, 2]. -// -// The motivating intent for this method is to unpack a base64-encoded -// run-length encoding without using intermediate storage. -// -// This method relies on these assumptions and details: -// - array encoded using run-length and base64 always returns string of length -// 0, 3, or 6 (mod 8) -// - since original array is composed of uint8s, we ignore Unicode codepoints -// - JavaScript bitwise operators operate on 32-bits so decoding must be done -// in 32-bit chunks - -/* eslint no-bitwise: ["error", { "allow": ["<<", ">>", ">>=", "&", "|"] }] */ -export function runLengthDecodeBase64Url(input: string, size: number, capacity: number): number[] { - const output = new Array(capacity); - const multipleOf8 = Math.floor(size / 8); - const remainder = size % 8; - - let n = 0; - let count = 0; - let value = 0; - let i = 0; - let j = 0; - - for (i = 0; i < multipleOf8 * 8; i += 8) { - n = - (charCodeAt(input, i) << 26) | - (charCodeAt(input, i + 1) << 20) | - (charCodeAt(input, i + 2) << 14) | - (charCodeAt(input, i + 3) << 8) | - (charCodeAt(input, i + 4) << 2) | - (charCodeAt(input, i + 5) >> 4); - - count = (n >> 24) & 0xff; - value = (n >> 16) & 0xff; - - copyNumber(output, value, j, j + count); - j += count; - - count = (n >> 8) & 0xff; - value = n & 0xff; - - copyNumber(output, value, j, j + count); - j += count; - - n = - ((charCodeAt(input, i + 5) & 0xf) << 12) | - (charCodeAt(input, i + 6) << 6) | - charCodeAt(input, i + 7); - - count = (n >> 8) & 0xff; - value = n & 0xff; - - copyNumber(output, value, j, j + count); - j += count; - } - - if (remainder === 6) { - n = - (charCodeAt(input, i) << 26) | - (charCodeAt(input, i + 1) << 20) | - (charCodeAt(input, i + 2) << 14) | - (charCodeAt(input, i + 3) << 8) | - (charCodeAt(input, i + 4) << 2) | - (charCodeAt(input, i + 5) >> 4); - - count = (n >> 24) & 0xff; - value = (n >> 16) & 0xff; - - copyNumber(output, value, j, j + count); - j += count; - - count = (n >> 8) & 0xff; - value = n & 0xff; - - copyNumber(output, value, j, j + count); - j += count; - } else if (remainder === 3) { - n = (charCodeAt(input, i) << 12) | (charCodeAt(input, i + 1) << 6) | charCodeAt(input, i + 2); - n >>= 2; - - count = (n >> 8) & 0xff; - value = n & 0xff; - - copyNumber(output, value, j, j + count); - j += count; - } - - // Due to truncation of the frame types for stacktraces longer than 255, - // the expected output size and the actual decoded size can be different. - // Ordinarily, these two values should be the same. - // - // We have decided to fill in the remainder of the output array with zeroes - // as a reasonable default. Without this step, the output array would have - // undefined values. - copyNumber(output, 0, j, capacity); - - return output; -} diff --git a/x-pack/plugins/profiling/common/topn.ts b/x-pack/plugins/profiling/common/topn.ts index 41d820729b48f..cd58e35c6442f 100644 --- a/x-pack/plugins/profiling/common/topn.ts +++ b/x-pack/plugins/profiling/common/topn.ts @@ -9,9 +9,9 @@ import { euiPaletteColorBlind } from '@elastic/eui'; import { InferSearchResponseOf } from '@kbn/es-types'; import { i18n } from '@kbn/i18n'; import { orderBy } from 'lodash'; -import { ProfilingESField } from './elasticsearch'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; +import { StackFrameMetadata } from '@kbn/profiling-data-access-plugin/common/profiling'; import { createUniformBucketsForTimeRange } from './histogram'; -import { StackFrameMetadata } from './profiling'; export const OTHER_BUCKET_LABEL = i18n.translate('xpack.profiling.topn.otherBucketLabel', { defaultMessage: 'Other', diff --git a/x-pack/plugins/profiling/kibana.jsonc b/x-pack/plugins/profiling/kibana.jsonc index 2985456d4ec8b..612e8d7936c25 100644 --- a/x-pack/plugins/profiling/kibana.jsonc +++ b/x-pack/plugins/profiling/kibana.jsonc @@ -23,12 +23,13 @@ "observabilityShared", "observabilityAIAssistant", "unifiedSearch", - "share" + "share", + "profilingDataAccess" ], "requiredBundles": [ "kibanaReact", "kibanaUtils", - "observabilityAIAssistant", + "observabilityAIAssistant" ] } } diff --git a/x-pack/plugins/profiling/public/components/flamegraph/index.tsx b/x-pack/plugins/profiling/public/components/flamegraph/index.tsx index 5f4bc8cfab9cc..7d02f4b480350 100644 --- a/x-pack/plugins/profiling/public/components/flamegraph/index.tsx +++ b/x-pack/plugins/profiling/public/components/flamegraph/index.tsx @@ -19,7 +19,7 @@ import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; import { Maybe } from '@kbn/observability-plugin/common/typings'; import React, { useEffect, useMemo, useState } from 'react'; import { useUiTracker } from '@kbn/observability-shared-plugin/public'; -import { ElasticFlameGraph } from '../../../common/flamegraph'; +import { ElasticFlameGraph } from '@kbn/profiling-data-access-plugin/common/flamegraph'; import { getFlamegraphModel } from '../../utils/get_flamegraph_model'; import { FlameGraphLegend } from './flame_graph_legend'; import { FrameInformationWindow } from '../frame_information_window'; diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/get_information_rows.ts b/x-pack/plugins/profiling/public/components/frame_information_window/get_information_rows.ts index 057f56f9c2f06..8c2fa0ebd0763 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/get_information_rows.ts +++ b/x-pack/plugins/profiling/public/components/frame_information_window/get_information_rows.ts @@ -6,8 +6,8 @@ */ import { i18n } from '@kbn/i18n'; +import { describeFrameType } from '@kbn/profiling-data-access-plugin/common/profiling'; import { NOT_AVAILABLE_LABEL } from '../../../common'; -import { describeFrameType } from '../../../common/profiling'; export function getInformationRows({ fileID, diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx index d0925897877fc..96879a59fc737 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/index.tsx @@ -13,7 +13,10 @@ import { useObservabilityAIAssistant, } from '@kbn/observability-ai-assistant-plugin/public'; import React, { useMemo } from 'react'; -import { FrameSymbolStatus, getFrameSymbolStatus } from '../../../common/profiling'; +import { + FrameSymbolStatus, + getFrameSymbolStatus, +} from '@kbn/profiling-data-access-plugin/common/profiling'; import { FrameInformationPanel } from './frame_information_panel'; import { getImpactRows } from './get_impact_rows'; import { getInformationRows } from './get_information_rows'; diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx index ba353d48c6995..aba91dcc4127a 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.stories.tsx @@ -8,7 +8,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Meta } from '@storybook/react'; import React from 'react'; -import { FrameType } from '../../../common/profiling'; +import { FrameType } from '@kbn/profiling-data-access-plugin/common/profiling'; import { MockProfilingDependenciesStorybook } from '../contexts/profiling_dependencies/mock_profiling_dependencies_storybook'; import { MissingSymbolsCallout } from './missing_symbols_callout'; diff --git a/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx index ff86ba5628c27..1f9d40d23a648 100644 --- a/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx +++ b/x-pack/plugins/profiling/public/components/frame_information_window/missing_symbols_callout.tsx @@ -9,7 +9,7 @@ import { EuiButton, EuiCallOut, EuiLink } from '@elastic/eui'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; -import { FrameType, getLanguageType } from '../../../common/profiling'; +import { FrameType, getLanguageType } from '@kbn/profiling-data-access-plugin/common/profiling'; import { PROFILING_FEEDBACK_LINK } from '../profiling_app_page_template'; import { useProfilingDependencies } from '../contexts/profiling_dependencies/use_profiling_dependencies'; import { useProfilingRouter } from '../../hooks/use_profiling_router'; diff --git a/x-pack/plugins/profiling/public/components/stack_frame_summary/index.tsx b/x-pack/plugins/profiling/public/components/stack_frame_summary/index.tsx index a92934df79009..5533df8479d4e 100644 --- a/x-pack/plugins/profiling/public/components/stack_frame_summary/index.tsx +++ b/x-pack/plugins/profiling/public/components/stack_frame_summary/index.tsx @@ -6,7 +6,11 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiText } from '@elastic/eui'; import React from 'react'; -import { getCalleeFunction, getCalleeSource, StackFrameMetadata } from '../../../common/profiling'; +import { + getCalleeFunction, + getCalleeSource, + StackFrameMetadata, +} from '@kbn/profiling-data-access-plugin/common/profiling'; interface Props { frame: StackFrameMetadata; diff --git a/x-pack/plugins/profiling/public/components/subchart.tsx b/x-pack/plugins/profiling/public/components/subchart.tsx index 72c869e85c3a3..ee388b851d0ed 100644 --- a/x-pack/plugins/profiling/public/components/subchart.tsx +++ b/x-pack/plugins/profiling/public/components/subchart.tsx @@ -32,7 +32,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { StackFrameMetadata } from '../../common/profiling'; +import { StackFrameMetadata } from '@kbn/profiling-data-access-plugin/common/profiling'; import { CountPerTime, OTHER_BUCKET_LABEL, TopNSample } from '../../common/topn'; import { useKibanaTimeZoneSetting } from '../hooks/use_kibana_timezone_setting'; import { useProfilingChartsTheme } from '../hooks/use_profiling_charts_theme'; diff --git a/x-pack/plugins/profiling/public/components/topn_functions/utils.ts b/x-pack/plugins/profiling/public/components/topn_functions/utils.ts index f44454d255601..f4524425883d1 100644 --- a/x-pack/plugins/profiling/public/components/topn_functions/utils.ts +++ b/x-pack/plugins/profiling/public/components/topn_functions/utils.ts @@ -5,8 +5,8 @@ * 2.0. */ import { keyBy } from 'lodash'; +import { StackFrameMetadata } from '@kbn/profiling-data-access-plugin/common/profiling'; import { TopNFunctions } from '../../../common/functions'; -import { StackFrameMetadata } from '../../../common/profiling'; import { calculateImpactEstimates } from '../../../common/calculate_impact_estimates'; export function getColorLabel(percent: number) { diff --git a/x-pack/plugins/profiling/public/routing/index.tsx b/x-pack/plugins/profiling/public/routing/index.tsx index 9e08cfbc53fec..b6dcebc3ec18d 100644 --- a/x-pack/plugins/profiling/public/routing/index.tsx +++ b/x-pack/plugins/profiling/public/routing/index.tsx @@ -9,8 +9,11 @@ import { toNumberRt } from '@kbn/io-ts-utils'; import { createRouter, Outlet } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; +import { + StackTracesDisplayOption, + TopNType, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { TopNFunctionSortField, topNFunctionSortFieldRt } from '../../common/functions'; -import { StackTracesDisplayOption, TopNType } from '../../common/stack_traces'; import { indexLifecyclePhaseRt, IndexLifecyclePhaseSelectOption, diff --git a/x-pack/plugins/profiling/public/services.ts b/x-pack/plugins/profiling/public/services.ts index 1a2a684f96e15..6fbe64f57d025 100644 --- a/x-pack/plugins/profiling/public/services.ts +++ b/x-pack/plugins/profiling/public/services.ts @@ -5,8 +5,12 @@ * 2.0. */ import { HttpFetchQuery } from '@kbn/core/public'; +import { + BaseFlameGraph, + createFlameGraph, + ElasticFlameGraph, +} from '@kbn/profiling-data-access-plugin/common/flamegraph'; import { getRoutePaths } from '../common'; -import { BaseFlameGraph, createFlameGraph, ElasticFlameGraph } from '../common/flamegraph'; import { TopNFunctions } from '../common/functions'; import type { IndexLifecyclePhaseSelectOption, diff --git a/x-pack/plugins/profiling/public/utils/get_flamegraph_model/index.ts b/x-pack/plugins/profiling/public/utils/get_flamegraph_model/index.ts index 9e0ec087523ad..6ba179ac44d9c 100644 --- a/x-pack/plugins/profiling/public/utils/get_flamegraph_model/index.ts +++ b/x-pack/plugins/profiling/public/utils/get_flamegraph_model/index.ts @@ -8,10 +8,10 @@ import { ColumnarViewModel } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import d3 from 'd3'; import { compact, range, sum, uniqueId } from 'lodash'; +import { describeFrameType, FrameType } from '@kbn/profiling-data-access-plugin/common/profiling'; +import { ElasticFlameGraph } from '@kbn/profiling-data-access-plugin/common/flamegraph'; import { createColumnarViewModel } from '../../../common/columnar_view_model'; -import { ElasticFlameGraph } from '../../../common/flamegraph'; import { FRAME_TYPE_COLOR_MAP, rgbToRGBA } from '../../../common/frame_type_colors'; -import { describeFrameType, FrameType } from '../../../common/profiling'; import { ComparisonMode } from '../../components/normalization_menu'; import { getInterpolationValue } from './get_interpolation_value'; diff --git a/x-pack/plugins/profiling/public/views/stack_traces_view/get_stack_traces_tabs.ts b/x-pack/plugins/profiling/public/views/stack_traces_view/get_stack_traces_tabs.ts index 3b06074ba9db9..b1a70254348ab 100644 --- a/x-pack/plugins/profiling/public/views/stack_traces_view/get_stack_traces_tabs.ts +++ b/x-pack/plugins/profiling/public/views/stack_traces_view/get_stack_traces_tabs.ts @@ -8,7 +8,7 @@ import { EuiPageHeaderContentProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { TypeOf } from '@kbn/typed-react-router-config'; -import { TopNType } from '../../../common/stack_traces'; +import { TopNType } from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { StatefulProfilingRouter } from '../../hooks/use_profiling_router'; import { ProfilingRoutes } from '../../routing'; diff --git a/x-pack/plugins/profiling/public/views/stack_traces_view/index.tsx b/x-pack/plugins/profiling/public/views/stack_traces_view/index.tsx index 638df8712e115..0df1f9ae855f9 100644 --- a/x-pack/plugins/profiling/public/views/stack_traces_view/index.tsx +++ b/x-pack/plugins/profiling/public/views/stack_traces_view/index.tsx @@ -7,7 +7,10 @@ import { EuiButton, EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { StackTracesDisplayOption, TopNType } from '../../../common/stack_traces'; +import { + StackTracesDisplayOption, + TopNType, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { groupSamplesByCategory, TopNResponse } from '../../../common/topn'; import { useProfilingParams } from '../../hooks/use_profiling_params'; import { useProfilingRouter } from '../../hooks/use_profiling_router'; diff --git a/x-pack/plugins/profiling/public/views/stack_traces_view/utils.test.ts b/x-pack/plugins/profiling/public/views/stack_traces_view/utils.test.ts index 915b24c53429d..71272b7eda63c 100644 --- a/x-pack/plugins/profiling/public/views/stack_traces_view/utils.test.ts +++ b/x-pack/plugins/profiling/public/views/stack_traces_view/utils.test.ts @@ -4,7 +4,10 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { StackTracesDisplayOption, TopNType } from '../../../common/stack_traces'; +import { + StackTracesDisplayOption, + TopNType, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { getTracesViewRouteParams } from './utils'; describe('stack traces view utils', () => { diff --git a/x-pack/plugins/profiling/public/views/stack_traces_view/utils.ts b/x-pack/plugins/profiling/public/views/stack_traces_view/utils.ts index 74e13f249108c..7b6b2a0ead397 100644 --- a/x-pack/plugins/profiling/public/views/stack_traces_view/utils.ts +++ b/x-pack/plugins/profiling/public/views/stack_traces_view/utils.ts @@ -6,7 +6,10 @@ */ import { TypeOf } from '@kbn/typed-react-router-config'; -import { getFieldNameForTopNType, TopNType } from '../../../common/stack_traces'; +import { + getFieldNameForTopNType, + TopNType, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { ProfilingRoutes } from '../../routing'; export function getTracesViewRouteParams({ diff --git a/x-pack/plugins/profiling/public/views/storage_explorer/summary.tsx b/x-pack/plugins/profiling/public/views/storage_explorer/summary.tsx index 051765a8880a6..19a3e95809155 100644 --- a/x-pack/plugins/profiling/public/views/storage_explorer/summary.tsx +++ b/x-pack/plugins/profiling/public/views/storage_explorer/summary.tsx @@ -9,7 +9,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiPanel, EuiStat, EuiText } from ' import { i18n } from '@kbn/i18n'; import { asDynamicBytes } from '@kbn/observability-plugin/common'; import React from 'react'; -import { StackTracesDisplayOption, TopNType } from '../../../common/stack_traces'; +import { + StackTracesDisplayOption, + TopNType, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { StorageExplorerSummaryAPIResponse } from '../../../common/storage_explorer'; import { useProfilingDependencies } from '../../components/contexts/profiling_dependencies/use_profiling_dependencies'; import { LabelWithHint } from '../../components/label_with_hint'; diff --git a/x-pack/plugins/profiling/server/routes/flamechart.ts b/x-pack/plugins/profiling/server/routes/flamechart.ts index 0f78ca0288d81..5dedcc15e0c78 100644 --- a/x-pack/plugins/profiling/server/routes/flamechart.ts +++ b/x-pack/plugins/profiling/server/routes/flamechart.ts @@ -6,21 +6,17 @@ */ import { schema } from '@kbn/config-schema'; - import { RouteRegisterParameters } from '.'; import { getRoutePaths } from '../../common'; -import { createCalleeTree } from '../../common/callee'; import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; -import { createBaseFlameGraph } from '../../common/flamegraph'; -import { withProfilingSpan } from '../utils/with_profiling_span'; import { getClient } from './compat'; -import { createCommonFilter } from './query'; -import { searchStackTraces } from './search_stacktraces'; export function registerFlameChartSearchRoute({ router, logger, - services: { createProfilingEsClient }, + dependencies: { + start: { profilingDataAccess }, + }, }: RouteRegisterParameters) { const paths = getRoutePaths(); router.get( @@ -37,39 +33,15 @@ export function registerFlameChartSearchRoute({ }, async (context, request, response) => { const { timeFrom, timeTo, kuery } = request.query; - const targetSampleSize = 20000; // minimum number of samples to get statistically sound results try { const esClient = await getClient(context); - const profilingElasticsearchClient = createProfilingEsClient({ request, esClient }); - const filter = createCommonFilter({ - timeFrom, - timeTo, + const flamegraph = await profilingDataAccess.services.fetchFlamechartData({ + esClient, + rangeFrom: timeFrom, + rangeTo: timeTo, kuery, }); - const totalSeconds = timeTo - timeFrom; - - const { events, stackTraces, executables, stackFrames, totalFrames, samplingRate } = - await searchStackTraces({ - client: profilingElasticsearchClient, - filter, - sampleSize: targetSampleSize, - }); - - const flamegraph = await withProfilingSpan('create_flamegraph', async () => { - const tree = createCalleeTree( - events, - stackTraces, - stackFrames, - executables, - totalFrames, - samplingRate - ); - - const fg = createBaseFlameGraph(tree, samplingRate, totalSeconds); - - return fg; - }); return response.ok({ body: flamegraph }); } catch (error) { diff --git a/x-pack/plugins/profiling/server/routes/query.ts b/x-pack/plugins/profiling/server/routes/query.ts index f8a776ee68ce7..eed6b272c800e 100644 --- a/x-pack/plugins/profiling/server/routes/query.ts +++ b/x-pack/plugins/profiling/server/routes/query.ts @@ -7,7 +7,7 @@ import { QueryDslBoolQuery } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { kqlQuery } from '@kbn/observability-plugin/server'; -import { ProfilingESField } from '../../common/elasticsearch'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; export interface ProjectTimeQuery { bool: QueryDslBoolQuery; diff --git a/x-pack/plugins/profiling/server/routes/search_stacktraces.ts b/x-pack/plugins/profiling/server/routes/search_stacktraces.ts index b90cbaf78bbe3..1e42cd11265ee 100644 --- a/x-pack/plugins/profiling/server/routes/search_stacktraces.ts +++ b/x-pack/plugins/profiling/server/routes/search_stacktraces.ts @@ -4,8 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { decodeStackTraceResponse } from '../../common/stack_traces'; +import { decodeStackTraceResponse } from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { ProjectTimeQuery } from './query'; diff --git a/x-pack/plugins/profiling/server/routes/stacktrace.test.ts b/x-pack/plugins/profiling/server/routes/stacktrace.test.ts deleted file mode 100644 index 91b55312928c3..0000000000000 --- a/x-pack/plugins/profiling/server/routes/stacktrace.test.ts +++ /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 { createStackFrameID, StackTrace } from '../../common/profiling'; -import { runLengthEncode } from '../../common/run_length_encoding'; -import { decodeStackTrace, EncodedStackTrace } from './stacktrace'; - -enum fileID { - A = 'aQpJmTLWydNvOapSFZOwKg', - B = 'hz_u-HGyrN6qeIk6UIJeCA', - C = 'AJ8qrcXSoJbl_haPhlc4og', - D = 'lHZiv7a58px6Gumcpo-6yA', - E = 'fkbxUTZgljnk71ZMnqJnyA', - F = 'gnEsgxvvEODj6iFYMQWYlA', -} - -enum addressOrLine { - A = 515512, - B = 26278522, - C = 6712518, - D = 105806025, - E = 111, - F = 106182663, - G = 100965370, -} - -const frameID: Record = { - A: createStackFrameID(fileID.A, addressOrLine.A), - B: createStackFrameID(fileID.B, addressOrLine.B), - C: createStackFrameID(fileID.C, addressOrLine.C), - D: createStackFrameID(fileID.D, addressOrLine.D), - E: createStackFrameID(fileID.E, addressOrLine.E), - F: createStackFrameID(fileID.F, addressOrLine.F), - G: createStackFrameID(fileID.F, addressOrLine.G), -}; - -const frameTypeA = [0, 0, 0]; -const frameTypeB = [8, 8, 8, 8]; - -describe('Stack trace operations', () => { - test('decodeStackTrace', () => { - const tests: Array<{ - original: EncodedStackTrace; - expected: StackTrace; - }> = [ - { - original: { - Stacktrace: { - frame: { - ids: frameID.A + frameID.B + frameID.C, - types: runLengthEncode(frameTypeA).toString('base64url'), - }, - }, - } as EncodedStackTrace, - expected: { - FrameIDs: [frameID.A, frameID.B, frameID.C], - FileIDs: [fileID.A, fileID.B, fileID.C], - AddressOrLines: [addressOrLine.A, addressOrLine.B, addressOrLine.C], - Types: frameTypeA, - } as StackTrace, - }, - { - original: { - Stacktrace: { - frame: { - ids: frameID.D + frameID.E + frameID.F + frameID.G, - types: runLengthEncode(frameTypeB).toString('base64url'), - }, - }, - } as EncodedStackTrace, - expected: { - FrameIDs: [frameID.D, frameID.E, frameID.F, frameID.G], - FileIDs: [fileID.D, fileID.E, fileID.F, fileID.F], - AddressOrLines: [addressOrLine.D, addressOrLine.E, addressOrLine.F, addressOrLine.G], - Types: frameTypeB, - } as StackTrace, - }, - ]; - - for (const t of tests) { - expect(decodeStackTrace(t.original)).toEqual(t.expected); - } - }); -}); diff --git a/x-pack/plugins/profiling/server/routes/stacktrace.ts b/x-pack/plugins/profiling/server/routes/stacktrace.ts deleted file mode 100644 index 0777d8c741161..0000000000000 --- a/x-pack/plugins/profiling/server/routes/stacktrace.ts +++ /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 { DedotObject, ProfilingESField } from '../../common/elasticsearch'; -import { - getAddressFromStackFrameID, - getFileIDFromStackFrameID, - StackTrace, -} from '../../common/profiling'; -import { runLengthDecodeBase64Url } from '../../common/run_length_encoding'; - -const BASE64_FRAME_ID_LENGTH = 32; - -export type EncodedStackTrace = DedotObject<{ - // This field is a base64-encoded byte string. The string represents a - // serialized list of frame IDs in which the order of frames are - // reversed to allow for prefix compression (leaf frame last). Each - // frame ID is composed of two concatenated values: a 16-byte file ID - // and an 8-byte address or line number (depending on the context of - // the downstream reader). - // - // Frame ID #1 Frame ID #2 - // +----------------+--------+----------------+--------+---- - // | File ID | Addr | File ID | Addr | - // +----------------+--------+----------------+--------+---- - [ProfilingESField.StacktraceFrameIDs]: string; - - // This field is a run-length encoding of a list of uint8s. The order is - // reversed from the original input. - [ProfilingESField.StacktraceFrameTypes]: string; -}>; - -// decodeStackTrace unpacks an encoded stack trace from Elasticsearch -export function decodeStackTrace(input: EncodedStackTrace): StackTrace { - const inputFrameIDs = input.Stacktrace.frame.ids; - const inputFrameTypes = input.Stacktrace.frame.types; - const countsFrameIDs = inputFrameIDs.length / BASE64_FRAME_ID_LENGTH; - - const fileIDs: string[] = new Array(countsFrameIDs); - const frameIDs: string[] = new Array(countsFrameIDs); - const addressOrLines: number[] = new Array(countsFrameIDs); - - // Step 1: Convert the base64-encoded frameID list into two separate - // lists (frame IDs and file IDs), both of which are also base64-encoded. - // - // To get the frame ID, we grab the next 32 bytes. - // - // To get the file ID, we grab the first 22 bytes of the frame ID. - // However, since the file ID is base64-encoded using 21.33 bytes - // (16 * 4 / 3), then the 22 bytes have an extra 4 bits from the - // address (see diagram in definition of EncodedStackTrace). - for (let i = 0, pos = 0; i < countsFrameIDs; i++, pos += BASE64_FRAME_ID_LENGTH) { - const frameID = inputFrameIDs.slice(pos, pos + BASE64_FRAME_ID_LENGTH); - frameIDs[i] = frameID; - fileIDs[i] = getFileIDFromStackFrameID(frameID); - addressOrLines[i] = getAddressFromStackFrameID(frameID); - } - - // Step 2: Convert the run-length byte encoding into a list of uint8s. - const typeIDs = runLengthDecodeBase64Url(inputFrameTypes, inputFrameTypes.length, countsFrameIDs); - - return { - AddressOrLines: addressOrLines, - FileIDs: fileIDs, - FrameIDs: frameIDs, - Types: typeIDs, - } as StackTrace; -} diff --git a/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_breakdown_size_timeseries.ts b/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_breakdown_size_timeseries.ts index 57ec31e6bcfbd..529887f7f190d 100644 --- a/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_breakdown_size_timeseries.ts +++ b/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_breakdown_size_timeseries.ts @@ -6,7 +6,7 @@ */ import { kqlQuery, termQuery } from '@kbn/observability-plugin/server'; -import { ProfilingESField } from '../../../common/elasticsearch'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; import { computeBucketWidthFromTimeRangeAndBucketCount } from '../../../common/histogram'; import { IndexLifecyclePhaseSelectOption, diff --git a/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_details.ts b/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_details.ts index 65a66071431f1..20f3f080597f5 100644 --- a/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_details.ts +++ b/x-pack/plugins/profiling/server/routes/storage_explorer/get_host_details.ts @@ -6,7 +6,7 @@ */ import { kqlQuery, termQuery } from '@kbn/observability-plugin/server'; -import { ProfilingESField } from '../../../common/elasticsearch'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; import { IndexLifecyclePhaseSelectOption, indexLifeCyclePhaseToDataTier, diff --git a/x-pack/plugins/profiling/server/routes/storage_explorer/get_profiling_hosts_details_by_id.ts b/x-pack/plugins/profiling/server/routes/storage_explorer/get_profiling_hosts_details_by_id.ts index 6e3216dc0fd43..bc3a0dd581903 100644 --- a/x-pack/plugins/profiling/server/routes/storage_explorer/get_profiling_hosts_details_by_id.ts +++ b/x-pack/plugins/profiling/server/routes/storage_explorer/get_profiling_hosts_details_by_id.ts @@ -6,7 +6,7 @@ */ import { kqlQuery } from '@kbn/observability-plugin/server'; import { keyBy } from 'lodash'; -import { ProfilingESField } from '../../../common/elasticsearch'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; import { ProfilingESClient } from '../../utils/create_profiling_es_client'; interface HostDetails { diff --git a/x-pack/plugins/profiling/server/routes/topn.test.ts b/x-pack/plugins/profiling/server/routes/topn.test.ts index 1276c5dcc94dd..ab88c911ce97a 100644 --- a/x-pack/plugins/profiling/server/routes/topn.test.ts +++ b/x-pack/plugins/profiling/server/routes/topn.test.ts @@ -8,7 +8,7 @@ import { AggregationsAggregationContainer } from '@elastic/elasticsearch/lib/api/types'; import { coreMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; -import { ProfilingESField } from '../../common/elasticsearch'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; import { ProfilingESClient } from '../utils/create_profiling_es_client'; import { topNElasticSearchQuery } from './topn'; diff --git a/x-pack/plugins/profiling/server/routes/topn.ts b/x-pack/plugins/profiling/server/routes/topn.ts index ac4621cf0ed14..5e3f1cb16e8be 100644 --- a/x-pack/plugins/profiling/server/routes/topn.ts +++ b/x-pack/plugins/profiling/server/routes/topn.ts @@ -7,12 +7,15 @@ import { schema } from '@kbn/config-schema'; import type { Logger } from '@kbn/core/server'; -import { RouteRegisterParameters } from '.'; +import { ProfilingESField } from '@kbn/profiling-data-access-plugin/common/elasticsearch'; +import { groupStackFrameMetadataByStackTrace } from '@kbn/profiling-data-access-plugin/common/profiling'; +import { + getFieldNameForTopNType, + TopNType, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { getRoutePaths, INDEX_EVENTS } from '../../common'; -import { ProfilingESField } from '../../common/elasticsearch'; +import { RouteRegisterParameters } from '.'; import { computeBucketWidthFromTimeRangeAndBucketCount } from '../../common/histogram'; -import { groupStackFrameMetadataByStackTrace } from '../../common/profiling'; -import { getFieldNameForTopNType, TopNType } from '../../common/stack_traces'; import { createTopNSamples, getTopNAggregationRequest, TopNResponse } from '../../common/topn'; import { handleRouteHandlerError } from '../utils/handle_route_error_handler'; import { ProfilingESClient } from '../utils/create_profiling_es_client'; diff --git a/x-pack/plugins/profiling/server/types.ts b/x-pack/plugins/profiling/server/types.ts index e1542e6939896..6ee94e238effa 100644 --- a/x-pack/plugins/profiling/server/types.ts +++ b/x-pack/plugins/profiling/server/types.ts @@ -12,6 +12,10 @@ import { SpacesPluginStart, SpacesPluginSetup } from '@kbn/spaces-plugin/server' import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server'; import { FleetSetupContract, FleetStartContract } from '@kbn/fleet-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; +import { + ProfilingDataAccessPluginSetup, + ProfilingDataAccessPluginStart, +} from '@kbn/profiling-data-access-plugin/server'; export interface ProfilingPluginSetupDeps { observability: ObservabilityPluginSetup; @@ -20,6 +24,7 @@ export interface ProfilingPluginSetupDeps { fleet: FleetSetupContract; spaces?: SpacesPluginSetup; usageCollection?: UsageCollectionSetup; + profilingDataAccess: ProfilingDataAccessPluginSetup; } export interface ProfilingPluginStartDeps { @@ -28,6 +33,7 @@ export interface ProfilingPluginStartDeps { cloud: CloudStart; fleet: FleetStartContract; spaces?: SpacesPluginStart; + profilingDataAccess: ProfilingDataAccessPluginStart; } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts index 8fa67eb23ecfe..1379fe2a56bf2 100644 --- a/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts +++ b/x-pack/plugins/profiling/server/utils/create_profiling_es_client.ts @@ -10,8 +10,11 @@ import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import type { KibanaRequest } from '@kbn/core/server'; import { unwrapEsResponse } from '@kbn/observability-plugin/server'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { + ProfilingStatusResponse, + StackTraceResponse, +} from '@kbn/profiling-data-access-plugin/common/stack_traces'; import { withProfilingSpan } from './with_profiling_span'; -import { ProfilingStatusResponse, StackTraceResponse } from '../../common/stack_traces'; export function cancelEsRequestOnAbort>( promise: T, diff --git a/x-pack/plugins/profiling/tsconfig.json b/x-pack/plugins/profiling/tsconfig.json index 980249959b215..ff93bada71703 100644 --- a/x-pack/plugins/profiling/tsconfig.json +++ b/x-pack/plugins/profiling/tsconfig.json @@ -47,7 +47,8 @@ "@kbn/licensing-plugin", "@kbn/utility-types", "@kbn/usage-collection-plugin", - "@kbn/observability-ai-assistant-plugin" + "@kbn/observability-ai-assistant-plugin", + "@kbn/profiling-data-access-plugin" // add references to other TypeScript projects the plugin depends on // requiredPlugins from ./kibana.json diff --git a/x-pack/plugins/profiling_data_access/.i18nrc.json b/x-pack/plugins/profiling_data_access/.i18nrc.json new file mode 100644 index 0000000000000..de8ac3249413e --- /dev/null +++ b/x-pack/plugins/profiling_data_access/.i18nrc.json @@ -0,0 +1,7 @@ +{ + "prefix": "profiling", + "paths": { + "profiling": "." + }, + "translations": [] +} diff --git a/x-pack/plugins/profiling/common/__fixtures__/README.md b/x-pack/plugins/profiling_data_access/common/__fixtures__/README.md similarity index 100% rename from x-pack/plugins/profiling/common/__fixtures__/README.md rename to x-pack/plugins/profiling_data_access/common/__fixtures__/README.md diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces.ts b/x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces.ts similarity index 100% rename from x-pack/plugins/profiling/common/__fixtures__/stacktraces.ts rename to x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces.ts diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_3600s_5x.json b/x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_3600s_5x.json similarity index 100% rename from x-pack/plugins/profiling/common/__fixtures__/stacktraces_3600s_5x.json rename to x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_3600s_5x.json diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_604800s_625x.json b/x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_604800s_625x.json similarity index 100% rename from x-pack/plugins/profiling/common/__fixtures__/stacktraces_604800s_625x.json rename to x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_604800s_625x.json diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_60s_1x.json b/x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_60s_1x.json similarity index 100% rename from x-pack/plugins/profiling/common/__fixtures__/stacktraces_60s_1x.json rename to x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_60s_1x.json diff --git a/x-pack/plugins/profiling/common/__fixtures__/stacktraces_86400s_125x.json b/x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_86400s_125x.json similarity index 100% rename from x-pack/plugins/profiling/common/__fixtures__/stacktraces_86400s_125x.json rename to x-pack/plugins/profiling_data_access/common/__fixtures__/stacktraces_86400s_125x.json diff --git a/x-pack/plugins/profiling/common/callee.test.ts b/x-pack/plugins/profiling_data_access/common/callee.test.ts similarity index 100% rename from x-pack/plugins/profiling/common/callee.test.ts rename to x-pack/plugins/profiling_data_access/common/callee.test.ts diff --git a/x-pack/plugins/profiling/common/callee.ts b/x-pack/plugins/profiling_data_access/common/callee.ts similarity index 100% rename from x-pack/plugins/profiling/common/callee.ts rename to x-pack/plugins/profiling_data_access/common/callee.ts diff --git a/x-pack/plugins/profiling/common/elasticsearch.ts b/x-pack/plugins/profiling_data_access/common/elasticsearch.ts similarity index 100% rename from x-pack/plugins/profiling/common/elasticsearch.ts rename to x-pack/plugins/profiling_data_access/common/elasticsearch.ts diff --git a/x-pack/plugins/profiling/common/flamegraph.test.ts b/x-pack/plugins/profiling_data_access/common/flamegraph.test.ts similarity index 100% rename from x-pack/plugins/profiling/common/flamegraph.test.ts rename to x-pack/plugins/profiling_data_access/common/flamegraph.test.ts diff --git a/x-pack/plugins/profiling/common/flamegraph.ts b/x-pack/plugins/profiling_data_access/common/flamegraph.ts similarity index 100% rename from x-pack/plugins/profiling/common/flamegraph.ts rename to x-pack/plugins/profiling_data_access/common/flamegraph.ts diff --git a/x-pack/plugins/profiling/common/frame_group.test.ts b/x-pack/plugins/profiling_data_access/common/frame_group.test.ts similarity index 100% rename from x-pack/plugins/profiling/common/frame_group.test.ts rename to x-pack/plugins/profiling_data_access/common/frame_group.test.ts diff --git a/x-pack/plugins/profiling/common/frame_group.ts b/x-pack/plugins/profiling_data_access/common/frame_group.ts similarity index 100% rename from x-pack/plugins/profiling/common/frame_group.ts rename to x-pack/plugins/profiling_data_access/common/frame_group.ts diff --git a/x-pack/plugins/profiling/common/hash.test.ts b/x-pack/plugins/profiling_data_access/common/hash.test.ts similarity index 100% rename from x-pack/plugins/profiling/common/hash.test.ts rename to x-pack/plugins/profiling_data_access/common/hash.test.ts diff --git a/x-pack/plugins/profiling/common/hash.ts b/x-pack/plugins/profiling_data_access/common/hash.ts similarity index 100% rename from x-pack/plugins/profiling/common/hash.ts rename to x-pack/plugins/profiling_data_access/common/hash.ts diff --git a/x-pack/plugins/profiling/common/profiling.test.ts b/x-pack/plugins/profiling_data_access/common/profiling.test.ts similarity index 90% rename from x-pack/plugins/profiling/common/profiling.test.ts rename to x-pack/plugins/profiling_data_access/common/profiling.test.ts index 5115055ad3c94..24c898bf1cfbe 100644 --- a/x-pack/plugins/profiling/common/profiling.test.ts +++ b/x-pack/plugins/profiling_data_access/common/profiling.test.ts @@ -6,26 +6,15 @@ */ import { - createStackFrameID, createStackFrameMetadata, FrameSymbolStatus, FrameType, - getAddressFromStackFrameID, getCalleeFunction, getCalleeSource, - getFileIDFromStackFrameID, getFrameSymbolStatus, getLanguageType, } from './profiling'; -describe('Stack frame operations', () => { - test('decode stack frame ID', () => { - const frameID = createStackFrameID('ABCDEFGHIJKLMNOPQRSTUw', 123456789); - expect(getAddressFromStackFrameID(frameID)).toEqual(123456789); - expect(getFileIDFromStackFrameID(frameID)).toEqual('ABCDEFGHIJKLMNOPQRSTUw'); - }); -}); - describe('Stack frame metadata operations', () => { test('metadata has executable and function names', () => { const metadata = createStackFrameMetadata({ diff --git a/x-pack/plugins/profiling/common/profiling.ts b/x-pack/plugins/profiling_data_access/common/profiling.ts similarity index 86% rename from x-pack/plugins/profiling/common/profiling.ts rename to x-pack/plugins/profiling_data_access/common/profiling.ts index 22480a26f8ab2..c6f72f20629d3 100644 --- a/x-pack/plugins/profiling/common/profiling.ts +++ b/x-pack/plugins/profiling_data_access/common/profiling.ts @@ -5,50 +5,10 @@ * 2.0. */ -import { charCodeAt, safeBase64Encoder } from './base64'; - export type StackTraceID = string; export type StackFrameID = string; export type FileID = string; -export function createStackFrameID(fileID: FileID, addressOrLine: number): StackFrameID { - const buf = Buffer.alloc(24); - Buffer.from(fileID, 'base64url').copy(buf); - buf.writeBigUInt64BE(BigInt(addressOrLine), 16); - return buf.toString('base64url'); -} - -/* eslint no-bitwise: ["error", { "allow": ["&"] }] */ -export function getFileIDFromStackFrameID(frameID: StackFrameID): FileID { - return frameID.slice(0, 21) + safeBase64Encoder[frameID.charCodeAt(21) & 0x30]; -} - -/* eslint no-bitwise: ["error", { "allow": ["<<=", "&"] }] */ -export function getAddressFromStackFrameID(frameID: StackFrameID): number { - let address = charCodeAt(frameID, 21) & 0xf; - address <<= 6; - address += charCodeAt(frameID, 22); - address <<= 6; - address += charCodeAt(frameID, 23); - address <<= 6; - address += charCodeAt(frameID, 24); - address <<= 6; - address += charCodeAt(frameID, 25); - address <<= 6; - address += charCodeAt(frameID, 26); - address <<= 6; - address += charCodeAt(frameID, 27); - address <<= 6; - address += charCodeAt(frameID, 28); - address <<= 6; - address += charCodeAt(frameID, 29); - address <<= 6; - address += charCodeAt(frameID, 30); - address <<= 6; - address += charCodeAt(frameID, 31); - return address; -} - export enum FrameType { Unsymbolized = 0, Python, diff --git a/x-pack/plugins/profiling/common/stack_traces.test.ts b/x-pack/plugins/profiling_data_access/common/stack_traces.test.ts similarity index 100% rename from x-pack/plugins/profiling/common/stack_traces.test.ts rename to x-pack/plugins/profiling_data_access/common/stack_traces.test.ts diff --git a/x-pack/plugins/profiling/common/stack_traces.ts b/x-pack/plugins/profiling_data_access/common/stack_traces.ts similarity index 100% rename from x-pack/plugins/profiling/common/stack_traces.ts rename to x-pack/plugins/profiling_data_access/common/stack_traces.ts diff --git a/x-pack/plugins/profiling_data_access/jest.config.js b/x-pack/plugins/profiling_data_access/jest.config.js new file mode 100644 index 0000000000000..c87c047a5ea73 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/jest.config.js @@ -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. + */ + +const path = require('path'); + +module.exports = { + preset: '@kbn/test', + rootDir: path.resolve(__dirname, '../../..'), + roots: ['/x-pack/plugins/profiling_data_access'], +}; diff --git a/x-pack/plugins/profiling_data_access/kibana.jsonc b/x-pack/plugins/profiling_data_access/kibana.jsonc new file mode 100644 index 0000000000000..3f0254ba92647 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/kibana.jsonc @@ -0,0 +1,14 @@ +{ + "type": "plugin", + "id": "@kbn/profiling-data-access-plugin", + "owner": "@elastic/profiling-ui", + "plugin": { + "id": "profilingDataAccess", + "server": true, + "browser": false, + "configPath": ["xpack", "profiling"], + "requiredPlugins": ["data"], + "optionalPlugins": [], + "requiredBundles": [] + } +} diff --git a/x-pack/plugins/profiling_data_access/server/index.ts b/x-pack/plugins/profiling_data_access/server/index.ts new file mode 100644 index 0000000000000..d979d22f4a011 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { schema, TypeOf } from '@kbn/config-schema'; + +import type { PluginInitializerContext } from '@kbn/core/server'; +import { ProfilingDataAccessPlugin } from './plugin'; +import type { ProfilingDataAccessPluginSetup, ProfilingDataAccessPluginStart } from './plugin'; + +const configSchema = schema.object({ + elasticsearch: schema.conditional( + schema.contextRef('dist'), + schema.literal(true), + schema.never(), + schema.maybe( + schema.object({ + hosts: schema.string(), + username: schema.string(), + password: schema.string(), + }) + ) + ), +}); + +export type ProfilingConfig = TypeOf; + +export type { ProfilingDataAccessPluginSetup, ProfilingDataAccessPluginStart }; + +export function plugin(initializerContext: PluginInitializerContext) { + return new ProfilingDataAccessPlugin(initializerContext); +} diff --git a/x-pack/plugins/profiling_data_access/server/plugin.ts b/x-pack/plugins/profiling_data_access/server/plugin.ts new file mode 100644 index 0000000000000..23d72f39caee6 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/plugin.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 type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import { ProfilingConfig } from '.'; +import { registerServices } from './services/register_services'; +import { createProfilingEsClient } from './utils/create_profiling_es_client'; + +export type ProfilingDataAccessPluginSetup = ReturnType; +export type ProfilingDataAccessPluginStart = ReturnType; + +export class ProfilingDataAccessPlugin implements Plugin { + constructor(private readonly initializerContext: PluginInitializerContext) {} + public setup(core: CoreSetup) {} + + public start(core: CoreStart) { + const config = this.initializerContext.config.get(); + + const profilingSpecificEsClient = config.elasticsearch + ? core.elasticsearch.createClient('profiling', { + hosts: [config.elasticsearch.hosts], + username: config.elasticsearch.username, + password: config.elasticsearch.password, + }) + : undefined; + + const services = registerServices({ + createProfilingEsClient: ({ esClient: defaultEsClient, useDefaultAuth = false }) => { + const esClient = + profilingSpecificEsClient && !useDefaultAuth + ? profilingSpecificEsClient.asInternalUser + : defaultEsClient; + + return createProfilingEsClient({ esClient }); + }, + }); + + // called after all plugins are set up + return { + services, + }; + } +} diff --git a/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.ts b/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.ts new file mode 100644 index 0000000000000..dd72a012c6343 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/services/fetch_flamechart/index.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 { ElasticsearchClient } from '@kbn/core/server'; +import { RegisterServicesParams } from '../register_services'; +import { withProfilingSpan } from '../../utils/with_profiling_span'; +import { searchStackTraces } from '../search_stack_traces'; +import { createCalleeTree } from '../../../common/callee'; +import { createBaseFlameGraph } from '../../../common/flamegraph'; + +interface FetchFlamechartParams { + esClient: ElasticsearchClient; + rangeFrom: number; + rangeTo: number; + kuery: string; +} + +export function createFetchFlamechart({ createProfilingEsClient }: RegisterServicesParams) { + return async ({ esClient, rangeFrom, rangeTo, kuery }: FetchFlamechartParams) => { + const profilingEsClient = createProfilingEsClient({ esClient }); + const targetSampleSize = 20000; // minimum number of samples to get statistically sound results + + const totalSeconds = rangeTo - rangeFrom; + + const { events, stackTraces, executables, stackFrames, totalFrames, samplingRate } = + await searchStackTraces({ + client: profilingEsClient, + rangeFrom, + rangeTo, + kuery, + sampleSize: targetSampleSize, + }); + + const flamegraph = await withProfilingSpan('create_flamegraph', async () => { + const tree = createCalleeTree( + events, + stackTraces, + stackFrames, + executables, + totalFrames, + samplingRate + ); + + const fg = createBaseFlameGraph(tree, samplingRate, totalSeconds); + + return fg; + }); + + return flamegraph; + }; +} diff --git a/x-pack/plugins/profiling_data_access/server/services/register_services.ts b/x-pack/plugins/profiling_data_access/server/services/register_services.ts new file mode 100644 index 0000000000000..fdac4528f6b5d --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/services/register_services.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ElasticsearchClient } from '@kbn/core/server'; +import { createFetchFlamechart } from './fetch_flamechart'; +import { ProfilingESClient } from '../utils/create_profiling_es_client'; + +export interface RegisterServicesParams { + createProfilingEsClient: (params: { + esClient: ElasticsearchClient; + useDefaultAuth?: boolean; + }) => ProfilingESClient; +} + +export function registerServices(params: RegisterServicesParams) { + return { fetchFlamechartData: createFetchFlamechart(params) }; +} diff --git a/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts b/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts new file mode 100644 index 0000000000000..1c9e185fe4c05 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/services/search_stack_traces/index.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; +import { decodeStackTraceResponse } from '../../../common/stack_traces'; +import { ProfilingESClient } from '../../utils/create_profiling_es_client'; + +export async function searchStackTraces({ + client, + sampleSize, + rangeFrom, + rangeTo, + kuery, +}: { + client: ProfilingESClient; + sampleSize: number; + rangeFrom: number; + rangeTo: number; + kuery: string; +}) { + const response = await client.profilingStacktraces({ + query: { + bool: { + filter: [ + ...kqlQuery(kuery), + { + range: { + ['@timestamp']: { + gte: String(rangeFrom), + lt: String(rangeTo), + format: 'epoch_second', + boost: 1.0, + }, + }, + }, + ], + }, + }, + sampleSize, + }); + + return decodeStackTraceResponse(response); +} + +function kqlQuery(kql?: string): estypes.QueryDslQueryContainer[] { + if (!kql) { + return []; + } + + const ast = fromKueryExpression(kql); + return [toElasticsearchQuery(ast)]; +} diff --git a/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts b/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts new file mode 100644 index 0000000000000..0c5b85f42c8fb --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/utils/create_profiling_es_client.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { ElasticsearchClient } from '@kbn/core/server'; +import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; +import { unwrapEsResponse } from '@kbn/observability-plugin/server'; +import { ProfilingStatusResponse, StackTraceResponse } from '../../common/stack_traces'; +import { withProfilingSpan } from './with_profiling_span'; + +export interface ProfilingESClient { + search( + operationName: string, + searchRequest: TSearchRequest + ): Promise>; + profilingStacktraces({}: { + query: QueryDslQueryContainer; + sampleSize: number; + }): Promise; + profilingStatus(): Promise; + getEsClient(): ElasticsearchClient; +} + +export function createProfilingEsClient({ + esClient, +}: { + esClient: ElasticsearchClient; +}): ProfilingESClient { + return { + search( + operationName: string, + searchRequest: TSearchRequest + ): Promise> { + const controller = new AbortController(); + + const promise = withProfilingSpan(operationName, () => { + return esClient.search(searchRequest, { + signal: controller.signal, + meta: true, + }) as unknown as Promise<{ + body: InferSearchResponseOf; + }>; + }); + + return unwrapEsResponse(promise); + }, + profilingStacktraces({ query, sampleSize }) { + const controller = new AbortController(); + const promise = withProfilingSpan('_profiling/stacktraces', () => { + return esClient.transport.request( + { + method: 'POST', + path: encodeURI('/_profiling/stacktraces'), + body: { + query, + sample_size: sampleSize, + }, + }, + { + signal: controller.signal, + meta: true, + } + ); + }); + + return unwrapEsResponse(promise) as Promise; + }, + profilingStatus() { + const controller = new AbortController(); + + const promise = withProfilingSpan('_profiling/status', () => { + return esClient.transport.request( + { + method: 'GET', + path: encodeURI('/_profiling/status'), + }, + { + signal: controller.signal, + meta: true, + } + ); + }); + + return unwrapEsResponse(promise) as Promise; + }, + getEsClient() { + return esClient; + }, + }; +} diff --git a/x-pack/plugins/profiling_data_access/server/utils/with_profiling_span.ts b/x-pack/plugins/profiling_data_access/server/utils/with_profiling_span.ts new file mode 100644 index 0000000000000..6d366799780e7 --- /dev/null +++ b/x-pack/plugins/profiling_data_access/server/utils/with_profiling_span.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { withSpan, SpanOptions, parseSpanOptions } from '@kbn/apm-utils'; + +export function withProfilingSpan( + optionsOrName: SpanOptions | string, + cb: () => Promise +): Promise { + const options = parseSpanOptions(optionsOrName); + + const optionsWithDefaults = { + ...(options.intercept ? {} : { type: 'plugin:profiling' }), + ...options, + labels: { + plugin: 'profiling', + ...options.labels, + }, + }; + + return withSpan(optionsWithDefaults, cb); +} diff --git a/x-pack/plugins/profiling_data_access/tsconfig.json b/x-pack/plugins/profiling_data_access/tsconfig.json new file mode 100644 index 0000000000000..f8693cb83658e --- /dev/null +++ b/x-pack/plugins/profiling_data_access/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "server/**/*", + "common/**/*.ts", + "common/**/*.json", + "jest.config.js" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/config-schema", + "@kbn/core", + "@kbn/es-query", + "@kbn/es-types", + "@kbn/observability-plugin", + "@kbn/apm-utils" + ] +} diff --git a/x-pack/plugins/saved_objects_tagging/server/plugin.ts b/x-pack/plugins/saved_objects_tagging/server/plugin.ts index 39ab63e1b01d4..f62d84f5742e9 100644 --- a/x-pack/plugins/saved_objects_tagging/server/plugin.ts +++ b/x-pack/plugins/saved_objects_tagging/server/plugin.ts @@ -54,11 +54,14 @@ export class SavedObjectTaggingPlugin features.registerKibanaFeature(savedObjectsTaggingFeature); if (usageCollection) { - const kibanaIndices = savedObjects.getAllIndices(); + const getKibanaIndices = () => + getStartServices() + .then(([core]) => core.savedObjects.getAllIndices()) + .catch(() => []); usageCollection.registerCollector( createTagUsageCollector({ usageCollection, - kibanaIndices, + getKibanaIndices, }) ); } diff --git a/x-pack/plugins/saved_objects_tagging/server/usage/tag_usage_collector.ts b/x-pack/plugins/saved_objects_tagging/server/usage/tag_usage_collector.ts index 9af63f3cb6adb..d0d33e5b7d995 100644 --- a/x-pack/plugins/saved_objects_tagging/server/usage/tag_usage_collector.ts +++ b/x-pack/plugins/saved_objects_tagging/server/usage/tag_usage_collector.ts @@ -12,17 +12,17 @@ import { tagUsageCollectorSchema } from './schema'; export const createTagUsageCollector = ({ usageCollection, - kibanaIndices, + getKibanaIndices, }: { usageCollection: UsageCollectionSetup; - kibanaIndices: string[]; + getKibanaIndices: () => Promise; }) => { return usageCollection.makeUsageCollector({ type: 'saved_objects_tagging', isReady: () => true, schema: tagUsageCollectorSchema, fetch: async ({ esClient }) => { - return fetchTagUsageData({ esClient, kibanaIndices }); + return fetchTagUsageData({ esClient, kibanaIndices: await getKibanaIndices() }); }, }); }; diff --git a/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts b/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts index 1c5883c052135..f6a394e8c46c9 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_loaders/index_endpoint_rule_alerts.ts @@ -127,14 +127,17 @@ const ensureEndpointRuleAlertsIndexExists = async (esClient: Client): Promise { }; }); +const mockUseObservable = jest.fn(); + +jest.mock('react-use', () => ({ + ...jest.requireActual('react-use'), + useObservable: () => mockUseObservable(), +})); + const DEFAULT_DASHBOARD_CAPABILITIES = { show: true, createNew: true }; const mockUseCapabilities = useCapabilities as jest.Mock; mockUseCapabilities.mockReturnValue(DEFAULT_DASHBOARD_CAPABILITIES); @@ -210,4 +217,13 @@ describe('Dashboards landing', () => { }); }); }); + + it('should render callout when available', async () => { + const DummyComponent = () => ; + mockUseObservable.mockReturnValue(); + + await renderDashboardLanding(); + + expect(screen.queryByTestId('test')).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx index 7d579c66e8191..8cb12d5895021 100644 --- a/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx +++ b/x-pack/plugins/security_solution/public/dashboards/pages/landing_page/index.tsx @@ -17,10 +17,11 @@ import React, { useCallback, useMemo } from 'react'; import type { DashboardCapabilities } from '@kbn/dashboard-plugin/common/types'; import { DashboardListingTable, LEGACY_DASHBOARD_APP_ID } from '@kbn/dashboard-plugin/public'; import { LandingLinksImageCards } from '@kbn/security-solution-navigation/landing_links'; +import { useObservable } from 'react-use'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; import { SecurityPageName } from '../../../../common/constants'; -import { useCapabilities, useNavigateTo } from '../../../common/lib/kibana'; +import { useCapabilities, useKibana, useNavigateTo } from '../../../common/lib/kibana'; import { useRootNavLink } from '../../../common/links/nav_links'; import { Title } from '../../../common/components/header_page/title'; import { LinkButton } from '../../../common/components/links/helpers'; @@ -82,6 +83,8 @@ const Header: React.FC<{ canCreateDashboard: boolean }> = ({ canCreateDashboard }; export const DashboardsLandingPage = () => { + const { dashboardsLandingCalloutComponent$ } = useKibana().services; + const dashboardLandingCallout = useObservable(dashboardsLandingCalloutComponent$); const { links = [] } = useRootNavLink(SecurityPageName.dashboards) ?? {}; const urlState = useGlobalQueryString(); const { show: canReadDashboard, createNew: canCreateDashboard } = @@ -121,6 +124,13 @@ export const DashboardsLandingPage = () => {

+ {dashboardLandingCallout && ( + <> + {dashboardLandingCallout} + + + )} +

{i18n.DASHBOARDS_PAGE_SECTION_DEFAULT}

diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx index c4d50062675d2..2ee3cbd169ecf 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_preview/index.tsx @@ -12,7 +12,6 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiFormRow, EuiSpacer, EuiSuperDatePicker, EuiSuperUpdateButton, @@ -232,36 +231,32 @@ const RulePreviewComponent: React.FC = ({ )} - - - +

{i18n.QUERY_PREVIEW_LABEL}

+ + + + + + - - - - -
+ + {isPreviewRequestInProgress && } {!isPreviewRequestInProgress && previewId && spaceId && ( diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx index e1512b8b7ada1..5c7a900765fe3 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.test.tsx @@ -11,11 +11,18 @@ import { LeftPanelContext } from '../context'; import { PrevalenceDetails } from './prevalence_details'; import { PREVALENCE_DETAILS_LOADING_TEST_ID, + PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID, + PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_ERROR_TEST_ID, + PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID, + PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID, PREVALENCE_DETAILS_TABLE_TEST_ID, + PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, + PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, } from './test_ids'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; import { TestProviders } from '../../../common/mock'; +import { licenseService } from '../../../common/hooks/use_license'; jest.mock('../../shared/hooks/use_prevalence'); @@ -27,6 +34,17 @@ jest.mock('react-redux', () => { useDispatch: () => mockDispatch, }; }); +jest.mock('../../../common/hooks/use_license', () => { + const licenseServiceInstance = { + isPlatinumPlus: jest.fn(), + }; + return { + licenseService: licenseServiceInstance, + useLicense: () => { + return licenseServiceInstance; + }, + }; +}); const panelContextValue = { eventId: 'event id', @@ -36,7 +54,13 @@ const panelContextValue = { } as unknown as LeftPanelContext; describe('PrevalenceDetails', () => { - it('should render the table', () => { + const licenseServiceMock = licenseService as jest.Mocked; + + beforeEach(() => { + licenseServiceMock.isPlatinumPlus.mockReturnValue(true); + }); + + it('should render the table with all columns if license is platinum', () => { const field1 = 'field1'; const field2 = 'field2'; (usePrevalence as jest.Mock).mockReturnValue({ @@ -62,7 +86,7 @@ describe('PrevalenceDetails', () => { ], }); - const { getByTestId } = render( + const { getByTestId, getAllByTestId, queryByTestId } = render( @@ -71,6 +95,74 @@ describe('PrevalenceDetails', () => { ); expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument(); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID).length).toBeGreaterThan(1); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID).length).toBeGreaterThan(1); + expect( + getAllByTestId(PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID).length + ).toBeGreaterThan(1); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID).length).toBeGreaterThan( + 1 + ); + expect( + getAllByTestId(PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID).length + ).toBeGreaterThan(1); + expect( + getAllByTestId(PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID).length + ).toBeGreaterThan(1); + expect(queryByTestId(`${PREVALENCE_DETAILS_TABLE_TEST_ID}UpSell`)).not.toBeInTheDocument(); + }); + + it('should render the table with only basic columns if license is not platinum', () => { + const field1 = 'field1'; + const field2 = 'field2'; + (usePrevalence as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [ + { + field: field1, + value: 'value1', + alertCount: 1, + docCount: 1, + hostPrevalence: 0.05, + userPrevalence: 0.1, + }, + { + field: field2, + value: 'value2', + alertCount: 1, + docCount: 1, + hostPrevalence: 0.5, + userPrevalence: 0.05, + }, + ], + }); + licenseServiceMock.isPlatinumPlus.mockReturnValue(false); + + const { getByTestId, getAllByTestId } = render( + + + + + + ); + + expect(getByTestId(PREVALENCE_DETAILS_TABLE_TEST_ID)).toBeInTheDocument(); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID).length).toBeGreaterThan(1); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID).length).toBeGreaterThan(1); + expect( + getAllByTestId(PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID).length + ).toBeGreaterThan(1); + expect(getAllByTestId(PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID).length).toBeGreaterThan( + 1 + ); + expect( + getAllByTestId(PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID).length + ).toBeGreaterThan(1); + expect( + getAllByTestId(PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID).length + ).toBeGreaterThan(1); + expect(getByTestId(`${PREVALENCE_DETAILS_TABLE_TEST_ID}UpSell`)).toBeInTheDocument(); }); it('should render loading', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx index b11622b4a4560..11f370e9572a6 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/prevalence_details.tsx @@ -5,19 +5,25 @@ * 2.0. */ -import React, { useState } from 'react'; +import dateMath from '@elastic/datemath'; +import React, { useMemo, useState } from 'react'; import type { EuiBasicTableColumn, OnTimeChangeProps } from '@elastic/eui'; import { + EuiCallOut, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, + EuiLink, EuiLoadingSpinner, EuiPanel, EuiSpacer, EuiSuperDatePicker, + EuiText, EuiToolTip, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { useLicense } from '../../../common/hooks/use_license'; import { InvestigateInTimelineButton } from '../../../common/components/event_details/table/investigate_in_timeline_button'; import type { PrevalenceData } from '../../shared/hooks/use_prevalence'; import { usePrevalence } from '../../shared/hooks/use_prevalence'; @@ -63,16 +69,31 @@ export const PREVALENCE_TAB_ID = 'prevalence-details'; const DEFAULT_FROM = 'now-30d'; const DEFAULT_TO = 'now'; -const columns: Array> = [ +interface PrevalenceDetailsRow extends PrevalenceData { + /** + * From datetime selected in the date picker to pass to timeline + */ + from: string; + /** + * To datetime selected in the date picker to pass to timeline + */ + to: string; +} + +const columns: Array> = [ { field: 'field', name: PREVALENCE_TABLE_FIELD_COLUMN_TITLE, 'data-test-subj': PREVALENCE_DETAILS_TABLE_FIELD_CELL_TEST_ID, + render: (field: string) => {field}, + width: '20%', }, { field: 'value', name: PREVALENCE_TABLE_VALUE_COLUMN_TITLE, 'data-test-subj': PREVALENCE_DETAILS_TABLE_VALUE_CELL_TEST_ID, + render: (value: string) => {value}, + width: '20%', }, { name: ( @@ -84,7 +105,7 @@ const columns: Array> = [ ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_ALERT_COUNT_CELL_TEST_ID, - render: (data: PrevalenceData) => { + render: (data: PrevalenceDetailsRow) => { const dataProviders = [ getDataProvider(data.field, `timeline-indicator-${data.field}-${data.value}`, data.value), ]; @@ -93,6 +114,7 @@ const columns: Array> = [ asEmptyButton={true} dataProviders={dataProviders} filters={[]} + timeRange={{ kind: 'absolute', from: data.from, to: data.to }} > <>{data.alertCount} @@ -112,7 +134,7 @@ const columns: Array> = [ ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_DOC_COUNT_CELL_TEST_ID, - render: (data: PrevalenceData) => { + render: (data: PrevalenceDetailsRow) => { const dataProviders = [ { ...getDataProvider( @@ -136,6 +158,7 @@ const columns: Array> = [ asEmptyButton={true} dataProviders={dataProviders} filters={[]} + timeRange={{ kind: 'absolute', from: data.from, to: data.to }} keepDataView // changing dataview from only detections to include non-alerts docs > <>{data.docCount} @@ -158,10 +181,7 @@ const columns: Array> = [ ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_HOST_PREVALENCE_CELL_TEST_ID, render: (hostPrevalence: number) => ( - <> - {Math.round(hostPrevalence * 100)} - {'%'} - + {`${Math.round(hostPrevalence * 100)}%`} ), width: '10%', }, @@ -177,10 +197,7 @@ const columns: Array> = [ ), 'data-test-subj': PREVALENCE_DETAILS_TABLE_USER_PREVALENCE_CELL_TEST_ID, render: (userPrevalence: number) => ( - <> - {Math.round(userPrevalence * 100)} - {'%'} - + {`${Math.round(userPrevalence * 100)}%`} ), width: '10%', }, @@ -193,12 +210,38 @@ export const PrevalenceDetails: React.FC = () => { const { browserFields, dataFormattedForFieldBrowser, eventId, investigationFields } = useLeftPanelContext(); + const isPlatinumPlus = useLicense().isPlatinumPlus(); + + // these two are used by the usePrevalence hook to fetch the data const [start, setStart] = useState(DEFAULT_FROM); const [end, setEnd] = useState(DEFAULT_TO); - const onTimeChange = ({ start: s, end: e }: OnTimeChangeProps) => { + // these two are used to pass to timeline + const [absoluteStart, setAbsoluteStart] = useState( + (dateMath.parse(DEFAULT_FROM) || new Date()).toISOString() + ); + const [absoluteEnd, setAbsoluteEnd] = useState( + (dateMath.parse(DEFAULT_TO) || new Date()).toISOString() + ); + + // TODO update the logic to use a single set of start/end dates + // currently as we're using this InvestigateInTimelineButton component we need to pass the timeRange + // as an AbsoluteTimeRange, which requires from/to values + const onTimeChange = ({ start: s, end: e, isInvalid }: OnTimeChangeProps) => { + if (isInvalid) return; + setStart(s); setEnd(e); + + const from = dateMath.parse(s); + if (from && from.isValid()) { + setAbsoluteStart(from.toISOString()); + } + + const to = dateMath.parse(e); + if (to && to.isValid()) { + setAbsoluteEnd(to.toISOString()); + } }; const { loading, error, data } = usePrevalence({ @@ -210,6 +253,12 @@ export const PrevalenceDetails: React.FC = () => { }, }); + // add timeRange to pass it down to timeline + const items = useMemo( + () => data.map((item) => ({ ...item, from: absoluteStart, to: absoluteEnd })), + [data, absoluteStart, absoluteEnd] + ); + if (loading) { return ( { ); } + const upsell = ( + <> + + + + + ), + }} + /> + + + + ); + return ( <> + {!isPlatinumPlus && upsell} { {data.length > 0 ? ( diff --git a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx index 07153217262b2..6281a34e0d78f 100644 --- a/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/left/components/response_details.tsx @@ -69,7 +69,7 @@ export const ResponseDetails: React.FC = () => { values={{ editRuleLink: ( ', () => { expect(mockUseAlertPrevalenceFromProcessTree).toHaveBeenCalledWith({ isActiveTimeline: false, documentId: 'ancestors-id', - indices: ['rule-parameters-index'], + indices: ['rule-indices'], }); expect(wrapper.getByTestId(ANALYZER_PREVIEW_TEST_ID)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx index 54fa7d6907bdc..3d872640a5a22 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/analyzer_preview.tsx @@ -10,7 +10,7 @@ import { EuiTreeView } from '@elastic/eui'; import { ANALYZER_PREVIEW_TEST_ID } from './test_ids'; import { getTreeNodes } from '../utils/analyzer_helpers'; import { ANALYZER_PREVIEW_TITLE } from './translations'; -import { ANCESTOR_ID, RULE_PARAMETERS_INDEX } from '../../shared/constants/field_names'; +import { ANCESTOR_ID, RULE_INDICES } from '../../shared/constants/field_names'; import { useRightPanelContext } from '../context'; import { useAlertPrevalenceFromProcessTree } from '../../../common/containers/alerts/use_alert_prevalence_from_process_tree'; import type { StatsNode } from '../../../common/containers/alerts/use_alert_prevalence_from_process_tree'; @@ -38,7 +38,7 @@ export const AnalyzerPreview: React.FC = () => { const processDocumentId = documentId && Array.isArray(documentId.values) ? documentId.values[0] : ''; - const index = find({ category: 'kibana', field: RULE_PARAMETERS_INDEX }, data); + const index = find({ category: 'kibana', field: RULE_INDICES }, data); const indices = index?.values ?? []; const { statsNodes } = useAlertPrevalenceFromProcessTree({ diff --git a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx index 2a77f1a1eeddb..8a1724dd98d5a 100644 --- a/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx +++ b/x-pack/plugins/security_solution/public/flyout/right/components/highlighted_fields.tsx @@ -54,11 +54,13 @@ const columns: Array> = [ field: 'field', name: HIGHLIGHTED_FIELDS_FIELD_COLUMN, 'data-test-subj': 'fieldCell', + width: '50%', }, { field: 'description', name: HIGHLIGHTED_FIELDS_VALUE_COLUMN, 'data-test-subj': 'valueCell', + width: '50%', render: (description: { field: string; values: string[] | null | undefined; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/constants/field_names.ts b/x-pack/plugins/security_solution/public/flyout/shared/constants/field_names.ts index e9a896a73dded..b663ea41e2069 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/constants/field_names.ts +++ b/x-pack/plugins/security_solution/public/flyout/shared/constants/field_names.ts @@ -7,6 +7,7 @@ export const ANCESTOR_ID = 'kibana.alert.ancestors.id'; export const RULE_PARAMETERS_INDEX = 'kibana.alert.rule.parameters.index'; +export const RULE_INDICES = 'kibana.alert.rule.indices'; export const ORIGINAL_EVENT_ID = 'kibana.alert.original_event.id'; export const ENTRY_LEADER_ENTITY_ID = 'process.entry_leader.entity_id'; export const ENTRY_LEADER_START = 'process.entry_leader.start'; diff --git a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_fetch_prevalence.ts b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_fetch_prevalence.ts index 804784728c3f7..3a0f5f824f4b2 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_fetch_prevalence.ts +++ b/x-pack/plugins/security_solution/public/flyout/shared/hooks/use_fetch_prevalence.ts @@ -11,6 +11,9 @@ import { useQuery } from '@tanstack/react-query'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { createFetchData } from '../utils/fetch_data'; import { useKibana } from '../../../common/lib/kibana'; +import { useTimelineDataFilters } from '../../../timelines/containers/use_timeline_data_filters'; +import { isActiveTimeline } from '../../../helpers'; +import { SourcererScopeName } from '../../../common/store/sourcerer/model'; const QUERY_KEY = 'useFetchFieldValuePairWithAggregation'; @@ -99,7 +102,10 @@ export const useFetchPrevalence = ({ }, } = useKibana(); - const searchRequest = buildSearchRequest(highlightedFieldsFilters, from, to); + // retrieves detections and non-detections indices (for example, the alert security index from the current space and 'logs-*' indices) + const { selectedPatterns } = useTimelineDataFilters(isActiveTimeline(SourcererScopeName.default)); + + const searchRequest = buildSearchRequest(highlightedFieldsFilters, from, to, selectedPatterns); const { data, isLoading, isError } = useQuery( [QUERY_KEY, highlightedFieldsFilters, from, to], @@ -120,7 +126,8 @@ export const useFetchPrevalence = ({ const buildSearchRequest = ( highlightedFieldsFilters: Record, from: string, - to: string + to: string, + selectedPatterns: string[] ): IEsSearchRequest => { const query = buildEsQuery( undefined, @@ -146,14 +153,16 @@ const buildSearchRequest = ( ] ); - return buildAggregationSearchRequest(query, highlightedFieldsFilters); + return buildAggregationSearchRequest(query, highlightedFieldsFilters, selectedPatterns); }; const buildAggregationSearchRequest = ( query: QueryDslQueryContainer, - highlightedFieldsFilters: Record + highlightedFieldsFilters: Record, + selectedPatterns: string[] ): IEsSearchRequest => ({ params: { + index: selectedPatterns, body: { query, aggs: { diff --git a/x-pack/plugins/security_solution/public/flyout/shared/mocks/mock_context.ts b/x-pack/plugins/security_solution/public/flyout/shared/mocks/mock_context.ts index 8280fb64df927..46fa9cff49a31 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/mocks/mock_context.ts +++ b/x-pack/plugins/security_solution/public/flyout/shared/mocks/mock_context.ts @@ -81,6 +81,13 @@ export const mockDataFormattedForFieldBrowser = [ originalValue: ['rule-parameters-index'], isObjectArray: false, }, + { + category: 'kibana', + field: 'kibana.alert.rule.indices', + values: ['rule-indices'], + originalValue: ['rule-indices'], + isObjectArray: false, + }, { category: 'process', field: 'process.entity_id', diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_table.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_table.tsx index 2504392d5ef10..4e7e443972abc 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_table.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/components/actions_log_table.tsx @@ -7,19 +7,19 @@ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { - EuiI18nNumber, + type CriteriaWithPagination, EuiAvatar, EuiBasicTable, EuiButtonIcon, EuiFacetButton, EuiHorizontalRule, - RIGHT_ALIGNMENT, + EuiI18nNumber, EuiScreenReaderOnly, + EuiSkeletonText, EuiText, EuiToolTip, type HorizontalAlignment, - type CriteriaWithPagination, - EuiSkeletonText, + RIGHT_ALIGNMENT, } from '@elastic/eui'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -30,14 +30,13 @@ import { SecuritySolutionLinkAnchor } from '../../../../common/components/links' import type { ActionListApiResponse } from '../../../../../common/endpoint/types'; import type { EndpointActionListRequestQuery } from '../../../../../common/api/endpoint'; import { FormattedDate } from '../../../../common/components/formatted_date'; -import { TABLE_COLUMN_NAMES, UX_MESSAGES, ARIA_LABELS } from '../translations'; +import { ARIA_LABELS, TABLE_COLUMN_NAMES, UX_MESSAGES } from '../translations'; import { getActionStatus, getUiCommand } from './hooks'; import { getEmptyValue } from '../../../../common/components/empty_value'; import { StatusBadge } from './status_badge'; import { ActionsLogExpandedTray } from './action_log_expanded_tray'; import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants'; -import { useActionHistoryUrlParams } from './use_action_history_url_params'; import { useUrlPagination } from '../../../hooks/use_url_pagination'; const emptyValue = getEmptyValue(); @@ -292,22 +291,19 @@ export const ActionsLogTable = memo( }) => { const getTestId = useTestIdGenerator(dataTestSubj); const { pagination: paginationFromUrlParams } = useUrlPagination(); - const { withOutputs: withOutputsFromUrl } = useActionHistoryUrlParams(); const [expandedRowMap, setExpandedRowMap] = useState({}); - const actionIdsWithOpenTrays = useMemo((): string[] => { - // get the list of action ids from URL params on the history page - if (!isFlyout) { - return withOutputsFromUrl ?? []; - } - // get the list of action ids form the query params for flyout view - return queryParams.withOutputs - ? typeof queryParams.withOutputs === 'string' - ? [queryParams.withOutputs] - : queryParams.withOutputs - : []; - }, [isFlyout, queryParams.withOutputs, withOutputsFromUrl]); + const actionIdsWithOpenTrays = useMemo( + (): string[] => + // get the list of action ids from the query params for flyout view + queryParams.withOutputs + ? typeof queryParams.withOutputs === 'string' + ? [queryParams.withOutputs] + : queryParams.withOutputs + : [], + [queryParams.withOutputs] + ); const redoOpenTrays = useCallback(() => { if (actionIdsWithOpenTrays.length && items.length) { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/integration_tests/response_actions_log.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/integration_tests/response_actions_log.test.tsx index 476a86a6561dd..1e835e34ac7ef 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/integration_tests/response_actions_log.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_response_actions_list/integration_tests/response_actions_log.test.tsx @@ -7,12 +7,13 @@ import React from 'react'; import * as reactTestingLibrary from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import { - createAppRootMockRenderer, type AppContextTestRender, + createAppRootMockRenderer, } from '../../../../common/mock/endpoint'; import { ResponseActionsLog } from '../response_actions_log'; import type { @@ -29,7 +30,6 @@ import { v4 as uuidv4 } from 'uuid'; import { RESPONSE_ACTION_API_COMMANDS_NAMES } from '../../../../../common/endpoint/service/response_actions/constants'; import { useUserPrivileges as _useUserPrivileges } from '../../../../common/components/user_privileges'; import { responseActionsHttpMocks } from '../../../mocks/response_actions_http_mocks'; -import { waitFor } from '@testing-library/react'; import { getEndpointAuthzInitialStateMock } from '../../../../../common/endpoint/service/authz/mocks'; import { useGetEndpointActionList as _useGetEndpointActionList } from '../../../hooks/response_actions/use_get_endpoint_action_list'; import { OUTPUT_MESSAGES } from '../translations'; @@ -470,7 +470,7 @@ describe('Response actions history', () => { ); }); - it('should expand each row to show details', async () => { + it('should expand/collapse each row to show/hide details', async () => { render(); const { getAllByTestId, queryAllByTestId } = renderResult; @@ -961,8 +961,7 @@ describe('Response actions history', () => { const expandButtons = getAllByTestId(`${testPrefix}-expand-button`); expandButtons.map((button) => userEvent.click(button)); - const outputs = getAllByTestId(`${testPrefix}-details-tray-output`); - return outputs; + return getAllByTestId(`${testPrefix}-details-tray-output`); }; it.each(RESPONSE_ACTION_API_COMMANDS_NAMES)( diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/reponse_actions_history.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/reponse_actions_history.cy.ts index cb6c7c3a96eee..5c4bb0f3efb8c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/reponse_actions_history.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/mocked_data/reponse_actions_history.cy.ts @@ -50,4 +50,25 @@ describe('Response actions history page', () => { cy.getByTestSubj('pagination-button-0').click(); cy.getByTestSubj('response-actions-list-details-tray').should('exist'); }); + + it('collapses expanded tray with a single click', () => { + loadPage(`/app/security/administration/response_actions_history`); + // 2nd row on 1st page + const row = cy.getByTestSubj('response-actions-list-expand-button').eq(1); + + // expand the row + row.click(); + cy.getByTestSubj('response-actions-list-details-tray').should('exist'); + cy.url().should('include', 'withOutputs'); + + // collapse the row + cy.intercept('GET', '/api/endpoint/action*').as('getResponses'); + row.click(); + // wait for the API response to come back + // and then see if the tray is actually closed + cy.wait('@getResponses', { timeout: 500 }).then(() => { + cy.getByTestSubj('response-actions-list-details-tray').should('not.exist'); + cy.url().should('not.include', 'withOutputs'); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.test.tsx index ebde74b17be76..ea720f79a66c6 100644 --- a/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/response_actions/view/response_actions_list_page.test.tsx @@ -236,7 +236,7 @@ describe('Response actions history page', () => { return { id: `agent-id-${i}`, name: `Host-name-${i}`, - selected: [0, 1, 3, 5].includes(i) ? true : false, + selected: [0, 1, 3, 5].includes(i), }; }), page: 0, diff --git a/x-pack/plugins/security_solution/public/mocks.ts b/x-pack/plugins/security_solution/public/mocks.ts index b48da210d6756..9e0757047879a 100644 --- a/x-pack/plugins/security_solution/public/mocks.ts +++ b/x-pack/plugins/security_solution/public/mocks.ts @@ -28,6 +28,7 @@ const startMock = (): PluginStart => ({ ), setExtraRoutes: jest.fn(), getUpselling: () => upselling, + setDashboardsLandingCallout: jest.fn(), }); export const securitySolutionMock = { diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index c482c7cfa1616..a384999c32b54 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -194,7 +194,7 @@ export class Plugin implements IPlugin SecuritySolutionTemplateWrapper, }, - savedObjectsManagement: startPluginsDeps.savedObjectsManagement, + contentManagement: startPluginsDeps.contentManagement, telemetry: this.telemetry.start(), customDataService, topValuesPopover: new TopValuesPopoverService(), diff --git a/x-pack/plugins/security_solution/public/plugin_contract.ts b/x-pack/plugins/security_solution/public/plugin_contract.ts index a96572e006f89..d21eabe738f4f 100644 --- a/x-pack/plugins/security_solution/public/plugin_contract.ts +++ b/x-pack/plugins/security_solution/public/plugin_contract.ts @@ -17,6 +17,7 @@ export class PluginContract { public isILMAvailable$: BehaviorSubject; public isSidebarEnabled$: BehaviorSubject; public getStartedComponent$: BehaviorSubject; + public dashboardsLandingCallout$: BehaviorSubject; public upsellingService: UpsellingService; public extraRoutes$: BehaviorSubject; public appLinksSwitcher: AppLinksSwitcher; @@ -26,6 +27,8 @@ export class PluginContract { this.isILMAvailable$ = new BehaviorSubject(true); this.isSidebarEnabled$ = new BehaviorSubject(true); this.getStartedComponent$ = new BehaviorSubject(null); + this.dashboardsLandingCallout$ = new BehaviorSubject(null); + this.upsellingService = new UpsellingService(); this.appLinksSwitcher = (appLinks) => appLinks; } @@ -36,6 +39,7 @@ export class PluginContract { isILMAvailable$: this.isILMAvailable$.asObservable(), isSidebarEnabled$: this.isSidebarEnabled$.asObservable(), getStartedComponent$: this.getStartedComponent$.asObservable(), + dashboardsLandingCalloutComponent$: this.dashboardsLandingCallout$.asObservable(), upselling: this.upsellingService, }; } @@ -59,6 +63,9 @@ export class PluginContract { setGetStartedPage: (getStartedComponent) => { this.getStartedComponent$.next(getStartedComponent); }, + setDashboardsLandingCallout: (dashboardsLandingCallout) => { + this.dashboardsLandingCallout$.next(dashboardsLandingCallout); + }, getBreadcrumbsNav$: () => breadcrumbsNav$, getUpselling: () => this.upsellingService, }; diff --git a/x-pack/plugins/security_solution/public/rules/links.ts b/x-pack/plugins/security_solution/public/rules/links.ts index c65b7ec3517de..23334456ac04f 100644 --- a/x-pack/plugins/security_solution/public/rules/links.ts +++ b/x-pack/plugins/security_solution/public/rules/links.ts @@ -94,7 +94,7 @@ export const links: LinkItem = { description: i18n.translate( 'xpack.securitySolution.appLinks.coverageOverviewDashboardDescription', { - defaultMessage: 'Review and maintain your protections MITRE ATT&CK® coverage', + defaultMessage: 'Review and maintain your protections MITRE ATT&CK® coverage.', } ), path: COVERAGE_OVERVIEW_PATH, diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index b1fc18359f4f6..6b16958f65808 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -48,7 +48,7 @@ import type { ThreatIntelligencePluginStart } from '@kbn/threat-intelligence-plu import type { CloudExperimentsPluginStart } from '@kbn/cloud-experiments-plugin/common'; import type { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public'; import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public'; -import type { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { RouteProps } from 'react-router-dom'; import type { DiscoverStart } from '@kbn/discover-plugin/public'; @@ -133,7 +133,7 @@ export interface StartPlugins { } export interface StartPluginsDependencies extends StartPlugins { - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; savedObjectsTaggingOss: SavedObjectTaggingOssPluginStart; } @@ -142,6 +142,7 @@ export interface ContractStartServices { isILMAvailable$: Observable; isSidebarEnabled$: Observable; getStartedComponent$: Observable; + dashboardsLandingCalloutComponent$: Observable; upselling: UpsellingService; } @@ -161,7 +162,7 @@ export type StartServices = CoreStart & securityLayout: { getPluginWrapper: () => typeof SecuritySolutionTemplateWrapper; }; - savedObjectsManagement: SavedObjectsManagementPluginStart; + contentManagement: ContentManagementPublicStart; telemetry: TelemetryClientStart; customDataService: DataPublicPluginStart; topValuesPopover: TopValuesPopoverService; @@ -178,6 +179,7 @@ export interface PluginStart { setIsILMAvailable: (isILMAvailable: boolean) => void; setIsSidebarEnabled: (isSidebarEnabled: boolean) => void; setGetStartedPage: (getStartedComponent: React.ComponentType) => void; + setDashboardsLandingCallout: (dashboardsLandingCallout: React.ComponentType) => void; getBreadcrumbsNav$: () => Observable; getUpselling: () => UpsellingService; } diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index c039895eaaef5..d0d55753ba336 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -46,6 +46,7 @@ import type { AppFeaturesService } from '../lib/app_features_service/app_feature export interface EndpointAppContextServiceSetupContract { securitySolutionRequestContextFactory: IRequestContextFactory; + cloud: CloudSetup; } export interface EndpointAppContextServiceStartContract { @@ -68,7 +69,6 @@ export interface EndpointAppContextServiceStartContract { experimentalFeatures: ExperimentalFeatures; messageSigningService: MessageSigningServiceInterface | undefined; actionCreateService: ActionCreateService | undefined; - cloud: CloudSetup; esClient: ElasticsearchClient; appFeaturesService: AppFeaturesService; } @@ -102,7 +102,6 @@ export class EndpointAppContextService { logger, manifestManager, alerting, - cloud, licenseService, exceptionListsClient, featureUsageService, @@ -120,7 +119,7 @@ export class EndpointAppContextService { alerting, licenseService, exceptionListsClient, - cloud, + this.setupDependencies.cloud, appFeaturesService ) ); @@ -137,7 +136,7 @@ export class EndpointAppContextService { licenseService, featureUsageService, endpointMetadataService, - cloud, + this.setupDependencies.cloud, esClient, appFeaturesService ) diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 73beb5aea6838..0cd5c02a770ec 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -132,6 +132,7 @@ export const createMockEndpointAppContextServiceSetupContract = (): jest.Mocked => { return { securitySolutionRequestContextFactory: requestContextFactoryMock.create(), + cloud: cloudMock.createSetup(), }; }; @@ -213,7 +214,6 @@ export const createMockEndpointAppContextServiceStartContract = >(), exceptionListsClient: listMock.getExceptionListClient(), cases: casesMock, - cloud: cloudMock.createSetup(), featureUsageService: createFeatureUsageServiceMock(), experimentalFeatures, messageSigningService: createMessageSigningServiceMock(), diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 4ba3d0a2cbc07..65d66e4fde644 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -190,6 +190,7 @@ export class Plugin implements ISecuritySolutionPlugin { this.endpointAppContextService.setup({ securitySolutionRequestContextFactory: requestContextFactory, + cloud: plugins.cloud, }); initUsageCollectors({ @@ -520,7 +521,6 @@ export class Plugin implements ISecuritySolutionPlugin { manifestManager, registerIngestCallback, licenseService, - cloud: plugins.cloud, exceptionListsClient: exceptionListClient, registerListsServerExtension: this.lists?.registerExtension, featureUsageService, diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 8355537470d67..5452acb5e6f0c 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -149,7 +149,6 @@ "@kbn/expandable-flyout", "@kbn/securitysolution-grouping", "@kbn/securitysolution-data-table", - "@kbn/saved-objects-management-plugin", "@kbn/core-analytics-server", "@kbn/analytics-client", "@kbn/security-solution-side-nav", @@ -172,6 +171,7 @@ "@kbn/core-logging-server-mocks", "@kbn/core-lifecycle-browser", "@kbn/security-solution-features", - "@kbn/handlebars" + "@kbn/handlebars", + "@kbn/content-management-plugin" ] } diff --git a/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/dashboard_landing_callout.tsx b/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/dashboard_landing_callout.tsx new file mode 100644 index 0000000000000..43102f0e50ae3 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/dashboard_landing_callout.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCallOut } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { LinkAnchor } from '@kbn/security-solution-navigation/links'; +import { css } from '@emotion/react'; +import { ExternalPageName } from '../../navigation/links/constants'; + +const linkAnchorCss = css` + text-decoration: underline; +`; + +export const DashboardsLandingCalloutComponent: React.FC = () => { + return ( + + + + + ), + visualizationLibrary: ( + + + + ), + }} + /> + + } + /> + ); +}; + +DashboardsLandingCalloutComponent.displayName = 'DashboardsLandingCalloutComponent'; +export const DashboardsLandingCallout = React.memo(DashboardsLandingCalloutComponent); + +// eslint-disable-next-line import/no-default-export +export default DashboardsLandingCallout; diff --git a/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/index.tsx b/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/index.tsx new file mode 100644 index 0000000000000..207a6f122c98e --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/index.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { Services } from '../../common/services'; +import { ServicesProvider } from '../../common/services'; + +import { DashboardsLandingCallout } from './lazy'; + +export const getDashboardsLandingCallout = (services: Services): React.ComponentType => + function DashboardsLandingCalloutComponent() { + return ( + + + + ); + }; diff --git a/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/lazy.tsx b/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/lazy.tsx new file mode 100644 index 0000000000000..80ac8eacd281e --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout/lazy.tsx @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { lazy, Suspense } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; + +const DashboardsLandingCalloutLazy = lazy(() => import('./dashboard_landing_callout')); + +export const DashboardsLandingCallout = () => ( + }> + + +); diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts index 0d0b606976bfe..9c6073c028731 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/constants.ts @@ -32,6 +32,9 @@ export const SecurityPagePath = { export enum ExternalPageName { // Osquery osquery = 'osquery:', + // Analytics + maps = 'maps:', + visualize = 'visualize:', // Machine Learning // Ref: packages/default-nav/ml/default_navigation.ts mlOverview = 'ml:overview', diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts index 039ffcfda7dd2..643ec2e905298 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_links.ts @@ -53,10 +53,17 @@ export const projectSettingsNavCategories: ProjectLinkCategory[] = [ linkIds: [ ExternalPageName.cloudUsersAndRoles, ExternalPageName.cloudBilling, - ExternalPageName.integrationsSecurity, SecurityPageName.entityAnalyticsManagement, ], }, + { + type: LinkCategoryType.separator, + linkIds: [ + ExternalPageName.integrationsSecurity, + ExternalPageName.maps, + ExternalPageName.visualize, + ], + }, { type: LinkCategoryType.accordion, label: i18n.MANAGEMENT_CATEGORY_TITLE, @@ -181,4 +188,16 @@ export const projectSettingsNavLinks: ProjectNavigationLink[] = [ id: ExternalPageName.managementSettings, title: i18n.MANAGEMENT_SETTINGS_TITLE, }, + { + id: ExternalPageName.maps, + title: i18n.MAPS_TITLE, + description: i18n.MAPS_DESCRIPTION, + landingIcon: IconGraphLazy, + }, + { + id: ExternalPageName.visualize, + title: i18n.VISUALIZE_TITLE, + description: i18n.VISUALIZE_DESCRIPTION, + landingIcon: IconGraphLazy, + }, ]; diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_translations.ts b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_translations.ts index 036c3a350a74f..56ef414457dfa 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_translations.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/links/sections/project_settings_translations.ts @@ -174,3 +174,28 @@ export const OTHER_CATEGORY_TITLE = i18n.translate( defaultMessage: 'OTHER', } ); +export const MAPS_TITLE = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectSettings.maps.title', + { + defaultMessage: 'Maps', + } +); +export const MAPS_DESCRIPTION = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectSettings.maps.description', + { + defaultMessage: 'Plot geographic data', + } +); +export const VISUALIZE_TITLE = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectSettings.visualize.title', + { + defaultMessage: 'Visualize library', + } +); + +export const VISUALIZE_DESCRIPTION = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectSettings.visualize.description', + { + defaultMessage: 'Visualize library page', + } +); diff --git a/x-pack/plugins/security_solution_serverless/public/pages/project_settings.tsx b/x-pack/plugins/security_solution_serverless/public/pages/project_settings.tsx index 9c3f8e5012a67..71809249b266e 100644 --- a/x-pack/plugins/security_solution_serverless/public/pages/project_settings.tsx +++ b/x-pack/plugins/security_solution_serverless/public/pages/project_settings.tsx @@ -8,10 +8,10 @@ import React from 'react'; import { EuiHorizontalRule, EuiPageHeader, EuiSpacer } from '@elastic/eui'; import { - LandingLinksIcons, + LandingLinksIconsCategories, LandingLinksIconsCategoriesGroups, } from '@kbn/security-solution-navigation/landing_links'; -import type { AccordionLinkCategory } from '@kbn/security-solution-navigation'; +import type { AccordionLinkCategory, NavigationLink } from '@kbn/security-solution-navigation'; import { isAccordionLinkCategory, isSeparatorLinkCategory, @@ -25,13 +25,21 @@ export const ProjectSettingsRoute: React.FC = () => { const projectSettingsLink = useNavLink(SecurityPageName.projectSettings); const { links = [], categories = [], title } = projectSettingsLink ?? {}; - const iconLinkIds = - categories.find((category) => isSeparatorLinkCategory(category))?.linkIds ?? []; - const iconLinks = links.filter(({ id }) => iconLinkIds.includes(id)); + const iconLinks = categories.reduce((acc, category) => { + if (isSeparatorLinkCategory(category)) { + const categoryLinks = links.filter(({ id }) => category.linkIds.includes(id)); + + acc.push(...categoryLinks); + } + return acc; + }, []); const accordionCategories = (categories.filter((category) => isAccordionLinkCategory(category)) ?? []) as AccordionLinkCategory[]; + const separatorCategories = (categories.filter((category) => isSeparatorLinkCategory(category)) ?? + []) as AccordionLinkCategory[]; + return ( @@ -39,7 +47,7 @@ export const ProjectSettingsRoute: React.FC = () => { - + diff --git a/x-pack/plugins/security_solution_serverless/public/plugin.ts b/x-pack/plugins/security_solution_serverless/public/plugin.ts index 05ea3185ce43c..b562e16293c66 100644 --- a/x-pack/plugins/security_solution_serverless/public/plugin.ts +++ b/x-pack/plugins/security_solution_serverless/public/plugin.ts @@ -8,6 +8,7 @@ import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { getSecurityGetStartedComponent } from './get_started'; +import { getDashboardsLandingCallout } from './components/dashboards_landing_callout'; import type { SecuritySolutionServerlessPluginSetup, SecuritySolutionServerlessPluginStart, @@ -57,6 +58,7 @@ export class SecuritySolutionServerlessPlugin registerUpsellings(securitySolution.getUpselling(), this.config.productTypes, services); securitySolution.setGetStartedPage(getSecurityGetStartedComponent(services, productTypes)); + securitySolution.setDashboardsLandingCallout(getDashboardsLandingCallout(services)); securitySolution.setIsILMAvailable(false); configureNavigation(services, this.config); diff --git a/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.scss b/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.scss new file mode 100644 index 0000000000000..b74c06cd58030 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.scss @@ -0,0 +1,3 @@ +.apiKeySuccessPanel { + background-color: transparentize($euiColorSuccess, .9); +} diff --git a/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx b/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx index 07d93fb8bcfe2..07675f41e3f07 100644 --- a/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/api_key/api_key.tsx @@ -14,10 +14,9 @@ import { EuiIcon, EuiPanel, EuiSpacer, - EuiSplitPanel, EuiStep, EuiText, - EuiThemeProvider, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -29,9 +28,10 @@ import { useKibanaServices } from '../../hooks/use_kibana'; import { MANAGEMENT_API_KEYS } from '../../routes'; import { CreateApiKeyFlyout } from './create_api_key_flyout'; import { CreateApiKeyResponse } from './types'; +import './api_key.scss'; export const ApiKeyPanel = ({ setClientApiKey }: { setClientApiKey: (value: string) => void }) => { - const { cloud, http, userProfile } = useKibanaServices(); + const { http, userProfile } = useKibanaServices(); const [isFlyoutOpen, setIsFlyoutOpen] = useState(false); const { data } = useQuery({ queryKey: ['apiKey'], @@ -53,7 +53,7 @@ export const ApiKeyPanel = ({ setClientApiKey }: { setClientApiKey: (value: stri /> )} {apiKey ? ( - + ) : ( - - - {i18n.translate('xpack.serverlessSearch.apiKey.stepOneDescription', { - defaultMessage: 'Unique identifier for authentication and authorization. ', + +

+ {i18n.translate('xpack.serverlessSearch.apiKey.panel.title', { + defaultMessage: 'Prepare an API Key', })} - - - - - - - - setIsFlyoutOpen(true)} - > - - {i18n.translate('xpack.serverlessSearch.apiKey.newButtonLabel', { - defaultMessage: 'New', - })} - - - - - - - - {i18n.translate('xpack.serverlessSearch.apiKey.manageLabel', { - defaultMessage: 'Manage', +

+
+ + {i18n.translate('xpack.serverlessSearch.apiKey.panel.description', { + defaultMessage: + 'An API key is a private, unique identifier for authentication and authorization.', + })} + + + + + + + + setIsFlyoutOpen(true)} + > + + {i18n.translate('xpack.serverlessSearch.apiKey.newButtonLabel', { + defaultMessage: 'New', })} - - +
+ + + + + + + {i18n.translate('xpack.serverlessSearch.apiKey.manageLabel', { + defaultMessage: 'Manage', + })} + + + +
+ + + {!!data?.apiKeys && ( + + + + + + + 0 ? 'success' : 'warning'}> + {data.apiKeys.length} + + ), + }} + /> + - - - {!!data?.apiKeys && ( - - - - - - - 0 ? 'success' : 'warning'}> - {data.apiKeys.length} - - ), - }} - /> - - - - )} - - - + )} + + )} - - - - - - {i18n.translate('xpack.serverlessSearch.apiKey.stepTwoDescription', { - defaultMessage: 'Unique identifier for specific project. ', - })} - - - - - - - {cloud.cloudId} - - - - ); }; diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx index 0d1cf8efa67c8..28748db40cedb 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx @@ -10,7 +10,25 @@ import { ElasticsearchOverview as Overview } from './overview'; describe('', () => { beforeEach(() => { - core.http.fetch.mockResolvedValueOnce({ apiKeys: [] }); + core.http.fetch.mockImplementation((url) => { + let fetchedUrl: string; + if (typeof url === 'string') { + fetchedUrl = url; + } + + return new Promise((resolve, reject) => { + switch (fetchedUrl) { + case '/internal/serverless_search/api_keys': + resolve({ apiKeys: [] }); + return; + case '/internal/serverless_search/connectors': + resolve({}); + return; + default: + return reject(`unknown path requested ${fetchedUrl}`); + } + }); + }); }); test('renders without throwing an error', () => { @@ -33,7 +51,11 @@ describe('', () => { }); test('api key', () => { const { getByRole } = render(); - expect(getByRole('heading', { name: 'Store your API key and Cloud ID' })).toBeDefined(); + expect(getByRole('heading', { level: 2, name: 'Prepare an API Key' })).toBeDefined(); + }); + test('cloud id', () => { + const { getByRole } = render(); + expect(getByRole('heading', { name: 'Copy your connection details' })).toBeDefined(); }); test('configure client', () => { const { getByRole } = render(); diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.tsx index 0fb599c770044..ddcc4e08cce13 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.tsx @@ -9,11 +9,15 @@ import { EuiAvatar, EuiButtonEmpty, EuiCard, + EuiCodeBlock, EuiFlexGroup, EuiFlexItem, EuiPageTemplate, EuiPanel, + EuiSpacer, EuiText, + EuiThemeProvider, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { @@ -107,19 +111,71 @@ export const ElasticsearchOverview = () => { } - links={[ - { - href: docLinks.securityApis, - label: i18n.translate('xpack.serverlessSearch.configureClient.basicConfigLabel', { - defaultMessage: 'Basic configuration', - }), - }, - ]} + links={[]} title={i18n.translate('xpack.serverlessSearch.apiKey.title', { - defaultMessage: 'Store your API key and Cloud ID', + defaultMessage: 'Prepare an API Key', + })} + /> + + + + + +
+ {i18n.translate('xpack.serverlessSearch.cloudIdDetails.id.title', { + defaultMessage: 'Cloud ID', + })} +
+
+ + + + + {cloud.cloudId} + + + +
+ + +
+ {i18n.translate('xpack.serverlessSearch.cloudIdDetails.url.title', { + defaultMessage: 'Cloud URL', + })} +
+
+ + + + + {cloud.elasticsearchUrl} + + + +
+ + } + links={[]} + title={i18n.translate('xpack.serverlessSearch.cloudIdDetails.title', { + defaultMessage: 'Copy your connection details', })} />
diff --git a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts index d5f6fa883e4b5..d6a40ff10a642 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts @@ -33,7 +33,7 @@ export const OverviewStatusMetaDataCodec = t.interface({ monitorQueryId: t.string, configId: t.string, status: t.string, - location: t.string, + locationId: t.string, timestamp: t.string, ping: OverviewPingCodec, }); diff --git a/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts b/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts index fe019d4a07af5..51adff582c478 100644 --- a/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts +++ b/x-pack/plugins/synthetics/common/runtime_types/ping/ping.ts @@ -148,6 +148,7 @@ export const PingType = t.intersection([ timestamp: t.string, monitor: MonitorType, docId: t.string, + observer: ObserverCodec, }), t.partial({ '@timestamp': t.string, @@ -198,7 +199,6 @@ export const PingType = t.intersection([ uid: t.string, }), }), - observer: ObserverCodec, resolve: t.partial({ ip: t.string, rtt: t.partial({ @@ -263,37 +263,6 @@ export const PingStatusType = t.intersection([ export type PingStatus = t.TypeOf; -// Convenience function for tests etc that makes an empty ping -// object with the minimum of fields. -export const makePing = (f: { - docId?: string; - type?: string; - id?: string; - timestamp?: string; - ip?: string; - status?: string; - duration?: number; - location?: string; - name?: string; - url?: string; -}): Ping => { - return { - docId: f.docId || 'myDocId', - timestamp: f.timestamp || '2020-07-07T01:14:08Z', - monitor: { - id: f.id || 'myId', - type: f.type || 'myType', - ip: f.ip || '127.0.0.1', - status: f.status || 'up', - duration: { us: f.duration || 100000 }, - name: f.name, - check_group: 'myCheckGroup', - }, - ...(f.location ? { observer: { geo: { name: f.location } } } : {}), - ...(f.url ? { url: { full: f.url } } : {}), - }; -}; - export const PingsResponseType = t.type({ total: t.number, pings: t.array(PingType), diff --git a/x-pack/plugins/synthetics/e2e/synthetics/journeys/services/data/browser_docs.ts b/x-pack/plugins/synthetics/e2e/synthetics/journeys/services/data/browser_docs.ts index cbed9b9f259c3..22576524545c1 100644 --- a/x-pack/plugins/synthetics/e2e/synthetics/journeys/services/data/browser_docs.ts +++ b/x-pack/plugins/synthetics/e2e/synthetics/journeys/services/data/browser_docs.ts @@ -7,13 +7,13 @@ import { DocOverrides } from './sample_docs'; -export const getGeoData = (locationName?: string) => ({ +export const getGeoData = (locationName?: string, locationId?: string) => ({ observer: { geo: { name: locationName ?? 'North America - US Central', location: '41.8780, 93.0977', }, - name: locationName ?? 'North America - US Central', + name: locationId ?? 'us_central', }, }); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx index 2c0885c7d6258..ce6de294d7e60 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx @@ -65,10 +65,10 @@ export const MetricItem = ({ const [isPopoverOpen, setIsPopoverOpen] = useState(false); const isErrorPopoverOpen = useSelector(selectErrorPopoverState); const locationName = - useLocationName({ locationId: monitor.location?.id })?.label || monitor.location?.id; + useLocationName({ locationId: monitor.location.id })?.label || monitor.location?.id; const { status, timestamp, ping, configIdByLocation } = useStatusByLocationOverview( monitor.configId, - locationName + monitor.location.id ); const theme = useTheme(); @@ -116,7 +116,7 @@ export const MetricItem = ({ configId: monitor.configId, id: monitor.id, location: locationName, - locationId: monitor.location?.id, + locationId: monitor.location.id, }); } }} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.test.tsx index 8cf6ac4ac0971..c736d47846ada 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.test.tsx @@ -40,6 +40,7 @@ describe('Monitor Detail Flyout', () => { full: 'https://www.elastic.co', }, tags: ['tag1', 'tag2'], + observer: {}, }, }); jest.spyOn(statusByLocation, 'useStatusByLocation').mockReturnValue({ diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx index 16fdc7cd5a497..30a09853ba27f 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx @@ -120,34 +120,34 @@ describe('useMonitorsSortedByStatus', () => { [`test-monitor-1-${location2.label}`]: { configId: 'test-monitor-1', monitorQueryId: 'test-monitor-1', - location: location2.label, + locationId: location2.label, }, [`test-monitor-2-${location2.label}`]: { configId: 'test-monitor-2', monitorQueryId: 'test-monitor-2', - location: location2.label, + locationId: location2.label, }, [`test-monitor-3-${location2.label}`]: { configId: 'test-monitor-3', monitorQueryId: 'test-monitor-3', - location: location2.label, + locationId: location2.label, }, }, downConfigs: { [`test-monitor-1-${location1.label}`]: { configId: 'test-monitor-1', monitorQueryId: 'test-monitor-1', - location: location1.label, + locationId: location1.label, }, [`test-monitor-2-${location1.label}`]: { configId: 'test-monitor-2', monitorQueryId: 'test-monitor-2', - location: location1.label, + locationId: location1.label, }, [`test-monitor-3${location1.label}`]: { configId: 'test-monitor-3', monitorQueryId: 'test-monitor-3', - location: location1.label, + locationId: location1.label, }, }, pendingConfigs: { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx index 2148b7e5eeb30..fd4c353a1f91d 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx @@ -37,11 +37,11 @@ export function useMonitorsSortedByStatus() { const { downConfigs, pendingConfigs } = status; const downMonitorMap: Record = {}; - Object.values(downConfigs).forEach(({ location, configId }) => { + Object.values(downConfigs).forEach(({ locationId, configId }) => { if (downMonitorMap[configId]) { - downMonitorMap[configId].push(location); + downMonitorMap[configId].push(locationId); } else { - downMonitorMap[configId] = [location]; + downMonitorMap[configId] = [locationId]; } }); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts index 019e50d8cbe4d..46e39f6eb0e66 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts @@ -9,22 +9,22 @@ import { useSelector } from 'react-redux'; import { OverviewStatusState } from '../../../../common/runtime_types'; import { selectOverviewStatus } from '../state/overview_status'; -export function useStatusByLocationOverview(configId: string, locationName?: string) { +export function useStatusByLocationOverview(configId: string, locationId: string) { const { status } = useSelector(selectOverviewStatus); - return getConfigStatusByLocation(status, configId, locationName); + return getConfigStatusByLocation(status, configId, locationId); } export const getConfigStatusByLocation = ( status: OverviewStatusState | null, configId: string, - locationName?: string + locationId: string ) => { - if (!locationName || !status) { + if (!status) { return { status: 'unknown' }; } const allConfigs = status.allConfigs; - const configIdByLocation = `${configId}-${locationName}`; + const configIdByLocation = `${configId}-${locationId}`; const config = allConfigs[configIdByLocation]; return { diff --git a/x-pack/plugins/synthetics/server/alert_rules/common.test.ts b/x-pack/plugins/synthetics/server/alert_rules/common.test.ts index f58eb9e4ce3c3..2edcd37a95927 100644 --- a/x-pack/plugins/synthetics/server/alert_rules/common.test.ts +++ b/x-pack/plugins/synthetics/server/alert_rules/common.test.ts @@ -202,7 +202,7 @@ describe('setRecoveredAlertsContext', () => { configId, monitorQueryId: 'stale-config', status: 'up', - location: '', + locationId: '', ping: { '@timestamp': new Date().toISOString(), state: { @@ -235,7 +235,7 @@ describe('setRecoveredAlertsContext', () => { configId, monitorQueryId: 'stale-config', status: 'down', - location: 'location', + locationId: 'location', ping: { '@timestamp': new Date().toISOString(), state: { @@ -294,7 +294,7 @@ describe('setRecoveredAlertsContext', () => { configId, monitorQueryId: 'stale-config', status: 'down', - location: 'location', + locationId: 'location', ping: { '@timestamp': new Date().toISOString(), state: { @@ -355,7 +355,7 @@ describe('setRecoveredAlertsContext', () => { configId, monitorQueryId: 'stale-config', status: 'down', - location: 'location', + locationId: 'location', ping: { state: { id: '123456', diff --git a/x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts b/x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts index 61173f7b0c227..dde24f409b0e3 100644 --- a/x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts +++ b/x-pack/plugins/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts @@ -93,7 +93,7 @@ export const registerSyntheticsStatusCheckRule = ( ); Object.entries(downConfigs).forEach(([idWithLocation, { ping, configId }]) => { - const locationId = statusRule.getLocationId(ping.observer?.geo?.name!) ?? ''; + const locationId = ping.observer.name ?? ''; const alertId = idWithLocation; const monitorSummary = getMonitorSummary( ping, diff --git a/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.test.ts b/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.test.ts index bb9183b661b04..ff8ecebccf968 100644 --- a/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.test.ts +++ b/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.test.ts @@ -97,7 +97,7 @@ describe('StatusRuleExecutor', () => { const staleDownConfigs = await statusRule.markDeletedConfigs({ id1: { - location: 'us-east-1', + locationId: 'us-east-1', configId: 'id1', status: 'down', timestamp: '2021-06-01T00:00:00.000Z', @@ -105,7 +105,7 @@ describe('StatusRuleExecutor', () => { ping: {} as any, }, '2548dab3-4752-4b4d-89a2-ae3402b6fb04-us_central_dev': { - location: 'US Central DEV', + locationId: 'us_central_dev', configId: '2548dab3-4752-4b4d-89a2-ae3402b6fb04', status: 'down', timestamp: '2021-06-01T00:00:00.000Z', @@ -113,7 +113,7 @@ describe('StatusRuleExecutor', () => { ping: {} as any, }, '2548dab3-4752-4b4d-89a2-ae3402b6fb04-us_central_qa': { - location: 'US Central QA', + locationId: 'us_central_qa', configId: '2548dab3-4752-4b4d-89a2-ae3402b6fb04', status: 'down', timestamp: '2021-06-01T00:00:00.000Z', @@ -126,7 +126,7 @@ describe('StatusRuleExecutor', () => { id1: { configId: 'id1', isDeleted: true, - location: 'us-east-1', + locationId: 'us-east-1', monitorQueryId: 'test', ping: {}, status: 'down', @@ -135,7 +135,7 @@ describe('StatusRuleExecutor', () => { '2548dab3-4752-4b4d-89a2-ae3402b6fb04-us_central_dev': { configId: '2548dab3-4752-4b4d-89a2-ae3402b6fb04', isLocationRemoved: true, - location: 'US Central DEV', + locationId: 'us_central_dev', monitorQueryId: 'test', ping: {}, status: 'down', @@ -175,7 +175,7 @@ describe('StatusRuleExecutor', () => { const staleDownConfigs = await statusRule.markDeletedConfigs({ id1: { - location: 'us-east-1', + locationId: 'us-east-1', configId: 'id1', status: 'down', timestamp: '2021-06-01T00:00:00.000Z', @@ -183,7 +183,7 @@ describe('StatusRuleExecutor', () => { ping: {} as any, }, '2548dab3-4752-4b4d-89a2-ae3402b6fb04-us_central_dev': { - location: 'US Central DEV', + locationId: 'us_central_dev', configId: '2548dab3-4752-4b4d-89a2-ae3402b6fb04', status: 'down', timestamp: '2021-06-01T00:00:00.000Z', @@ -191,7 +191,7 @@ describe('StatusRuleExecutor', () => { ping: {} as any, }, '2548dab3-4752-4b4d-89a2-ae3402b6fb04-us_central_qa': { - location: 'US Central QA', + locationId: 'us_central_qa', configId: '2548dab3-4752-4b4d-89a2-ae3402b6fb04', status: 'down', timestamp: '2021-06-01T00:00:00.000Z', @@ -204,7 +204,7 @@ describe('StatusRuleExecutor', () => { id1: { configId: 'id1', isDeleted: true, - location: 'us-east-1', + locationId: 'us-east-1', monitorQueryId: 'test', ping: {}, status: 'down', @@ -213,7 +213,7 @@ describe('StatusRuleExecutor', () => { '2548dab3-4752-4b4d-89a2-ae3402b6fb04-us_central_dev': { configId: '2548dab3-4752-4b4d-89a2-ae3402b6fb04', isLocationRemoved: true, - location: 'US Central DEV', + locationId: 'us_central_dev', monitorQueryId: 'test', ping: {}, status: 'down', diff --git a/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts b/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts index 2bb27ddb4a23b..0861b29c8134d 100644 --- a/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts +++ b/x-pack/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts @@ -13,7 +13,6 @@ import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { SyntheticsServerSetup } from '../../types'; import { UptimeEsClient } from '../../lib'; import { SYNTHETICS_INDEX_PATTERN } from '../../../common/constants'; -import { getAllLocations } from '../../synthetics_service/get_all_locations'; import { getAllMonitors, processMonitors, @@ -49,8 +48,6 @@ export class StatusRuleExecutor { syntheticsMonitorClient: SyntheticsMonitorClient; monitors: Array> = []; - public locationIdNameMap: Record = {}; - constructor( previousStartedAt: Date | null, p: StatusRuleParams, @@ -69,28 +66,7 @@ export class StatusRuleExecutor { this.syntheticsMonitorClient = syntheticsMonitorClient; } - async getAllLocationNames() { - const { publicLocations, privateLocations } = await getAllLocations({ - server: this.server, - syntheticsMonitorClient: this.syntheticsMonitorClient, - savedObjectsClient: this.soClient, - }); - - publicLocations.forEach((loc) => { - this.locationIdNameMap[loc.label] = loc.id; - }); - - privateLocations.forEach((loc) => { - this.locationIdNameMap[loc.label] = loc.id; - }); - } - - getLocationId(name: string) { - return this.locationIdNameMap[name]; - } - async getMonitors() { - await this.getAllLocationNames(); this.monitors = await getAllMonitors({ soClient: this.soClient, filter: `${monitorAttributes}.${AlertConfigKey.STATUS_ENABLED}: true`, @@ -99,20 +75,15 @@ export class StatusRuleExecutor { const { allIds, enabledMonitorQueryIds, - listOfLocations, + monitorLocationIds, monitorLocationMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, - } = await processMonitors( - this.monitors, - this.server, - this.soClient, - this.syntheticsMonitorClient - ); + } = processMonitors(this.monitors, this.server, this.soClient, this.syntheticsMonitorClient); return { enabledMonitorQueryIds, - listOfLocations, + monitorLocationIds, allIds, monitorLocationMap, projectMonitorsCount, @@ -124,7 +95,7 @@ export class StatusRuleExecutor { prevDownConfigs: OverviewStatus['downConfigs'] = {} ): Promise { const { - listOfLocations, + monitorLocationIds, enabledMonitorQueryIds, allIds, monitorLocationMap, @@ -138,7 +109,7 @@ export class StatusRuleExecutor { if (enabledMonitorQueryIds.length > 0) { const currentStatus = await queryMonitorStatus( this.esClient, - listOfLocations, + monitorLocationIds, { to: 'now', from, @@ -201,9 +172,7 @@ export class StatusRuleExecutor { delete downConfigs[locPlusId]; } else { const { locations } = monitor.attributes; - const isLocationRemoved = !locations.some( - (l) => l.id === this.getLocationId(downConfig.location) - ); + const isLocationRemoved = !locations.some((l) => l.id === downConfig.locationId); if (isLocationRemoved) { staleDownConfigs[locPlusId] = { ...downConfig, isLocationRemoved: true }; delete downConfigs[locPlusId]; diff --git a/x-pack/plugins/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts b/x-pack/plugins/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts index dbd97c2e0b51c..0ca15a53efc0a 100644 --- a/x-pack/plugins/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts +++ b/x-pack/plugins/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts @@ -70,20 +70,15 @@ export class TLSRuleExecutor { const { allIds, enabledMonitorQueryIds, - listOfLocations, + monitorLocationIds, monitorLocationMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, - } = await processMonitors( - this.monitors, - this.server, - this.soClient, - this.syntheticsMonitorClient - ); + } = processMonitors(this.monitors, this.server, this.soClient, this.syntheticsMonitorClient); return { enabledMonitorQueryIds, - listOfLocations, + monitorLocationIds, allIds, monitorLocationMap, projectMonitorsCount, diff --git a/x-pack/plugins/synthetics/server/queries/query_monitor_status.ts b/x-pack/plugins/synthetics/server/queries/query_monitor_status.ts index b714177e6cee9..e18e4f23b34c8 100644 --- a/x-pack/plugins/synthetics/server/queries/query_monitor_status.ts +++ b/x-pack/plugins/synthetics/server/queries/query_monitor_status.ts @@ -34,7 +34,7 @@ const fields = [ export async function queryMonitorStatus( esClient: UptimeEsClient, - listOfLocations: string[], + monitorLocationIds: string[], range: { from: string; to: string }, monitorQueryIds: string[], monitorLocationsMap: Record, @@ -50,7 +50,7 @@ export async function queryMonitorStatus( | 'allIds' > > { - const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / listOfLocations.length || 1); + const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / monitorLocationIds.length || 1); const pageCount = Math.ceil(monitorQueryIds.length / idSize); let up = 0; let down = 0; @@ -95,8 +95,8 @@ export async function queryMonitorStatus( aggs: { location: { terms: { - field: 'observer.geo.name', - size: listOfLocations.length || 100, + field: 'observer.name', + size: monitorLocationIds.length || 100, }, aggs: { status: { @@ -122,10 +122,10 @@ export async function queryMonitorStatus( }, }); - if (listOfLocations.length > 0) { + if (monitorLocationIds.length > 0) { params.body.query.bool.filter.push({ terms: { - 'observer.geo.name': listOfLocations, + 'observer.name': monitorLocationIds, }, }); } @@ -144,7 +144,7 @@ export async function queryMonitorStatus( // discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are // in monitorLocationsMap but not in listOfLocations const monLocations = monitorLocationsMap?.[queryId]; - const monQueriedLocations = intersection(monLocations, listOfLocations); + const monQueriedLocations = intersection(monLocations, monitorLocationIds); monQueriedLocations?.forEach((monLocation) => { const locationSummary = locationSummaries.find( (summary) => summary.location === monLocation @@ -154,14 +154,14 @@ export async function queryMonitorStatus( const { ping } = locationSummary; const downCount = ping.summary?.down ?? 0; const upCount = ping.summary?.up ?? 0; - const configId = ping.config_id!; + const configId = ping.config_id; const monitorQueryId = ping.monitor.id; const meta = { ping, configId, monitorQueryId, - location: monLocation, + locationId: monLocation, timestamp: ping['@timestamp'], }; diff --git a/x-pack/plugins/synthetics/server/routes/certs/get_certificates.ts b/x-pack/plugins/synthetics/server/routes/certs/get_certificates.ts index 982d9f60f90ff..405863865757d 100644 --- a/x-pack/plugins/synthetics/server/routes/certs/get_certificates.ts +++ b/x-pack/plugins/synthetics/server/routes/certs/get_certificates.ts @@ -57,7 +57,7 @@ export const getSyntheticsCertsRoute: SyntheticsRestApiRouteFactory< }; } - const { enabledMonitorQueryIds } = await processMonitors( + const { enabledMonitorQueryIds } = processMonitors( monitors, server, savedObjectsClient, diff --git a/x-pack/plugins/synthetics/server/routes/common.ts b/x-pack/plugins/synthetics/server/routes/common.ts index 84fa407296f09..b29e3578aba87 100644 --- a/x-pack/plugins/synthetics/server/routes/common.ts +++ b/x-pack/plugins/synthetics/server/routes/common.ts @@ -81,7 +81,7 @@ export const getMonitors = async ( monitorQueryIds, } = context.request.query; - const filterStr = await getMonitorFilters({ + const { filtersStr } = await getMonitorFilters({ filter, monitorTypes, tags, @@ -100,7 +100,7 @@ export const getMonitors = async ( sortOrder, searchFields: SEARCH_FIELDS, search: query ? `${query}*` : undefined, - filter: filterStr, + filter: filtersStr, searchAfter, fields, }; @@ -129,7 +129,7 @@ export const getMonitorFilters = async ({ }) => { const locationFilter = await parseLocationFilter(context, locations); - return [ + const filtersStr = [ filter, getKqlFilter({ field: 'tags', values: tags }), getKqlFilter({ field: 'project_id', values: projects }), @@ -140,6 +140,7 @@ export const getMonitorFilters = async ({ ] .filter((f) => !!f) .join(' AND '); + return { filtersStr, locationFilter }; }; export const getKqlFilter = ({ @@ -172,7 +173,7 @@ export const getKqlFilter = ({ const parseLocationFilter = async (context: RouteContext, locations?: string | string[]) => { if (!locations || locations?.length === 0) { - return ''; + return; } const { allLocations } = await getAllLocations(context); @@ -183,7 +184,7 @@ const parseLocationFilter = async (context: RouteContext, locations?: string | s .filter((val) => !!val); } - return findLocationItem(locations, allLocations)?.id ?? ''; + return [findLocationItem(locations, allLocations)?.id ?? '']; }; export const findLocationItem = ( diff --git a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts index 770fb102c5369..549c812eec27f 100644 --- a/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts +++ b/x-pack/plugins/synthetics/server/routes/monitor_cruds/get_monitor.ts @@ -91,7 +91,7 @@ export const getSyntheticsMonitorOverviewRoute: SyntheticsRestApiRouteFactory = locations: queriedLocations, } = request.query as MonitorsQuery; - const filtersStr = await getMonitorFilters({ + const { filtersStr } = await getMonitorFilters({ ...request.query, context: routeContext, }); diff --git a/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.test.ts b/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.test.ts index 983ae3cb3d854..02e5dfa61e2bc 100644 --- a/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.test.ts +++ b/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.test.ts @@ -15,39 +15,80 @@ import { EncryptedSyntheticsMonitorAttributes } from '../../../common/runtime_ty import { RouteContext } from '../types'; import { getUptimeESMockClient } from '../../legacy_uptime/lib/requests/test_helpers'; +import * as commonLibs from '../common'; +import { SyntheticsServerSetup } from '../../types'; +import { mockEncryptedSO } from '../../synthetics_service/utils/mocks'; +import { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; +import { loggerMock } from '@kbn/logging-mocks'; +import * as allLocationsFn from '../../synthetics_service/get_all_locations'; +const allLocations: any = [ + { + id: 'us_central_qa', + label: 'US Central QA', + }, + { + id: 'us_central', + label: 'North America - US Central', + }, +]; +jest.spyOn(allLocationsFn, 'getAllLocations').mockResolvedValue({ + publicLocations: allLocations, + privateLocations: [], + allLocations, +}); + jest.mock('../../saved_objects/synthetics_monitor/get_all_monitors', () => ({ ...jest.requireActual('../../saved_objects/synthetics_monitor/get_all_monitors'), getAllMonitors: jest.fn(), })); -jest.mock('../common', () => ({ - getMonitors: jest.fn().mockReturnValue({ - per_page: 10, - saved_objects: [ - { - id: 'mon-1', - attributes: { - enabled: false, - locations: ['us-east1', 'us-west1', 'japan'], - }, +jest.spyOn(commonLibs, 'getMonitors').mockResolvedValue({ + per_page: 10, + saved_objects: [ + { + id: 'mon-1', + attributes: { + enabled: false, + locations: [{ id: 'us-east1' }, { id: 'us-west1' }, { id: 'japan' }], }, - { - id: 'mon-2', - attributes: { - enabled: true, - locations: ['us-east1', 'us-west1', 'japan'], - schedule: { - number: '10', - unit: 'm', - }, + }, + { + id: 'mon-2', + attributes: { + enabled: true, + locations: [{ id: 'us-east1' }, { id: 'us-west1' }, { id: 'japan' }], + schedule: { + number: '10', + unit: 'm', }, }, - ], - }), - getMonitorFilters: () => '', -})); + }, + ], +} as any); describe('current status route', () => { + const logger = loggerMock.create(); + + const serverMock: SyntheticsServerSetup = { + logger, + config: { + service: { + username: 'dev', + password: '12345', + manifestUrl: 'http://localhost:8080/api/manifest', + }, + }, + spaces: { + spacesService: { + getSpaceId: jest.fn().mockReturnValue('test-space'), + }, + }, + encryptedSavedObjects: mockEncryptedSO(), + coreStart: { + savedObjects: savedObjectsServiceMock.createStartContract(), + }, + } as unknown as SyntheticsServerSetup; + describe('periodToMs', () => { it('returns 0 for unsupported unit type', () => { // @ts-expect-error Providing invalid value to test handler in function @@ -190,7 +231,7 @@ describe('current status route', () => { 'id1-Asia/Pacific - Japan': { configId: 'id1', monitorQueryId: 'id1', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', status: 'up', ping: expect.any(Object), timestamp: expect.any(String), @@ -198,7 +239,7 @@ describe('current status route', () => { 'id2-Asia/Pacific - Japan': { configId: 'id2', monitorQueryId: 'id2', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', status: 'up', ping: expect.any(Object), timestamp: expect.any(String), @@ -208,7 +249,7 @@ describe('current status route', () => { 'id2-Europe - Germany': { configId: 'id2', monitorQueryId: 'id2', - location: 'Europe - Germany', + locationId: 'Europe - Germany', status: 'down', ping: expect.any(Object), timestamp: expect.any(String), @@ -355,7 +396,7 @@ describe('current status route', () => { 'id1-Asia/Pacific - Japan': { configId: 'id1', monitorQueryId: 'id1', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', status: 'up', ping: expect.any(Object), timestamp: expect.any(String), @@ -363,7 +404,7 @@ describe('current status route', () => { 'id2-Asia/Pacific - Japan': { configId: 'id2', monitorQueryId: 'id2', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', status: 'up', ping: expect.any(Object), timestamp: expect.any(String), @@ -373,7 +414,7 @@ describe('current status route', () => { 'id2-Europe - Germany': { configId: 'id2', monitorQueryId: 'id2', - location: 'Europe - Germany', + locationId: 'Europe - Germany', status: 'down', ping: expect.any(Object), timestamp: expect.any(String), @@ -525,7 +566,7 @@ describe('current status route', () => { 'id1-Asia/Pacific - Japan': { configId: 'id1', monitorQueryId: 'id1', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', status: 'up', ping: expect.any(Object), timestamp: expect.any(String), @@ -533,7 +574,7 @@ describe('current status route', () => { 'id2-Asia/Pacific - Japan': { configId: 'id2', monitorQueryId: 'id2', - location: 'Asia/Pacific - Japan', + locationId: 'Asia/Pacific - Japan', status: 'up', ping: expect.any(Object), timestamp: expect.any(String), @@ -543,7 +584,7 @@ describe('current status route', () => { 'id2-Europe - Germany': { configId: 'id2', monitorQueryId: 'id2', - location: 'Europe - Germany', + locationId: 'Europe - Germany', status: 'down', ping: expect.any(Object), timestamp: expect.any(String), @@ -729,17 +770,17 @@ describe('current status route', () => { }, ]) ); - expect( - await getStatus( - { - uptimeEsClient, - savedObjectsClient: savedObjectsClientMock.create(), - } as unknown as RouteContext, - { - locations, - } - ) - ).toEqual( + const result = await getStatus( + { + uptimeEsClient, + savedObjectsClient: savedObjectsClientMock.create(), + server: serverMock, + } as unknown as RouteContext, + { + locations, + } + ); + expect(result).toEqual( expect.objectContaining({ disabledCount, }) diff --git a/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.ts b/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.ts index 4de7341d10626..7d28d9b4f0576 100644 --- a/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.ts +++ b/x-pack/plugins/synthetics/server/routes/overview_status/overview_status.ts @@ -38,9 +38,8 @@ export function periodToMs(schedule: { number: string; unit: Unit }) { export async function getStatus(context: RouteContext, params: OverviewStatusQuery) { const { uptimeEsClient, syntheticsMonitorClient, savedObjectsClient, server } = context; - const { query, locations: qLocations, scopeStatusByLocation = true } = params; + const { query, scopeStatusByLocation = true } = params; - const queryLocations = qLocations && !Array.isArray(qLocations) ? [qLocations] : qLocations; /** * Walk through all monitor saved objects, bucket IDs by disabled/enabled status. * @@ -48,7 +47,7 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue * latest ping for all enabled monitors. */ - const filtersStr = await getMonitorFilters({ + const { filtersStr, locationFilter: queryLocations } = await getMonitorFilters({ ...params, context, }); @@ -73,12 +72,12 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue allIds, disabledCount, maxPeriod, - listOfLocations, + monitorLocationIds, monitorLocationMap, disabledMonitorsCount, projectMonitorsCount, monitorQueryIdToConfigIdMap, - } = await processMonitors( + } = processMonitors( allMonitors, server, savedObjectsClient, @@ -89,8 +88,8 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue // Account for locations filter const listOfLocationAfterFilter = queryLocations && scopeStatusByLocation - ? intersection(listOfLocations, queryLocations) - : listOfLocations; + ? intersection(monitorLocationIds, queryLocations) + : monitorLocationIds; const range = { from: moment().subtract(maxPeriod, 'milliseconds').subtract(20, 'minutes').toISOString(), diff --git a/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts b/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts index 1d25503159c58..33af8075616da 100644 --- a/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts +++ b/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts @@ -45,7 +45,7 @@ describe('processMonitors', () => { const monitorClient = new SyntheticsMonitorClient(syntheticsService, serverMock); it('should return a processed data', async () => { - const result = await processMonitors(testMonitors, serverMock, soClient, monitorClient); + const result = processMonitors(testMonitors, serverMock, soClient, monitorClient); expect(result).toEqual({ allIds: [ 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22', @@ -60,15 +60,15 @@ describe('processMonitors', () => { '7f796001-a795-4c0b-afdb-3ce74edea775', ], disabledMonitorQueryIds: ['test-project-id-default'], - listOfLocations: ['US Central QA', 'US Central Staging', 'North America - US Central'], + monitorLocationIds: ['us_central_qa', 'us_central_staging', 'us_central'], maxPeriod: 600000, monitorLocationMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': [ - 'US Central QA', - 'North America - US Central', - 'US Central Staging', + 'us_central_qa', + 'us_central', + 'us_central_staging', ], - 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22': ['US Central QA', 'US Central Staging'], + 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22': ['us_central_qa', 'us_central_staging'], }, monitorQueryIdToConfigIdMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': '7f796001-a795-4c0b-afdb-3ce74edea775', @@ -81,7 +81,7 @@ describe('processMonitors', () => { it('should return a processed data where location label is missing', async () => { testMonitors[0].attributes.locations[0].label = undefined; - const result = await processMonitors(testMonitors, serverMock, soClient, monitorClient); + const result = processMonitors(testMonitors, serverMock, soClient, monitorClient); expect(result).toEqual({ allIds: [ 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22', @@ -96,20 +96,15 @@ describe('processMonitors', () => { '7f796001-a795-4c0b-afdb-3ce74edea775', ], disabledMonitorQueryIds: ['test-project-id-default'], - listOfLocations: [ - 'US Central Staging', - 'us_central_qa', - 'US Central QA', - 'North America - US Central', - ], + monitorLocationIds: ['us_central_qa', 'us_central_staging', 'us_central'], maxPeriod: 600000, monitorLocationMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': [ - 'US Central QA', - 'North America - US Central', - 'US Central Staging', + 'us_central_qa', + 'us_central', + 'us_central_staging', ], - 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22': ['US Central Staging', 'us_central_qa'], + 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22': ['us_central_qa', 'us_central_staging'], }, monitorQueryIdToConfigIdMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': '7f796001-a795-4c0b-afdb-3ce74edea775', @@ -160,7 +155,7 @@ describe('processMonitors', () => { ) ); - const result = await processMonitors(testMonitors, serverMock, soClient, monitorClient); + const result = processMonitors(testMonitors, serverMock, soClient, monitorClient); expect(result).toEqual({ allIds: [ 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22', @@ -175,15 +170,15 @@ describe('processMonitors', () => { '7f796001-a795-4c0b-afdb-3ce74edea775', ], disabledMonitorQueryIds: ['test-project-id-default'], - listOfLocations: ['US Central Staging', 'US Central QA', 'North America - US Central'], + monitorLocationIds: ['us_central_qa', 'us_central_staging', 'us_central'], maxPeriod: 600000, monitorLocationMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': [ - 'US Central QA', - 'North America - US Central', - 'US Central Staging', + 'us_central_qa', + 'us_central', + 'us_central_staging', ], - 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22': ['US Central Staging', 'US Central QA'], + 'aa925d91-40b0-4f8f-b695-bb9b53cd4e22': ['us_central_qa', 'us_central_staging'], }, monitorQueryIdToConfigIdMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': '7f796001-a795-4c0b-afdb-3ce74edea775', diff --git a/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts b/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts index 9e629ba304a14..b8e9a08bf3dd1 100644 --- a/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts +++ b/x-pack/plugins/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts @@ -10,16 +10,13 @@ import { SavedObjectsFindOptions, SavedObjectsFindResult, } from '@kbn/core-saved-objects-api-server'; -import pMap from 'p-map'; import { intersection } from 'lodash'; import { SyntheticsServerSetup } from '../../types'; import { syntheticsMonitorType } from '../../../common/types/saved_objects'; import { periodToMs } from '../../routes/overview_status/overview_status'; -import { getAllLocations } from '../../synthetics_service/get_all_locations'; import { ConfigKey, EncryptedSyntheticsMonitorAttributes, - ServiceLocation, SourceType, } from '../../../common/runtime_types'; import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; @@ -59,7 +56,7 @@ export const getAllMonitors = async ({ return hits; }; -export const processMonitors = async ( +export const processMonitors = ( allMonitors: Array>, server: SyntheticsServerSetup, soClient: SavedObjectsClientContract, @@ -83,22 +80,6 @@ export const processMonitors = async ( const monitorLocationMap: Record = {}; const monitorQueryIdToConfigIdMap: Record = {}; - let allLocations: ServiceLocation[] | null = null; - - const getLocationLabel = async (locationId: string) => { - if (!allLocations) { - const { publicLocations, privateLocations } = await getAllLocations({ - server, - syntheticsMonitorClient, - savedObjectsClient: soClient, - }); - - allLocations = [...publicLocations, ...privateLocations]; - } - - return allLocations.find((loc) => loc.id === locationId)?.label ?? locationId; - }; - for (const monitor of allMonitors) { const attrs = monitor.attributes; @@ -108,8 +89,9 @@ export const processMonitors = async ( monitorQueryIdToConfigIdMap[attrs[ConfigKey.MONITOR_QUERY_ID]] = attrs[ConfigKey.CONFIG_ID]; + const monitorLocations = attrs[ConfigKey.LOCATIONS].map((location) => location.id); + if (attrs[ConfigKey.ENABLED] === false) { - const monitorLocations = attrs[ConfigKey.LOCATIONS].map((location) => location.label); const queriedLocations = Array.isArray(queryLocations) ? queryLocations : [queryLocations]; const intersectingLocations = intersection( monitorLocations, @@ -119,32 +101,12 @@ export const processMonitors = async ( disabledMonitorsCount += 1; disabledMonitorQueryIds.push(attrs[ConfigKey.MONITOR_QUERY_ID]); } else { - const missingLabels = new Set(); - enabledMonitorQueryIds.push(attrs[ConfigKey.MONITOR_QUERY_ID]); - const monLocs = new Set([ - ...(attrs[ConfigKey.LOCATIONS] - .filter((loc) => { - if (!loc.label) { - missingLabels.add(loc.id); - } - return loc.label; - }) - .map((location) => location.label) as string[]), - ]); - - // since label wasn't always part of location, there can be a case where we have a location - // with an id but no label. We need to fetch the label from the API - // Adding a migration to add the label to the saved object is a future consideration - const locLabels = await pMap([...missingLabels], async (locationId) => - getLocationLabel(locationId) - ); - const monitorLocations = [...monLocs, ...locLabels]; monitorLocationMap[attrs[ConfigKey.MONITOR_QUERY_ID]] = queryLocations ? intersection(monitorLocations, queryLocations) : monitorLocations; - listOfLocationsSet = new Set([...listOfLocationsSet, ...monLocs, ...locLabels]); + listOfLocationsSet = new Set([...listOfLocationsSet, ...monitorLocations]); maxPeriod = Math.max(maxPeriod, periodToMs(attrs[ConfigKey.SCHEDULE])); } @@ -159,7 +121,7 @@ export const processMonitors = async ( monitorLocationMap, disabledMonitorsCount, projectMonitorsCount, - listOfLocations: [...listOfLocationsSet], + monitorLocationIds: [...listOfLocationsSet], monitorQueryIdToConfigIdMap, }; }; diff --git a/x-pack/plugins/transform/common/api_schemas/transforms.ts b/x-pack/plugins/transform/common/api_schemas/transforms.ts index 5b300a613be94..65e0433a81264 100644 --- a/x-pack/plugins/transform/common/api_schemas/transforms.ts +++ b/x-pack/plugins/transform/common/api_schemas/transforms.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { schema, TypeOf } from '@kbn/config-schema'; +import { schema, type TypeOf } from '@kbn/config-schema'; import type { ES_FIELD_TYPES } from '@kbn/field-types'; diff --git a/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts b/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts index 459d37414e244..a9d177a341e21 100644 --- a/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts +++ b/x-pack/plugins/transform/common/api_schemas/transforms_stats.ts @@ -13,7 +13,7 @@ import { getTransformsRequestSchema } from './transforms'; export const getTransformsStatsRequestSchema = getTransformsRequestSchema; -export type GetTransformsRequestSchema = TypeOf; +export type GetTransformsStatsRequestSchema = TypeOf; export interface GetTransformsStatsResponseSchema { node_failures?: object; diff --git a/x-pack/plugins/transform/common/api_schemas/type_guards.ts b/x-pack/plugins/transform/common/api_schemas/type_guards.ts deleted file mode 100644 index d5dbad0056c35..0000000000000 --- a/x-pack/plugins/transform/common/api_schemas/type_guards.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; - -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; - -import type { EsIndex } from '../types/es_index'; -import type { EsIngestPipeline } from '../types/es_ingest_pipeline'; - -// To be able to use the type guards on the client side, we need to make sure we don't import -// the code of '@kbn/config-schema' but just its types, otherwise the client side code will -// fail to build. -import type { FieldHistogramsResponseSchema } from './field_histograms'; -import type { GetTransformsAuditMessagesResponseSchema } from './audit_messages'; -import type { DeleteTransformsResponseSchema } from './delete_transforms'; -import type { ResetTransformsResponseSchema } from './reset_transforms'; -import type { StartTransformsResponseSchema } from './start_transforms'; -import type { StopTransformsResponseSchema } from './stop_transforms'; -import type { ScheduleNowTransformsResponseSchema } from './schedule_now_transforms'; -import type { - GetTransformNodesResponseSchema, - GetTransformsResponseSchema, - PostTransformsPreviewResponseSchema, - PutTransformsResponseSchema, -} from './transforms'; -import type { GetTransformsStatsResponseSchema } from './transforms_stats'; -import type { PostTransformsUpdateResponseSchema } from './update_transforms'; - -const isGenericResponseSchema = (arg: any): arg is T => { - return isPopulatedObject(arg, ['count', 'transforms']) && Array.isArray(arg.transforms); -}; - -export const isGetTransformNodesResponseSchema = ( - arg: unknown -): arg is GetTransformNodesResponseSchema => { - return isPopulatedObject(arg, ['count']) && typeof arg.count === 'number'; -}; - -export const isGetTransformsResponseSchema = (arg: unknown): arg is GetTransformsResponseSchema => { - return isGenericResponseSchema(arg); -}; - -export const isGetTransformsStatsResponseSchema = ( - arg: unknown -): arg is GetTransformsStatsResponseSchema => { - return isGenericResponseSchema(arg); -}; - -export const isDeleteTransformsResponseSchema = ( - arg: unknown -): arg is DeleteTransformsResponseSchema => { - return ( - isPopulatedObject(arg) && - Object.values(arg).every((d) => isPopulatedObject(d, ['transformDeleted'])) - ); -}; - -export const isResetTransformsResponseSchema = ( - arg: unknown -): arg is ResetTransformsResponseSchema => { - return ( - isPopulatedObject(arg) && - Object.values(arg).every((d) => isPopulatedObject(d, ['transformReset'])) - ); -}; - -export const isEsIndices = (arg: unknown): arg is EsIndex[] => { - return Array.isArray(arg); -}; - -export const isEsIngestPipelines = (arg: unknown): arg is EsIngestPipeline[] => { - return Array.isArray(arg) && arg.every((d) => isPopulatedObject(d, ['name'])); -}; - -export const isEsSearchResponse = (arg: unknown): arg is estypes.SearchResponse => { - return isPopulatedObject(arg, ['hits']); -}; - -type SearchResponseWithAggregations = Required> & - estypes.SearchResponse; -export const isEsSearchResponseWithAggregations = ( - arg: unknown -): arg is SearchResponseWithAggregations => { - return isEsSearchResponse(arg) && {}.hasOwnProperty.call(arg, 'aggregations'); -}; - -export const isFieldHistogramsResponseSchema = ( - arg: unknown -): arg is FieldHistogramsResponseSchema => { - return Array.isArray(arg); -}; - -export const isGetTransformsAuditMessagesResponseSchema = ( - arg: unknown -): arg is GetTransformsAuditMessagesResponseSchema => { - return isPopulatedObject(arg, ['messages', 'total']); -}; - -export const isPostTransformsPreviewResponseSchema = ( - arg: unknown -): arg is PostTransformsPreviewResponseSchema => { - return ( - isPopulatedObject(arg, ['generated_dest_index', 'preview']) && - typeof arg.generated_dest_index !== undefined && - Array.isArray(arg.preview) - ); -}; - -export const isPostTransformsUpdateResponseSchema = ( - arg: unknown -): arg is PostTransformsUpdateResponseSchema => { - return isPopulatedObject(arg, ['id']) && typeof arg.id === 'string'; -}; - -export const isPutTransformsResponseSchema = (arg: unknown): arg is PutTransformsResponseSchema => { - return ( - isPopulatedObject(arg, ['transformsCreated', 'errors']) && - Array.isArray(arg.transformsCreated) && - Array.isArray(arg.errors) - ); -}; - -const isGenericSuccessResponseSchema = (arg: unknown) => - isPopulatedObject(arg) && Object.values(arg).every((d) => isPopulatedObject(d, ['success'])); - -export const isStartTransformsResponseSchema = ( - arg: unknown -): arg is StartTransformsResponseSchema => { - return isGenericSuccessResponseSchema(arg); -}; - -export const isStopTransformsResponseSchema = ( - arg: unknown -): arg is StopTransformsResponseSchema => { - return isGenericSuccessResponseSchema(arg); -}; - -export const isScheduleNowTransformsResponseSchema = ( - arg: unknown -): arg is ScheduleNowTransformsResponseSchema => { - return isGenericSuccessResponseSchema(arg); -}; diff --git a/x-pack/plugins/transform/common/constants.ts b/x-pack/plugins/transform/common/constants.ts index 633f0dc7849ac..a1ba2d8277af9 100644 --- a/x-pack/plugins/transform/common/constants.ts +++ b/x-pack/plugins/transform/common/constants.ts @@ -32,6 +32,21 @@ const EXTERNAL_API_BASE_PATH = '/api/transform/'; export const addInternalBasePath = (uri: string): string => `${INTERNAL_API_BASE_PATH}${uri}`; export const addExternalBasePath = (uri: string): string => `${EXTERNAL_API_BASE_PATH}${uri}`; +export const TRANSFORM_REACT_QUERY_KEYS = { + DATA_SEARCH: 'transform.data_search', + DATA_VIEW_EXISTS: 'transform.data_view_exists', + GET_DATA_VIEW_TITLES: 'transform.get_data_view_titles', + GET_ES_INDICES: 'transform.get_es_indices', + GET_ES_INGEST_PIPELINES: 'transform.get_es_ingest_pipelines', + GET_HISTOGRAMS_FOR_FIELDS: 'transform.get_histograms_for_fields', + GET_TRANSFORM: 'transform.get_transform', + GET_TRANSFORM_NODES: 'transform.get_transform_nodes', + GET_TRANSFORM_AUDIT_MESSAGES: 'transform.get_transform_audit_messages', + GET_TRANSFORM_STATS: 'transform.get_transform_stats', + GET_TRANSFORMS: 'transform.get_transforms', + GET_TRANSFORMS_PREVIEW: 'transform.get_transforms_preview', +} as const; + // In order to create a transform, the API requires the following privileges: // - transform_admin (builtin) // - cluster privileges: manage_transform @@ -71,22 +86,6 @@ export const APP_CLUSTER_PRIVILEGES = [ // Minimum privileges required to return transform node count export const NODES_INFO_PRIVILEGES = ['cluster:monitor/transform/get']; -// Equivalent of capabilities.canGetTransform -export const APP_GET_TRANSFORM_CLUSTER_PRIVILEGES = [ - 'cluster.cluster:monitor/transform/get', - 'cluster.cluster:monitor/transform/stats/get', -]; - -// Equivalent of capabilities.canCreateTransform -export const APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES = [ - 'cluster.cluster:monitor/transform/get', - 'cluster.cluster:monitor/transform/stats/get', - 'cluster.cluster:admin/transform/preview', - 'cluster.cluster:admin/transform/put', - 'cluster.cluster:admin/transform/start', - 'cluster.cluster:admin/transform/start_task', -]; - export const APP_INDEX_PRIVILEGES = ['monitor']; // reflects https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/transforms/TransformStats.java#L214 diff --git a/x-pack/plugins/transform/common/privilege/has_privilege_factory.ts b/x-pack/plugins/transform/common/privilege/has_privilege_factory.ts deleted file mode 100644 index 9dee0c1a73cf1..0000000000000 --- a/x-pack/plugins/transform/common/privilege/has_privilege_factory.ts +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; -import { isPopulatedObject } from '@kbn/ml-is-populated-object'; - -import { cloneDeep } from 'lodash'; -import { APP_INDEX_PRIVILEGES } from '../constants'; -import { Privileges } from '../types/privileges'; - -export interface PrivilegesAndCapabilities { - privileges: Privileges; - capabilities: Capabilities; -} - -export interface TransformCapabilities { - canGetTransform: boolean; - canDeleteTransform: boolean; - canPreviewTransform: boolean; - canCreateTransform: boolean; - canReauthorizeTransform: boolean; - canScheduleNowTransform: boolean; - canStartStopTransform: boolean; - canCreateTransformAlerts: boolean; - canUseTransformAlerts: boolean; - canResetTransform: boolean; -} -export type Capabilities = { [k in keyof TransformCapabilities]: boolean }; - -export const INITIAL_CAPABILITIES = Object.freeze({ - canGetTransform: false, - canDeleteTransform: false, - canPreviewTransform: false, - canCreateTransform: false, - canReauthorizeTransform: false, - canScheduleNowTransform: false, - canStartStopTransform: false, - canCreateTransformAlerts: false, - canUseTransformAlerts: false, - canResetTransform: false, -}); - -export type Privilege = [string, string]; - -function isPrivileges(arg: unknown): arg is Privileges { - return ( - isPopulatedObject(arg, ['hasAllPrivileges', 'missingPrivileges']) && - typeof arg.hasAllPrivileges === 'boolean' && - typeof arg.missingPrivileges === 'object' && - arg.missingPrivileges !== null - ); -} - -export const toArray = (value: string | string[]): string[] => - Array.isArray(value) ? value : [value]; - -export const hasPrivilegeFactory = - (privileges: Privileges | undefined | null) => (privilege: Privilege) => { - const [section, requiredPrivilege] = privilege; - if (isPrivileges(privileges) && !privileges.missingPrivileges[section]) { - // if the section does not exist in our missingPrivileges, everything is OK - return true; - } - if (isPrivileges(privileges) && privileges.missingPrivileges[section]!.length === 0) { - return true; - } - if (requiredPrivilege === '*') { - // If length > 0 and we require them all... KO - return false; - } - // If we require _some_ privilege, we make sure that the one - // we require is *not* in the missingPrivilege array - return ( - isPrivileges(privileges) && - !privileges.missingPrivileges[section]!.includes(requiredPrivilege) - ); - }; - -export const extractMissingPrivileges = ( - privilegesObject: { [key: string]: boolean } = {} -): string[] => - Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { - if (!privilegesObject[privilegeName]) { - privileges.push(privilegeName); - } - return privileges; - }, []); - -export const getPrivilegesAndCapabilities = ( - clusterPrivileges: Record, - hasOneIndexWithAllPrivileges: boolean, - hasAllPrivileges: boolean -): PrivilegesAndCapabilities => { - const privilegesResult: Privileges = { - hasAllPrivileges: true, - missingPrivileges: { - cluster: [], - index: [], - }, - }; - - // Find missing cluster privileges and set overall app privileges - privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(clusterPrivileges); - privilegesResult.hasAllPrivileges = hasAllPrivileges; - - if (!hasOneIndexWithAllPrivileges) { - privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; - } - - const hasPrivilege = hasPrivilegeFactory(privilegesResult); - - const capabilities = cloneDeep(INITIAL_CAPABILITIES); - capabilities.canGetTransform = - hasPrivilege(['cluster', 'cluster:monitor/transform/get']) && - hasPrivilege(['cluster', 'cluster:monitor/transform/stats/get']); - - capabilities.canCreateTransform = hasPrivilege(['cluster', 'cluster:admin/transform/put']); - - capabilities.canDeleteTransform = hasPrivilege(['cluster', 'cluster:admin/transform/delete']); - - capabilities.canResetTransform = hasPrivilege(['cluster', 'cluster:admin/transform/reset']); - - capabilities.canPreviewTransform = hasPrivilege(['cluster', 'cluster:admin/transform/preview']); - - capabilities.canStartStopTransform = - hasPrivilege(['cluster', 'cluster:admin/transform/start']) && - hasPrivilege(['cluster', 'cluster:admin/transform/start_task']) && - hasPrivilege(['cluster', 'cluster:admin/transform/stop']); - - capabilities.canCreateTransformAlerts = capabilities.canCreateTransform; - - capabilities.canUseTransformAlerts = capabilities.canGetTransform; - - capabilities.canScheduleNowTransform = capabilities.canStartStopTransform; - - capabilities.canReauthorizeTransform = capabilities.canStartStopTransform; - - return { privileges: privilegesResult, capabilities }; -}; -// create the text for button's tooltips if the user -// doesn't have the permission to press that button -export function createCapabilityFailureMessage( - capability: keyof TransformCapabilities | 'noTransformNodes' -) { - let message = ''; - - switch (capability) { - case 'canCreateTransform': - message = i18n.translate('xpack.transform.capability.noPermission.createTransformTooltip', { - defaultMessage: 'You do not have permission to create transforms.', - }); - break; - case 'canCreateTransformAlerts': - message = i18n.translate( - 'xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip', - { - defaultMessage: 'You do not have permission to create transform alert rules.', - } - ); - break; - case 'canScheduleNowTransform': - message = i18n.translate( - 'xpack.transform.capability.noPermission.scheduleNowTransformTooltip', - { - defaultMessage: - 'You do not have permission to schedule transforms to process data instantly.', - } - ); - break; - case 'canStartStopTransform': - message = i18n.translate( - 'xpack.transform.capability.noPermission.startOrStopTransformTooltip', - { - defaultMessage: 'You do not have permission to start or stop transforms.', - } - ); - break; - - case 'canReauthorizeTransform': - message = i18n.translate( - 'xpack.transform.capability.noPermission.reauthorizeTransformTooltip', - { - defaultMessage: 'You do not have permission to reauthorize transforms.', - } - ); - break; - - case 'canDeleteTransform': - message = i18n.translate('xpack.transform.capability.noPermission.deleteTransformTooltip', { - defaultMessage: 'You do not have permission to delete transforms.', - }); - break; - - case 'canResetTransform': - message = i18n.translate('xpack.transform.capability.noPermission.resetTransformTooltip', { - defaultMessage: 'You do not have permission to reset transforms.', - }); - break; - - case 'noTransformNodes': - message = i18n.translate('xpack.transform.capability.noPermission.noTransformNodesTooltip', { - defaultMessage: 'There are no transform nodes available.', - }); - break; - } - - return i18n.translate('xpack.transform.capability.pleaseContactAdministratorTooltip', { - defaultMessage: '{message} Please contact your administrator.', - values: { - message, - }, - }); -} diff --git a/x-pack/plugins/transform/common/types/capabilities.ts b/x-pack/plugins/transform/common/types/capabilities.ts new file mode 100644 index 0000000000000..ae5e241e3b0fe --- /dev/null +++ b/x-pack/plugins/transform/common/types/capabilities.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 { isPopulatedObject } from '@kbn/ml-is-populated-object'; + +export const getInitialTransformCapabilities = (initialSetting = false) => ({ + canCreateTransform: initialSetting, + canCreateTransformAlerts: initialSetting, + canDeleteIndex: initialSetting, + canDeleteTransform: initialSetting, + canGetTransform: initialSetting, + canPreviewTransform: initialSetting, + canReauthorizeTransform: initialSetting, + canResetTransform: initialSetting, + canScheduleNowTransform: initialSetting, + canStartStopTransform: initialSetting, + canUseTransformAlerts: initialSetting, +}); + +export const isTransformCapabilities = (arg: unknown): arg is TransformCapabilities => { + return ( + isPopulatedObject(arg, Object.keys(getInitialTransformCapabilities())) && + Object.values(arg).every((d) => typeof d === 'boolean') + ); +}; + +export type TransformCapabilities = ReturnType; +export type TransformCapability = keyof TransformCapabilities; + +export interface PrivilegesAndCapabilities { + privileges: Privileges; + capabilities: TransformCapabilities; +} + +export type Privilege = [string, string]; + +export interface MissingPrivileges { + [key: string]: string[] | undefined; +} + +export interface Privileges { + hasAllPrivileges: boolean; + missingPrivileges: MissingPrivileges; +} diff --git a/x-pack/plugins/transform/common/utils/create_capability_failure_message.ts b/x-pack/plugins/transform/common/utils/create_capability_failure_message.ts new file mode 100644 index 0000000000000..7f0f660bd2514 --- /dev/null +++ b/x-pack/plugins/transform/common/utils/create_capability_failure_message.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +import type { TransformCapabilities } from '../types/capabilities'; + +// create the text for button's tooltips if the user +// doesn't have the permission to press that button +export function createCapabilityFailureMessage( + capability: keyof TransformCapabilities | 'noTransformNodes' +) { + let message = ''; + + switch (capability) { + case 'canCreateTransform': + message = i18n.translate('xpack.transform.capability.noPermission.createTransformTooltip', { + defaultMessage: 'You do not have permission to create transforms.', + }); + break; + case 'canCreateTransformAlerts': + message = i18n.translate( + 'xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip', + { + defaultMessage: 'You do not have permission to create transform alert rules.', + } + ); + break; + case 'canScheduleNowTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.scheduleNowTransformTooltip', + { + defaultMessage: + 'You do not have permission to schedule transforms to process data instantly.', + } + ); + break; + case 'canStartStopTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.startOrStopTransformTooltip', + { + defaultMessage: 'You do not have permission to start or stop transforms.', + } + ); + break; + + case 'canReauthorizeTransform': + message = i18n.translate( + 'xpack.transform.capability.noPermission.reauthorizeTransformTooltip', + { + defaultMessage: 'You do not have permission to reauthorize transforms.', + } + ); + break; + + case 'canDeleteTransform': + message = i18n.translate('xpack.transform.capability.noPermission.deleteTransformTooltip', { + defaultMessage: 'You do not have permission to delete transforms.', + }); + break; + + case 'canResetTransform': + message = i18n.translate('xpack.transform.capability.noPermission.resetTransformTooltip', { + defaultMessage: 'You do not have permission to reset transforms.', + }); + break; + + case 'noTransformNodes': + message = i18n.translate('xpack.transform.capability.noPermission.noTransformNodesTooltip', { + defaultMessage: 'There are no transform nodes available.', + }); + break; + } + + return i18n.translate('xpack.transform.capability.pleaseContactAdministratorTooltip', { + defaultMessage: '{message} Please contact your administrator.', + values: { + message, + }, + }); +} diff --git a/x-pack/plugins/transform/public/app/lib/authorization/index.ts b/x-pack/plugins/transform/common/utils/to_array.ts similarity index 73% rename from x-pack/plugins/transform/public/app/lib/authorization/index.ts rename to x-pack/plugins/transform/common/utils/to_array.ts index e78d12e73a8ea..f41ceea9fc180 100644 --- a/x-pack/plugins/transform/public/app/lib/authorization/index.ts +++ b/x-pack/plugins/transform/common/utils/to_array.ts @@ -5,4 +5,4 @@ * 2.0. */ -export * from './components'; +export const toArray = (value: T | T[]): T[] => (Array.isArray(value) ? value : [value]); diff --git a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx index 56bd9a2db877e..49b8ee1a684fb 100644 --- a/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx +++ b/x-pack/plugins/transform/public/alerting/transform_health_rule_type/transform_health_rule_trigger.tsx @@ -6,16 +6,15 @@ */ import { EuiForm, EuiSpacer } from '@elastic/eui'; -import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import React, { FC, useCallback, useEffect, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import type { TransformHealthRuleParams } from '../../../common/types/alerting'; import { TestsSelectionControl } from './tests_selection_control'; import { TransformSelectorControl } from './transform_selector_control'; -import { useApi } from '../../app/hooks'; +import { useGetTransforms } from '../../app/hooks'; import { useToastNotifications } from '../../app/app_dependencies'; -import { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; import { ALL_TRANSFORMS_SELECTION } from '../../../common/constants'; export type TransformHealthRuleTriggerProps = @@ -29,9 +28,12 @@ const TransformHealthRuleTrigger: FC = ({ const formErrors = Object.values(errors).flat(); const isFormInvalid = formErrors.length > 0; - const api = useApi(); const toast = useToastNotifications(); - const [transformOptions, setTransformOptions] = useState([]); + const { error, data } = useGetTransforms(); + const transformOptions = useMemo( + () => data?.transforms.filter((v) => v.config.sync).map((v) => v.id) ?? [], + [data] + ); const onAlertParamChange = useCallback( (param: T) => @@ -41,34 +43,18 @@ const TransformHealthRuleTrigger: FC = ({ [setRuleParams] ); - useEffect( - function fetchTransforms() { - let unmounted = false; - api - .getTransforms() - .then((r) => { - if (!unmounted) { - setTransformOptions( - (r as GetTransformsResponseSchema).transforms.filter((v) => v.sync).map((v) => v.id) - ); + useEffect(() => { + if (error !== null) { + toast.addError(error, { + title: i18n.translate( + 'xpack.transform.alertingRuleTypes.transformHealth.fetchErrorMessage', + { + defaultMessage: 'Unable to fetch transforms', } - }) - .catch((e) => { - toast.addError(e, { - title: i18n.translate( - 'xpack.transform.alertingRuleTypes.transformHealth.fetchErrorMessage', - { - defaultMessage: 'Unable to fetch transforms', - } - ), - }); - }); - return () => { - unmounted = true; - }; - }, - [api, toast] - ); + ), + }); + } + }, [error, toast]); const excludeTransformOptions = useMemo(() => { if (ruleParams.includeTransforms?.some((v) => v === ALL_TRANSFORMS_SELECTION)) { diff --git a/x-pack/plugins/transform/public/app/app.tsx b/x-pack/plugins/transform/public/app/app.tsx index ba4a43bfa0876..505009784d26e 100644 --- a/x-pack/plugins/transform/public/app/app.tsx +++ b/x-pack/plugins/transform/public/app/app.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext, FC } from 'react'; +import React, { type FC } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; @@ -13,68 +13,50 @@ import { EuiErrorBoundary } from '@elastic/eui'; import { Router, Routes, Route } from '@kbn/shared-ux-router'; import { ScopedHistory } from '@kbn/core/public'; -import { FormattedMessage } from '@kbn/i18n-react'; import { KibanaContextProvider, KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import { addInternalBasePath } from '../../common/constants'; - -import { SectionError } from './components'; import { SECTION_SLUG } from './common/constants'; -import { AuthorizationContext, AuthorizationProvider } from './lib/authorization'; import { AppDependencies } from './app_dependencies'; import { CloneTransformSection } from './sections/clone_transform'; import { CreateTransformSection } from './sections/create_transform'; import { TransformManagementSection } from './sections/transform_management'; -export const App: FC<{ history: ScopedHistory }> = ({ history }) => { - const { apiError } = useContext(AuthorizationContext); - if (apiError !== null) { - return ( - - } - error={apiError} +export const App: FC<{ history: ScopedHistory }> = ({ history }) => ( + + + - ); - } - - return ( - - - - - - - - ); -}; + + + + +); export const renderApp = (element: HTMLElement, appDependencies: AppDependencies) => { const I18nContext = appDependencies.i18n.Context; - const queryClient = new QueryClient(); + + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + retry: false, + }, + }, + }); render( - - - - - + + + diff --git a/x-pack/plugins/transform/public/app/common/index.ts b/x-pack/plugins/transform/public/app/common/index.ts index c7656974ec569..2bea1421277ef 100644 --- a/x-pack/plugins/transform/public/app/common/index.ts +++ b/x-pack/plugins/transform/public/app/common/index.ts @@ -19,12 +19,7 @@ export { toggleSelectedField, } from './fields'; export type { DropDownLabel, DropDownOption, Label } from './dropdown'; -export { - isTransformIdValid, - refreshTransformList$, - useRefreshTransformList, - REFRESH_TRANSFORM_LIST_STATE, -} from './transform'; +export { isTransformIdValid } from './transform'; export type { TransformListAction, TransformListRow } from './transform_list'; export { TRANSFORM_LIST_COLUMN } from './transform_list'; export { getTransformProgress, isCompletedBatchTransform } from './transform_stats'; diff --git a/x-pack/plugins/transform/public/app/common/navigation.tsx b/x-pack/plugins/transform/public/app/common/navigation.tsx index 601e701c7f16d..ef6696d3e757a 100644 --- a/x-pack/plugins/transform/public/app/common/navigation.tsx +++ b/x-pack/plugins/transform/public/app/common/navigation.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { Redirect } from 'react-router-dom'; import { SECTION_SLUG } from './constants'; diff --git a/x-pack/plugins/transform/public/app/common/transform.ts b/x-pack/plugins/transform/public/app/common/transform.ts index 35ead5691a866..b689ee8096983 100644 --- a/x-pack/plugins/transform/public/app/common/transform.ts +++ b/x-pack/plugins/transform/public/app/common/transform.ts @@ -5,11 +5,8 @@ * 2.0. */ -import { useEffect } from 'react'; -import { BehaviorSubject } from 'rxjs'; -import { filter, distinctUntilChanged } from 'rxjs/operators'; -import { Subscription } from 'rxjs'; import { cloneDeep } from 'lodash'; + import type { TransformConfigUnion, TransformId } from '../../../common/types/transform'; // Via https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/transform/utils/TransformStrings.java#L24 @@ -23,64 +20,6 @@ export function isTransformIdValid(transformId: TransformId) { export const TRANSFORM_ERROR_TYPE = { DANGLING_TASK: 'dangling_task', } as const; -export enum REFRESH_TRANSFORM_LIST_STATE { - ERROR = 'error', - IDLE = 'idle', - LOADING = 'loading', - REFRESH = 'refresh', -} -export const refreshTransformList$ = new BehaviorSubject( - REFRESH_TRANSFORM_LIST_STATE.IDLE -); - -export const useRefreshTransformList = ( - callback: { - isLoading?(d: boolean): void; - onRefresh?(): void; - } = {} -) => { - useEffect(() => { - const distinct$ = refreshTransformList$.pipe(distinctUntilChanged()); - - const subscriptions: Subscription[] = []; - - if (typeof callback.onRefresh === 'function') { - // initial call to refresh - callback.onRefresh(); - - subscriptions.push( - distinct$ - .pipe(filter((state) => state === REFRESH_TRANSFORM_LIST_STATE.REFRESH)) - .subscribe(() => typeof callback.onRefresh === 'function' && callback.onRefresh()) - ); - } - - if (typeof callback.isLoading === 'function') { - subscriptions.push( - distinct$.subscribe( - (state) => - typeof callback.isLoading === 'function' && - callback.isLoading(state === REFRESH_TRANSFORM_LIST_STATE.LOADING) - ) - ); - } - - return () => { - subscriptions.map((sub) => sub.unsubscribe()); - }; - // The effect should only be called once. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return { - refresh: () => { - // A refresh is followed immediately by setting the state to loading - // to trigger data fetching and loading indicators in one go. - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.LOADING); - }, - }; -}; export const overrideTransformForCloning = (originalConfig: TransformConfigUnion) => { // 'Managed' means job is preconfigured and deployed by other solutions diff --git a/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx b/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx new file mode 100644 index 0000000000000..ce850aa2ffc6c --- /dev/null +++ b/x-pack/plugins/transform/public/app/components/capabilities_wrapper.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type FC } from 'react'; + +import { EuiFlexItem, EuiFlexGroup, EuiPageTemplate, EuiEmptyPrompt } from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n-react'; + +import type { TransformCapability } from '../../../common/types/capabilities'; +import { toArray } from '../../../common/utils/to_array'; + +import { useTransformCapabilities } from '../hooks'; + +interface Props { + title: React.ReactNode; + message: React.ReactNode | string; +} + +export const NotAuthorizedSection = ({ title, message }: Props) => ( + {title}

} body={

{message}

} /> +); + +const MissingCapabilities: FC = () => ( + + + + + } + message={ + + } + /> + + + +); + +export const CapabilitiesWrapper: FC<{ + requiredCapabilities: TransformCapability | TransformCapability[]; +}> = ({ children, requiredCapabilities }) => { + const capabilities = useTransformCapabilities(); + + const hasCapabilities = toArray(requiredCapabilities).every((c) => capabilities[c]); + + return hasCapabilities ? <>{children} : ; +}; diff --git a/x-pack/plugins/transform/public/app/components/index.ts b/x-pack/plugins/transform/public/app/components/index.ts index 7c3cb454aecb3..2edcf498e5832 100644 --- a/x-pack/plugins/transform/public/app/components/index.ts +++ b/x-pack/plugins/transform/public/app/components/index.ts @@ -5,6 +5,4 @@ * 2.0. */ -export { SectionError } from './section_error'; -export { SectionLoading } from './section_loading'; export { ToastNotificationText } from './toast_notification_text'; diff --git a/x-pack/plugins/transform/public/app/components/job_icon.tsx b/x-pack/plugins/transform/public/app/components/job_icon.tsx index 09db5a1c52377..12a5687156611 100644 --- a/x-pack/plugins/transform/public/app/components/job_icon.tsx +++ b/x-pack/plugins/transform/public/app/components/job_icon.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiIcon, EuiToolTip } from '@elastic/eui'; import { AuditMessageBase } from '../../../common/types/messages'; diff --git a/x-pack/plugins/transform/public/app/components/section_error.tsx b/x-pack/plugins/transform/public/app/components/section_error.tsx deleted file mode 100644 index 2a6ddd3174de7..0000000000000 --- a/x-pack/plugins/transform/public/app/components/section_error.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiPageTemplate } from '@elastic/eui'; - -interface Props { - title: React.ReactNode; - error: Error | null; - actions?: JSX.Element; -} - -export const SectionError: React.FunctionComponent = ({ - title, - error, - actions, - ...rest -}) => { - const errorMessage = error?.message ?? JSON.stringify(error, null, 2); - - return ( - {title}} - body={ -

-

{errorMessage}
- {actions ? actions : null} -

- } - /> - ); -}; diff --git a/x-pack/plugins/transform/public/app/components/section_loading.tsx b/x-pack/plugins/transform/public/app/components/section_loading.tsx deleted file mode 100644 index c1548ad960bb0..0000000000000 --- a/x-pack/plugins/transform/public/app/components/section_loading.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { - EuiEmptyPrompt, - EuiLoadingSpinner, - EuiText, - EuiFlexGroup, - EuiFlexItem, - EuiTextColor, -} from '@elastic/eui'; - -interface Props { - inline?: boolean; - children: React.ReactNode; - [key: string]: any; -} - -export const SectionLoading: React.FunctionComponent = ({ inline, children, ...rest }) => { - if (inline) { - return ( - - - - - - - {children} - - - - ); - } - - return ( - } - body={{children}} - data-test-subj="sectionLoading" - /> - ); -}; diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index 6409a8fcf3b45..8b2f154e8124e 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiButtonEmpty, @@ -19,41 +19,45 @@ import { import { i18n } from '@kbn/i18n'; -import { CoreStart } from '@kbn/core/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { useAppDependencies } from '../app_dependencies'; const MAX_SIMPLE_MESSAGE_LENGTH = 140; -// Because of the use of `toMountPoint`, `useKibanaContext` doesn't work via `useAppDependencies`. -// That's why we need to pass in `overlays` as a prop cannot get it via context. interface ToastNotificationTextProps { - overlays: CoreStart['overlays']; - theme: CoreStart['theme']; text: any; previewTextLength?: number; + inline?: boolean; + forceModal?: boolean; } export const ToastNotificationText: FC = ({ - overlays, text, - theme, previewTextLength, + inline = false, + forceModal = false, }) => { - if (typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { + const { overlays, theme, i18n: i18nStart } = useAppDependencies(); + + if (!forceModal && typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { return text; } if ( + !forceModal && typeof text === 'object' && + text !== null && typeof text.message === 'string' && text.message.length <= MAX_SIMPLE_MESSAGE_LENGTH ) { return text.message; } - const unformattedText = text.message ? text.message : text; - const formattedText = typeof unformattedText === 'object' ? JSON.stringify(text, null, 2) : text; + const unformattedText = + typeof text === 'object' && text !== null && text.message ? text.message : text; + const formattedText = + typeof unformattedText === 'object' ? JSON.stringify(text, null, 2) : unformattedText; const textLength = previewTextLength ?? 140; const previewText = `${formattedText.substring(0, textLength)}${ formattedText.length > textLength ? ' ...' : '' @@ -83,15 +87,19 @@ export const ToastNotificationText: FC = ({ , - { theme$: theme.theme$ } + { theme, i18n: i18nStart } ) ); }; return ( <> -
{previewText}
- + {!inline &&
{previewText}
} + {i18n.translate('xpack.transform.toastText.openModalButtonText', { defaultMessage: 'View details', })} diff --git a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts b/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts deleted file mode 100644 index 2e0407b0ac974..0000000000000 --- a/x-pack/plugins/transform/public/app/hooks/__mocks__/use_api.ts +++ /dev/null @@ -1,150 +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 { IHttpFetchError } from '@kbn/core-http-browser'; - -import { KBN_FIELD_TYPES } from '@kbn/field-types'; -import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; - -import type { TransformId } from '../../../../common/types/transform'; -import type { FieldHistogramsResponseSchema } from '../../../../common/api_schemas/field_histograms'; -import type { GetTransformsAuditMessagesResponseSchema } from '../../../../common/api_schemas/audit_messages'; -import type { - DeleteTransformsRequestSchema, - DeleteTransformsResponseSchema, -} from '../../../../common/api_schemas/delete_transforms'; -import type { - StartTransformsRequestSchema, - StartTransformsResponseSchema, -} from '../../../../common/api_schemas/start_transforms'; -import type { - StopTransformsRequestSchema, - StopTransformsResponseSchema, -} from '../../../../common/api_schemas/stop_transforms'; -import type { - GetTransformsResponseSchema, - PostTransformsPreviewRequestSchema, - PostTransformsPreviewResponseSchema, - PutTransformsRequestSchema, - PutTransformsResponseSchema, -} from '../../../../common/api_schemas/transforms'; -import type { GetTransformsStatsResponseSchema } from '../../../../common/api_schemas/transforms_stats'; -import type { - PostTransformsUpdateRequestSchema, - PostTransformsUpdateResponseSchema, -} from '../../../../common/api_schemas/update_transforms'; - -import type { EsIndex } from '../../../../common/types/es_index'; - -import type { SavedSearchQuery } from '../use_search_items'; - -export interface FieldHistogramRequestConfig { - fieldName: string; - type?: KBN_FIELD_TYPES; -} - -const apiFactory = () => ({ - async getTransform( - transformId: TransformId - ): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, - async getTransforms(): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, - async getTransformStats( - transformId: TransformId - ): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, - async getTransformsStats(): Promise { - return Promise.resolve({ count: 0, transforms: [] }); - }, - async createTransform( - transformId: TransformId, - transformConfig: PutTransformsRequestSchema - ): Promise { - return Promise.resolve({ transformsCreated: [], errors: [] }); - }, - async updateTransform( - transformId: TransformId, - transformConfig: PostTransformsUpdateRequestSchema - ): Promise { - return Promise.resolve({ - id: 'the-test-id', - source: { index: ['the-index-name'], query: { match_all: {} } }, - dest: { index: 'user-the-destination-index-name' }, - frequency: '10m', - pivot: { - group_by: { the_group: { terms: { field: 'the-group-by-field' } } }, - aggregations: { the_agg: { value_count: { field: 'the-agg-field' } } }, - }, - description: 'the-description', - settings: { docs_per_second: null }, - version: '8.0.0', - create_time: 1598860879097, - }); - }, - async deleteTransforms( - reqBody: DeleteTransformsRequestSchema - ): Promise { - return Promise.resolve({}); - }, - async getTransformsPreview( - obj: PostTransformsPreviewRequestSchema - ): Promise { - return Promise.resolve({ - generated_dest_index: { - mappings: { - _meta: { - _transform: { - transform: 'the-transform', - version: { create: 'the-version' }, - creation_date_in_millis: 0, - }, - created_by: 'mock', - }, - properties: {}, - }, - settings: { index: { number_of_shards: '1', auto_expand_replicas: '0-1' } }, - aliases: {}, - }, - preview: [], - }); - }, - async startTransforms( - reqBody: StartTransformsRequestSchema - ): Promise { - return Promise.resolve({}); - }, - async stopTransforms( - transformsInfo: StopTransformsRequestSchema - ): Promise { - return Promise.resolve({}); - }, - async getTransformAuditMessages( - transformId: TransformId - ): Promise { - return Promise.resolve({ messages: [], total: 0 }); - }, - - async getEsIndices(): Promise { - return Promise.resolve([]); - }, - async getHistogramsForFields( - dataViewTitle: string, - fields: FieldHistogramRequestConfig[], - query: string | SavedSearchQuery, - samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE - ): Promise { - return Promise.resolve([]); - }, -}); - -export const useApi = () => { - return apiFactory(); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index f6a4c72b39a44..749706f97cd70 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -5,10 +5,23 @@ * 2.0. */ -export { useApi } from './use_api'; +export { useCreateTransform } from './use_create_transform'; +export { useDocumentationLinks } from './use_documentation_links'; +export { useGetDataViewTitles } from './use_get_data_view_titles'; +export { useGetEsIndices } from './use_get_es_indices'; +export { useGetEsIngestPipelines } from './use_get_es_ingest_pipelines'; +export { useGetTransformAuditMessages } from './use_get_transform_audit_messages'; +export { useGetTransform } from './use_get_transform'; +export { useGetTransformNodes } from './use_get_transform_nodes'; export { useGetTransforms } from './use_get_transforms'; +export { useGetTransformsPreview } from './use_get_transforms_preview'; +export { useGetTransformStats } from './use_get_transform_stats'; export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; +export { useRefreshTransformList } from './use_refresh_transform_list'; export { useResetTransforms } from './use_reset_transform'; +export { useSearchItems } from './use_search_items'; export { useScheduleNowTransforms } from './use_schedule_now_transform'; export { useStartTransforms } from './use_start_transform'; export { useStopTransforms } from './use_stop_transform'; +export { useTransformCapabilities } from './use_transform_capabilities'; +export { useUpdateTransform } from './use_update_transform'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts deleted file mode 100644 index 066977fb841df..0000000000000 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ /dev/null @@ -1,301 +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 { useMemo } from 'react'; - -import type { IHttpFetchError } from '@kbn/core-http-browser'; - -import { KBN_FIELD_TYPES } from '@kbn/field-types'; -import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; - -import { - ReauthorizeTransformsRequestSchema, - ReauthorizeTransformsResponseSchema, -} from '../../../common/api_schemas/reauthorize_transforms'; -import type { GetTransformsAuditMessagesResponseSchema } from '../../../common/api_schemas/audit_messages'; -import type { - DeleteTransformsRequestSchema, - DeleteTransformsResponseSchema, -} from '../../../common/api_schemas/delete_transforms'; -import type { - FieldHistogramsRequestSchema, - FieldHistogramsResponseSchema, -} from '../../../common/api_schemas/field_histograms'; -import type { - ResetTransformsRequestSchema, - ResetTransformsResponseSchema, -} from '../../../common/api_schemas/reset_transforms'; -import type { - StartTransformsRequestSchema, - StartTransformsResponseSchema, -} from '../../../common/api_schemas/start_transforms'; -import type { - StopTransformsRequestSchema, - StopTransformsResponseSchema, -} from '../../../common/api_schemas/stop_transforms'; -import type { - ScheduleNowTransformsRequestSchema, - ScheduleNowTransformsResponseSchema, -} from '../../../common/api_schemas/schedule_now_transforms'; -import type { - GetTransformNodesResponseSchema, - GetTransformsResponseSchema, - PostTransformsPreviewRequestSchema, - PostTransformsPreviewResponseSchema, - PutTransformsRequestSchema, - PutTransformsResponseSchema, -} from '../../../common/api_schemas/transforms'; -import type { - PostTransformsUpdateRequestSchema, - PostTransformsUpdateResponseSchema, -} from '../../../common/api_schemas/update_transforms'; -import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; -import type { TransformId } from '../../../common/types/transform'; -import { addInternalBasePath } from '../../../common/constants'; -import type { EsIndex } from '../../../common/types/es_index'; -import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; - -import { useAppDependencies } from '../app_dependencies'; - -import type { SavedSearchQuery } from './use_search_items'; - -export interface FieldHistogramRequestConfig { - fieldName: string; - type?: KBN_FIELD_TYPES; -} - -interface FetchOptions { - asSystemRequest?: boolean; -} - -export const useApi = () => { - const { http } = useAppDependencies(); - - return useMemo( - () => ({ - async getTransformNodes(): Promise { - try { - return await http.get(addInternalBasePath(`transforms/_nodes`), { version: '1' }); - } catch (e) { - return e; - } - }, - async getTransform( - transformId: TransformId - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms/${transformId}`), { - version: '1', - }); - } catch (e) { - return e; - } - }, - async getTransforms( - fetchOptions: FetchOptions = {} - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms`), { - ...fetchOptions, - version: '1', - }); - } catch (e) { - return e; - } - }, - async getTransformStats( - transformId: TransformId - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms/${transformId}/_stats`), { - version: '1', - }); - } catch (e) { - return e; - } - }, - async getTransformsStats( - fetchOptions: FetchOptions = {} - ): Promise { - try { - return await http.get(addInternalBasePath(`transforms/_stats`), { - ...fetchOptions, - version: '1', - }); - } catch (e) { - return e; - } - }, - async createTransform( - transformId: TransformId, - transformConfig: PutTransformsRequestSchema - ): Promise { - try { - return await http.put(addInternalBasePath(`transforms/${transformId}`), { - body: JSON.stringify(transformConfig), - version: '1', - }); - } catch (e) { - return e; - } - }, - async updateTransform( - transformId: TransformId, - transformConfig: PostTransformsUpdateRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`transforms/${transformId}/_update`), { - body: JSON.stringify(transformConfig), - version: '1', - }); - } catch (e) { - return e; - } - }, - async deleteTransforms( - reqBody: DeleteTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`delete_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, - async getTransformsPreview( - obj: PostTransformsPreviewRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`transforms/_preview`), { - body: JSON.stringify(obj), - version: '1', - }); - } catch (e) { - return e; - } - }, - async reauthorizeTransforms( - reqBody: ReauthorizeTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`reauthorize_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, - - async resetTransforms( - reqBody: ResetTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`reset_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, - async startTransforms( - reqBody: StartTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`start_transforms`), { - body: JSON.stringify(reqBody), - version: '1', - }); - } catch (e) { - return e; - } - }, - async stopTransforms( - transformsInfo: StopTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`stop_transforms`), { - body: JSON.stringify(transformsInfo), - version: '1', - }); - } catch (e) { - return e; - } - }, - async scheduleNowTransforms( - transformsInfo: ScheduleNowTransformsRequestSchema - ): Promise { - try { - return await http.post(addInternalBasePath(`schedule_now_transforms`), { - body: JSON.stringify(transformsInfo), - version: '1', - }); - } catch (e) { - return e; - } - }, - async getTransformAuditMessages( - transformId: TransformId, - sortField: string, - sortDirection: 'asc' | 'desc' - ): Promise< - { messages: GetTransformsAuditMessagesResponseSchema; total: number } | IHttpFetchError - > { - try { - return await http.get(addInternalBasePath(`transforms/${transformId}/messages`), { - query: { - sortField, - sortDirection, - }, - version: '1', - }); - } catch (e) { - return e; - } - }, - async getEsIndices(): Promise { - try { - return await http.get(`/api/index_management/indices`, { version: '1' }); - } catch (e) { - return e; - } - }, - async getEsIngestPipelines(): Promise { - try { - return await http.get('/api/ingest_pipelines', { version: '1' }); - } catch (e) { - return e; - } - }, - async getHistogramsForFields( - dataViewTitle: string, - fields: FieldHistogramRequestConfig[], - query: string | SavedSearchQuery, - runtimeMappings?: FieldHistogramsRequestSchema['runtimeMappings'], - samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE - ): Promise { - try { - return await http.post(addInternalBasePath(`field_histograms/${dataViewTitle}`), { - body: JSON.stringify({ - query, - fields, - samplerShardSize, - ...(runtimeMappings !== undefined ? { runtimeMappings } : {}), - }), - version: '1', - }); - } catch (e) { - return e; - } - }, - }), - [http] - ); -}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx new file mode 100644 index 0000000000000..272e815c42eb4 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_create_transform.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { useMutation } from '@tanstack/react-query'; + +import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '@kbn/react-kibana-mount'; + +import type { + PutTransformsRequestSchema, + PutTransformsResponseSchema, +} from '../../../common/api_schemas/transforms'; +import { addInternalBasePath } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; +import { getErrorMessage } from '../../../common/utils/errors'; + +import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { ToastNotificationText } from '../components'; + +import { useRefreshTransformList } from './use_refresh_transform_list'; + +interface CreateTransformArgs { + transformId: TransformId; + transformConfig: PutTransformsRequestSchema; +} + +export const useCreateTransform = () => { + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); + const toastNotifications = useToastNotifications(); + + function errorToast(error: unknown, { transformId }: CreateTransformArgs) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { + defaultMessage: 'An error occurred creating the transform {transformId}:', + values: { transformId }, + }), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); + } + + const mutation = useMutation({ + mutationFn: ({ transformId, transformConfig }: CreateTransformArgs) => { + return http.put( + addInternalBasePath(`transforms/${transformId}`), + { + body: JSON.stringify(transformConfig), + version: '1', + } + ); + }, + onError: errorToast, + onSuccess: (resp, options) => { + if (resp.errors.length > 0) { + errorToast(resp.errors.length === 1 ? resp.errors[0] : resp.errors, options); + } + + refreshTransformList(); + }, + }); + + return mutation.mutate; +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_data_search.ts b/x-pack/plugins/transform/public/app/hooks/use_data_search.ts index af4bb440f9e24..f691cb7a0d8b6 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_data_search.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_data_search.ts @@ -5,37 +5,37 @@ * 2.0. */ -import { useCallback } from 'react'; +import { useQuery } from '@tanstack/react-query'; import { lastValueFrom } from 'rxjs'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + import type { IKibanaSearchRequest } from '@kbn/data-plugin/common'; +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + import { useAppDependencies } from '../app_dependencies'; -export const useDataSearch = () => { +export const useDataSearch = ( + esSearchRequestParams: IKibanaSearchRequest['params'], + enabled?: boolean +) => { const { data } = useAppDependencies(); - return useCallback( - async (esSearchRequestParams: IKibanaSearchRequest['params'], abortSignal?: AbortSignal) => { - try { - const { rawResponse: resp } = await lastValueFrom( - data.search.search( - { - params: esSearchRequestParams, - }, - { abortSignal } - ) - ); - - return resp; - } catch (error) { - if (error.name === 'AbortError') { - // ignore abort errors - } else { - return error; - } - } + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.DATA_SEARCH, esSearchRequestParams], + async ({ signal }) => { + const { rawResponse: resp } = await lastValueFrom( + data.search.search( + { + params: esSearchRequestParams, + }, + { abortSignal: signal } + ) + ); + + return resp; }, - [data] + { enabled } ); }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts b/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts new file mode 100644 index 0000000000000..d74fa9c909a5d --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_data_view_exists.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { ErrorType } from '@kbn/ml-error-utils'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; +import type { TransformListRow } from '../common'; + +export const useDataViewExists = (items: TransformListRow[]) => { + const { + data: { dataViews: dataViewsContract }, + } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.DATA_VIEW_EXISTS, items], + async () => { + if (items.length !== 1) { + return false; + } + const config = items[0].config; + const indexName = Array.isArray(config.dest.index) ? config.dest.index[0] : config.dest.index; + + if (indexName === undefined) { + return false; + } + + return (await dataViewsContract.find(indexName)).some(({ title }) => title === indexName); + } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 25318fc9e2903..a7ed779c47cc7 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -6,34 +6,40 @@ */ import React, { useCallback, useEffect, useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; + import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { extractErrorMessage } from '@kbn/ml-error-utils'; + +import { addInternalBasePath } from '../../../common/constants'; import type { - DeleteTransformStatus, DeleteTransformsRequestSchema, + DeleteTransformsResponseSchema, } from '../../../common/api_schemas/delete_transforms'; -import { isDeleteTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../common/utils/errors'; + import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { REFRESH_TRANSFORM_LIST_STATE, refreshTransformList$, TransformListRow } from '../common'; +import { type TransformListRow } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; -import { indexService } from '../services/es_index_service'; + +import { useTransformCapabilities } from './use_transform_capabilities'; +import { useDataViewExists } from './use_data_view_exists'; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { const { - http, - data: { dataViews: dataViewsContract }, application: { capabilities }, } = useAppDependencies(); const toastNotifications = useToastNotifications(); + const { canDeleteIndex: userCanDeleteIndex } = useTransformCapabilities(); + + const userCanDeleteDataView = + capabilities.savedObjectsManagement?.delete === true || + capabilities.indexPatterns?.save === true; const [deleteDestIndex, setDeleteDestIndex] = useState(true); - const [deleteDataView, setDeleteDataView] = useState(true); - const [userCanDeleteIndex, setUserCanDeleteIndex] = useState(false); - const [dataViewExists, setDataViewExists] = useState(false); - const [userCanDeleteDataView, setUserCanDeleteDataView] = useState(false); + const [deleteDataView, setDeleteDataView] = useState(userCanDeleteDataView); const toggleDeleteIndex = useCallback( () => setDeleteDestIndex(!deleteDestIndex), @@ -43,67 +49,31 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { () => setDeleteDataView(!deleteDataView), [deleteDataView] ); - const checkDataViewExists = useCallback( - async (indexName: string) => { - try { - const dvExists = await indexService.dataViewExists(dataViewsContract, indexName); - setDataViewExists(dvExists); - } catch (e) { - const error = extractErrorMessage(e); - toastNotifications.addDanger( - i18n.translate( - 'xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage', - { - defaultMessage: 'An error occurred checking if data view {dataView} exists: {error}', - values: { dataView: indexName, error }, - } - ) - ); - } - }, - [dataViewsContract, toastNotifications] - ); + const { error: dataViewExistsError, data: dataViewExists = items.length !== 1 } = + useDataViewExists(items); + + useEffect(() => { + if (dataViewExistsError !== null && items.length === 1) { + const config = items[0].config; + const indexName = Array.isArray(config.dest.index) ? config.dest.index[0] : config.dest.index; - const checkUserIndexPermission = useCallback(async () => { - try { - const userCanDelete = await indexService.canDeleteIndex(http); - if (userCanDelete) { - setUserCanDeleteIndex(true); - } - const canDeleteDataView = - capabilities.savedObjectsManagement.delete === true || - capabilities.indexPatterns.save === true; - setUserCanDeleteDataView(canDeleteDataView); - if (canDeleteDataView === false) { - setDeleteDataView(false); - } - } catch (e) { toastNotifications.addDanger( i18n.translate( - 'xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage', + 'xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage', { - defaultMessage: 'An error occurred checking if user can delete destination index', + defaultMessage: 'An error occurred checking if data view {dataView} exists: {error}', + values: { + dataView: indexName, + error: extractErrorMessage(dataViewExistsError), + }, } ) ); } - }, [http, toastNotifications, capabilities]); - - useEffect(() => { - checkUserIndexPermission(); - - // if user only deleting one transform - if (items.length === 1) { - const config = items[0].config; - const destinationIndex = Array.isArray(config.dest.index) - ? config.dest.index[0] - : config.dest.index; - checkDataViewExists(destinationIndex); - } else { - setDataViewExists(true); - } - }, [checkDataViewExists, checkUserIndexPermission, items]); + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dataViewExistsError]); return { userCanDeleteIndex, @@ -116,183 +86,87 @@ export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { }; }; -type SuccessCountField = keyof Omit; - export const useDeleteTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - return async (reqBody: DeleteTransformsRequestSchema) => { - const results = await api.deleteTransforms(reqBody); - - if (!isDeleteTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: DeleteTransformsRequestSchema) => + http.post(addInternalBasePath('delete_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { theme, i18n: i18nStart } ), - }); - return; - } - - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformDeleted: 0, - destIndexDeleted: 0, - destDataViewDeleted: 0, - }; - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const status = results[transformId]; - const destinationIndex = status.destinationIndex; - - // if we are only deleting one transform, show the success toast messages - if (!isBulk && status.transformDeleted) { - if (status.transformDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { - defaultMessage: 'Request to delete transform {transformId} acknowledged.', + }), + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const status = results[transformId]; + const destinationIndex = status.destinationIndex; + + if (status.transformDeleted?.error) { + const error = status.transformDeleted.error.reason; + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { + defaultMessage: 'An error occurred deleting the transform {transformId}', values: { transformId }, - }) - ); + }), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); } - if (status.destIndexDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage', + + if (status.destIndexDeleted?.error) { + const error = status.destIndexDeleted.error.reason; + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage', { - defaultMessage: - 'Request to delete destination index {destinationIndex} acknowledged.', + defaultMessage: 'An error occurred deleting destination index {destinationIndex}', values: { destinationIndex }, } - ) - ); + ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); } - if (status.destDataViewDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage', + + if (status.destDataViewDeleted?.error) { + const error = status.destDataViewDeleted.error.reason; + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage', { - defaultMessage: 'Request to delete data view {destinationIndex} acknowledged.', + defaultMessage: 'An error occurred deleting data view {destinationIndex}', values: { destinationIndex }, } - ) - ); + ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); } - } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } - if (status.transformDeleted?.error) { - const error = status.transformDeleted.error.reason; - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { - defaultMessage: 'An error occurred deleting the transform {transformId}', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } - - if (status.destIndexDeleted?.error) { - const error = status.destIndexDeleted.error.reason; - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage', - { - defaultMessage: 'An error occurred deleting destination index {destinationIndex}', - values: { destinationIndex }, - } - ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } - - if (status.destDataViewDeleted?.error) { - const error = status.destDataViewDeleted.error.reason; - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage', - { - defaultMessage: 'An error occurred deleting data view {destinationIndex}', - values: { destinationIndex }, - } - ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); } } - } - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteTransformSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformDeleted }, - }) - ); - } - - if (successCount.destIndexDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination {count, plural, one {index} other {indices}}.', - values: { count: successCount.destIndexDeleted }, - }) - ); - } - if (successCount.destDataViewDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination data {count, plural, one {view} other {views}}.', - values: { count: successCount.destDataViewDeleted }, - }) - ); - } - } + refreshTransformList(); + }, + }); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - }; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts b/x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts new file mode 100644 index 0000000000000..449ac30b9f513 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_data_view_titles.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetDataViewTitles = () => { + const { data } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_DATA_VIEW_TITLES], + () => data.dataViews.getTitles() + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_es_indices.ts b/x-pack/plugins/transform/public/app/hooks/use_get_es_indices.ts new file mode 100644 index 0000000000000..7da50c155d1be --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_es_indices.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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { EsIndex } from '../../../common/types/es_index'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetEsIndices = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_ES_INDICES], + ({ signal }) => + http.get('/api/index_management/indices', { + version: '1', + signal, + }) + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.ts b/x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.ts new file mode 100644 index 0000000000000..3f9784c64b652 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_es_ingest_pipelines.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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { EsIngestPipeline } from '../../../common/types/es_ingest_pipeline'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetEsIngestPipelines = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_ES_INGEST_PIPELINES], + ({ signal }) => + http.get('/api/ingest_pipelines', { + version: '1', + signal, + }) + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts b/x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts new file mode 100644 index 0000000000000..63ce23dba6214 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_histograms_for_fields.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import { KBN_FIELD_TYPES } from '@kbn/field-types'; +import { DEFAULT_SAMPLER_SHARD_SIZE } from '@kbn/ml-agg-utils'; + +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { + FieldHistogramsRequestSchema, + FieldHistogramsResponseSchema, +} from '../../../common/api_schemas/field_histograms'; + +import { useAppDependencies } from '../app_dependencies'; + +import type { SavedSearchQuery } from './use_search_items'; + +export interface FieldHistogramRequestConfig { + fieldName: string; + type?: KBN_FIELD_TYPES; +} + +export const useGetHistogramsForFields = ( + dataViewTitle: string, + fields: FieldHistogramRequestConfig[], + query: string | SavedSearchQuery, + runtimeMappings?: FieldHistogramsRequestSchema['runtimeMappings'], + enabled?: boolean, + samplerShardSize = DEFAULT_SAMPLER_SHARD_SIZE +) => { + const { http } = useAppDependencies(); + + return useQuery( + [ + TRANSFORM_REACT_QUERY_KEYS.GET_HISTOGRAMS_FOR_FIELDS, + { + dataViewTitle, + fields, + query, + runtimeMappings, + samplerShardSize, + }, + ], + ({ signal }) => + http.post( + addInternalBasePath(`field_histograms/${dataViewTitle}`), + { + body: JSON.stringify({ + query, + fields, + samplerShardSize, + ...(runtimeMappings !== undefined ? { runtimeMappings } : {}), + }), + version: '1', + signal, + } + ), + { enabled } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_get_transform.tsx new file mode 100644 index 0000000000000..b9e3d977c71bd --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform.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 { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransform = (transformId: TransformId, enabled?: boolean) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM, transformId], + ({ signal }) => + http.get(addInternalBasePath(`transforms/${transformId}`), { + version: '1', + signal, + }), + { enabled } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts new file mode 100644 index 0000000000000..3f7559a251275 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_audit_messages.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformsAuditMessagesResponseSchema } from '../../../common/api_schemas/audit_messages'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import { TransformMessage } from '../../../common/types/messages'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformAuditMessages = ( + transformId: string, + sortField: keyof TransformMessage, + sortDirection: 'asc' | 'desc' +) => { + const { http } = useAppDependencies(); + + const query = { sortField, sortDirection }; + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES, transformId, query], + ({ signal }) => + http.get( + addInternalBasePath(`transforms/${transformId}/messages`), + { + query, + version: '1', + signal, + } + ) + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts new file mode 100644 index 0000000000000..2d3d7cfa9defd --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_nodes.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformNodesResponseSchema } from '../../../common/api_schemas/transforms'; +import { + addInternalBasePath, + DEFAULT_REFRESH_INTERVAL_MS, + TRANSFORM_REACT_QUERY_KEYS, +} from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformNodes = () => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_NODES], + async ({ signal }) => { + const transformNodes = await http.get( + addInternalBasePath('transforms/_nodes'), + { + version: '1', + signal, + } + ); + + return transformNodes.count; + }, + { + refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, + } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts new file mode 100644 index 0000000000000..d2b9d32f25853 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transform_stats.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformStats = ( + transformId: TransformId, + enabled?: boolean, + refetchInterval?: number | false +) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_STATS, transformId], + ({ signal }) => + http.get( + addInternalBasePath(`transforms/${transformId}/_stats`), + { + version: '1', + signal, + } + ), + { enabled, refetchInterval } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts index 55e3bc40360cf..f74f7a5774ded 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms.ts @@ -5,75 +5,64 @@ * 2.0. */ +import { useQuery } from '@tanstack/react-query'; + import type { IHttpFetchError } from '@kbn/core-http-browser'; import { isDefined } from '@kbn/ml-is-defined'; -import { - isGetTransformNodesResponseSchema, - isGetTransformsResponseSchema, - isGetTransformsStatsResponseSchema, -} from '../../../common/api_schemas/type_guards'; -import { TRANSFORM_MODE } from '../../../common/constants'; -import { isTransformStats } from '../../../common/types/transform_stats'; +import type { GetTransformsResponseSchema } from '../../../common/api_schemas/transforms'; +import type { GetTransformsStatsResponseSchema } from '../../../common/api_schemas/transforms_stats'; import { - type TransformListRow, - refreshTransformList$, - REFRESH_TRANSFORM_LIST_STATE, -} from '../common'; + addInternalBasePath, + DEFAULT_REFRESH_INTERVAL_MS, + TRANSFORM_REACT_QUERY_KEYS, + TRANSFORM_MODE, +} from '../../../common/constants'; +import { isTransformStats } from '../../../common/types/transform_stats'; -import { useApi } from './use_api'; +import { type TransformListRow } from '../common'; +import { useAppDependencies } from '../app_dependencies'; import { TRANSFORM_ERROR_TYPE } from '../common/transform'; -export type GetTransforms = (forceRefresh?: boolean) => void; - -export const useGetTransforms = ( - setTransforms: React.Dispatch>, - setTransformNodes: React.Dispatch>, - setErrorMessage: React.Dispatch>, - setTransformIdsWithoutConfig: React.Dispatch>, - setIsInitialized: React.Dispatch>, - blockRefresh: boolean -): GetTransforms => { - const api = useApi(); - - let concurrentLoads = 0; - - const getTransforms = async (forceRefresh = false) => { - if (forceRefresh === true || blockRefresh === false) { - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.LOADING); - concurrentLoads++; - - if (concurrentLoads > 1) { - return; - } - - const fetchOptions = { asSystemRequest: true }; - const transformNodes = await api.getTransformNodes(); - const transformConfigs = await api.getTransforms(fetchOptions); - const transformStats = await api.getTransformsStats(fetchOptions); - - if ( - !isGetTransformsResponseSchema(transformConfigs) || - !isGetTransformsStatsResponseSchema(transformStats) || - !isGetTransformNodesResponseSchema(transformNodes) - ) { - // An error is followed immediately by setting the state to idle. - // This way we're able to treat ERROR as a one-time-event like REFRESH. - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.ERROR); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.IDLE); - setTransformNodes(0); - setTransforms([]); - - setIsInitialized(true); - - if (!isGetTransformsResponseSchema(transformConfigs)) { - setErrorMessage(transformConfigs); - } else if (!isGetTransformsStatsResponseSchema(transformStats)) { - setErrorMessage(transformStats); +interface UseGetTransformsResponse { + transforms: TransformListRow[]; + transformIds: string[]; + transformIdsWithoutConfig?: string[]; +} + +const getInitialData = (): UseGetTransformsResponse => ({ + transforms: [], + transformIds: [], +}); + +interface UseGetTransformsOptions { + enabled?: boolean; +} + +export const useGetTransforms = ({ enabled }: UseGetTransformsOptions = {}) => { + const { http } = useAppDependencies(); + + const { data = getInitialData(), ...rest } = useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS], + async ({ signal }) => { + const update = getInitialData(); + + const transformConfigs = await http.get( + addInternalBasePath('transforms'), + { + version: '1', + asSystemRequest: true, + signal, } - - return; - } + ); + const transformStats = await http.get( + addInternalBasePath(`transforms/_stats`), + { + version: '1', + asSystemRequest: true, + signal, + } + ); // There might be some errors with fetching certain transforms // For example, when task exists and is running but the config is deleted @@ -87,17 +76,12 @@ export const useGetTransforms = ( }) .filter(isDefined); - setTransformIdsWithoutConfig( - danglingTaskIdMatches.length > 0 ? danglingTaskIdMatches : undefined - ); - } else { - setTransformIdsWithoutConfig(undefined); + update.transformIdsWithoutConfig = + danglingTaskIdMatches.length > 0 ? danglingTaskIdMatches : undefined; } - const tableRows = transformConfigs.transforms.reduce((reducedtableRows, config) => { - const stats = isGetTransformsStatsResponseSchema(transformStats) - ? transformStats.transforms.find((d) => config.id === d.id) - : undefined; + update.transforms = transformConfigs.transforms.reduce((reducedtableRows, config) => { + const stats = transformStats.transforms.find((d) => config.id === d.id); // A newly created transform might not have corresponding stats yet. // If that's the case we just skip the transform and don't add it to the transform list yet. @@ -117,21 +101,15 @@ export const useGetTransforms = ( return reducedtableRows; }, [] as TransformListRow[]); - setTransformNodes(transformNodes.count); - setTransforms(tableRows); - setErrorMessage(undefined); - setIsInitialized(true); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.IDLE); - - concurrentLoads--; + update.transformIds = update.transforms.map(({ id }) => id); - if (concurrentLoads > 0) { - concurrentLoads = 0; - getTransforms(true); - return; - } + return update; + }, + { + enabled, + refetchInterval: DEFAULT_REFRESH_INTERVAL_MS, } - }; + ); - return getTransforms; + return { data, ...rest }; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts b/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts new file mode 100644 index 0000000000000..ae671912b9267 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_get_transforms_preview.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQuery } from '@tanstack/react-query'; + +import type { IHttpFetchError } from '@kbn/core-http-browser'; + +import type { + PostTransformsPreviewRequestSchema, + PostTransformsPreviewResponseSchema, +} from '../../../common/api_schemas/transforms'; +import { addInternalBasePath, TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useGetTransformsPreview = ( + obj: PostTransformsPreviewRequestSchema, + enabled?: boolean +) => { + const { http } = useAppDependencies(); + + return useQuery( + [TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS_PREVIEW, obj], + ({ signal }) => + http.post(addInternalBasePath('transforms/_preview'), { + body: JSON.stringify(obj), + version: '1', + signal, + }), + { enabled } + ); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx index 9da9fa8e5e782..ced29e2f8c17c 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.test.tsx @@ -5,13 +5,13 @@ * 2.0. */ -import React, { FC } from 'react'; -import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; - +import React, { type FC } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@testing-library/jest-dom/extend-expect'; import { render, screen, waitFor } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { CoreSetup } from '@kbn/core/public'; import { DataGrid, type UseIndexDataReturnType } from '@kbn/ml-data-grid'; import type { RuntimeMappings } from '@kbn/ml-runtime-field-utils'; @@ -25,7 +25,6 @@ import { useIndexData } from './use_index_data'; jest.mock('../../shared_imports'); jest.mock('../app_dependencies'); -jest.mock('./use_api'); import { MlSharedContext } from '../__mocks__/shared_context'; @@ -45,13 +44,17 @@ const runtimeMappings: RuntimeMappings = { }, }; +const queryClient = new QueryClient(); + describe('Transform: useIndexData()', () => { test('dataView set triggers loading', async () => { const mlShared = await getMlSharedImports(); const wrapper: FC = ({ children }) => ( - - {children} - + + + {children} + + ); const { result, waitForNextUpdate } = renderHook( @@ -102,11 +105,13 @@ describe('Transform: with useIndexData()', () => { }; render( - - - - - + + + + + + + ); // Act @@ -142,11 +147,13 @@ describe('Transform: with useIndexData()', () => { }; render( - - - - - + + + + + + + ); // Act diff --git a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts index 3a6781615b70b..4534552f6b405 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_index_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_index_data.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef } from 'react'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { EuiDataGridColumn } from '@elastic/eui'; @@ -28,10 +28,6 @@ import { } from '@kbn/ml-data-grid'; import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker'; -import { - isEsSearchResponse, - isFieldHistogramsResponseSchema, -} from '../../../common/api_schemas/type_guards'; import { hasKeywordDuplicate, isKeywordDuplicate, @@ -44,7 +40,7 @@ import { useToastNotifications, useAppDependencies } from '../app_dependencies'; import type { StepDefineExposedState } from '../sections/create_transform/components/step_define/common'; import { SearchItems } from './use_search_items'; -import { useApi } from './use_api'; +import { useGetHistogramsForFields } from './use_get_histograms_for_fields'; import { useDataSearch } from './use_data_search'; export const useIndexData = ( @@ -52,7 +48,7 @@ export const useIndexData = ( query: TransformConfigQuery, combinedRuntimeMappings?: StepDefineExposedState['runtimeMappings'], timeRangeMs?: TimeRangeMs, - populatedFields?: Set | null + populatedFields?: string[] ): UseIndexDataReturnType => { const { analytics } = useAppDependencies(); @@ -61,13 +57,8 @@ export const useIndexData = ( const loadIndexDataStartTime = useRef(window.performance.now()); const indexPattern = useMemo(() => dataView.getIndexPattern(), [dataView]); - - const api = useApi(); - const dataSearch = useDataSearch(); const toastNotifications = useToastNotifications(); - const [dataViewFields, setDataViewFields] = useState(); - const baseFilterCriteria = buildBaseFilterCriteria( dataView.timeFieldName, timeRangeMs?.from, @@ -86,73 +77,73 @@ export const useIndexData = ( }, }; - useEffect(() => { - if (dataView.timeFieldName !== undefined && timeRangeMs === undefined) { - return; - } - const abortController = new AbortController(); - - // Fetch 500 random documents to determine populated fields. - // This is a workaround to avoid passing potentially thousands of unpopulated fields - // (for example, as part of filebeat/metricbeat/ECS based indices) - // to the data grid component which would significantly slow down the page. - const fetchDataGridSampleDocuments = async function () { - let populatedDataViewFields = populatedFields ? [...populatedFields] : []; - let isMissingFields = populatedDataViewFields.length === 0; - - // If populatedFields are not provided, make own request to calculate - if (populatedFields === undefined) { - setErrorMessage(''); - setStatus(INDEX_STATUS.LOADING); - - const esSearchRequest = { - index: indexPattern, - body: { - fields: ['*'], - _source: false, - query: { - function_score: { - query: defaultQuery, - random_score: {}, - }, - }, - size: 500, + // Fetch 500 random documents to determine populated fields. + // This is a workaround to avoid passing potentially thousands of unpopulated fields + // (for example, as part of filebeat/metricbeat/ECS based indices) + // to the data grid component which would significantly slow down the page. + const { + error: dataViewFieldsError, + data: dataViewFieldsData, + isError: dataViewFieldsIsError, + isLoading: dataViewFieldsIsLoading, + } = useDataSearch( + { + index: indexPattern, + body: { + fields: ['*'], + _source: false, + query: { + function_score: { + query: defaultQuery, + random_score: {}, }, - }; - - const resp = await dataSearch(esSearchRequest, abortController.signal); - - if (!isEsSearchResponse(resp)) { - setErrorMessage(getErrorMessage(resp)); - setStatus(INDEX_STATUS.ERROR); - return; - } - const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); - isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined'); + }, + size: 500, + }, + }, + // Check whether fetching should be enabled + // If populatedFields are not provided, make own request to calculate + !Array.isArray(populatedFields) && + !(dataView.timeFieldName !== undefined && timeRangeMs === undefined) + ); - populatedDataViewFields = [...new Set(docs.map(Object.keys).flat(1))]; - } + useEffect(() => { + if (dataViewFieldsIsLoading && !dataViewFieldsIsError) { + setErrorMessage(''); + setStatus(INDEX_STATUS.LOADING); + } else if (dataViewFieldsError !== null) { + setErrorMessage(getErrorMessage(dataViewFieldsError)); + setStatus(INDEX_STATUS.ERROR); + } else if ( + !dataViewFieldsIsLoading && + !dataViewFieldsIsError && + dataViewFieldsData !== undefined + ) { const isCrossClusterSearch = indexPattern.includes(':'); - - // Get all field names for each returned doc and flatten it - // to a list of unique field names used across all docs. - const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); - const filteredDataViewFields = populatedDataViewFields - .filter((d) => allDataViewFields.includes(d)) - .sort(); + const isMissingFields = dataViewFieldsData.hits.hits.every( + (d) => typeof d.fields === 'undefined' + ); setCcsWarning(isCrossClusterSearch && isMissingFields); setStatus(INDEX_STATUS.LOADED); - setDataViewFields(filteredDataViewFields); - }; + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dataViewFieldsData, dataViewFieldsError, dataViewFieldsIsError, dataViewFieldsIsLoading]); - fetchDataGridSampleDocuments(); + const dataViewFields = useMemo(() => { + let allPopulatedFields = Array.isArray(populatedFields) ? populatedFields : []; - return () => { - abortController.abort(); - }; + if (populatedFields === undefined && dataViewFieldsData) { + // Get all field names for each returned doc and flatten it + // to a list of unique field names used across all docs. + const docs = dataViewFieldsData.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + allPopulatedFields = [...new Set(docs.map(Object.keys).flat(1))]; + } + + const allDataViewFields = getFieldsFromKibanaIndexPattern(dataView); + return allPopulatedFields.filter((d) => allDataViewFields.includes(d)).sort(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [timeRangeMs, populatedFields?.size]); + }, [dataViewFieldsData, populatedFields]); const columns: EuiDataGridColumn[] = useMemo(() => { if (typeof dataViewFields === 'undefined') { @@ -206,132 +197,113 @@ export const useIndexData = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify([query, timeRangeMs])]); - useEffect(() => { - if (typeof dataViewFields === 'undefined') { - return; - } - const abortController = new AbortController(); + const sort: EsSorting = sortingColumns.reduce((s, column) => { + s[column.id] = { order: column.direction }; + return s; + }, {} as EsSorting); - const fetchDataGridData = async function () { + const { + error: dataGridDataError, + data: dataGridData, + isError: dataGridDataIsError, + isLoading: dataGridDataIsLoading, + } = useDataSearch( + { + index: indexPattern, + body: { + fields: ['*'], + _source: false, + query: isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, + from: pagination.pageIndex * pagination.pageSize, + size: pagination.pageSize, + ...(Object.keys(sort).length > 0 ? { sort } : {}), + ...(isRuntimeMappings(combinedRuntimeMappings) + ? { runtime_mappings: combinedRuntimeMappings } + : {}), + }, + }, + // Check whether fetching should be enabled + dataViewFields !== undefined + ); + + useEffect(() => { + if (dataGridDataIsLoading && !dataGridDataIsError) { setErrorMessage(''); setStatus(INDEX_STATUS.LOADING); - - const sort: EsSorting = sortingColumns.reduce((s, column) => { - s[column.id] = { order: column.direction }; - return s; - }, {} as EsSorting); - - const esSearchRequest = { - index: indexPattern, - body: { - fields: ['*'], - _source: false, - query: isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, - from: pagination.pageIndex * pagination.pageSize, - size: pagination.pageSize, - ...(Object.keys(sort).length > 0 ? { sort } : {}), - ...(isRuntimeMappings(combinedRuntimeMappings) - ? { runtime_mappings: combinedRuntimeMappings } - : {}), - }, - }; - const resp = await dataSearch(esSearchRequest, abortController.signal); - - if (!isEsSearchResponse(resp)) { - setErrorMessage(getErrorMessage(resp)); - setStatus(INDEX_STATUS.ERROR); - return; - } - + } else if (dataGridDataError !== null) { + setErrorMessage(getErrorMessage(dataGridDataError)); + setStatus(INDEX_STATUS.ERROR); + } else if (!dataGridDataIsLoading && !dataGridDataIsError && dataGridData !== undefined) { const isCrossClusterSearch = indexPattern.includes(':'); - const isMissingFields = resp.hits.hits.every((d) => typeof d.fields === 'undefined'); + const isMissingFields = dataGridData.hits.hits.every((d) => typeof d.fields === 'undefined'); - const docs = resp.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); + const docs = dataGridData.hits.hits.map((d) => getProcessedFields(d.fields ?? {})); setCcsWarning(isCrossClusterSearch && isMissingFields); setRowCountInfo({ - rowCount: typeof resp.hits.total === 'number' ? resp.hits.total : resp.hits.total!.value, + rowCount: + typeof dataGridData.hits.total === 'number' + ? dataGridData.hits.total + : dataGridData.hits.total!.value, rowCountRelation: - typeof resp.hits.total === 'number' + typeof dataGridData.hits.total === 'number' ? ('eq' as estypes.SearchTotalHitsRelation) - : resp.hits.total!.relation, + : dataGridData.hits.total!.relation, }); setTableItems(docs); setStatus(INDEX_STATUS.LOADED); - }; - - fetchDataGridData(); - - return () => { - abortController.abort(); - }; - // custom comparison - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - indexPattern, + } // eslint-disable-next-line react-hooks/exhaustive-deps - JSON.stringify([ - query, - pagination, - sortingColumns, - dataViewFields, + }, [dataGridDataError, dataGridDataIsError, dataGridDataIsLoading]); + + const allDataViewFieldNames = new Set(dataView.fields.map((f) => f.name)); + const { error: histogramsForFieldsError, data: histogramsForFieldsData } = + useGetHistogramsForFields( + indexPattern, + columns + .filter((cT) => dataGrid.visibleColumns.includes(cT.id)) + .map((cT) => { + // If a column field name has a corresponding keyword field, + // fetch the keyword field instead to be able to do aggregations. + const fieldName = cT.id; + return hasKeywordDuplicate(fieldName, allDataViewFieldNames) + ? { + fieldName: `${fieldName}.keyword`, + type: getFieldType(undefined), + } + : { + fieldName, + type: getFieldType(cT.schema), + }; + }), + isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, combinedRuntimeMappings, - timeRangeMs, - ]), - ]); + chartsVisible + ); useEffect(() => { - const fetchColumnChartsData = async function () { - const allDataViewFieldNames = new Set(dataView.fields.map((f) => f.name)); - const columnChartsData = await api.getHistogramsForFields( - indexPattern, - columns - .filter((cT) => dataGrid.visibleColumns.includes(cT.id)) - .map((cT) => { - // If a column field name has a corresponding keyword field, - // fetch the keyword field instead to be able to do aggregations. - const fieldName = cT.id; - return hasKeywordDuplicate(fieldName, allDataViewFieldNames) - ? { - fieldName: `${fieldName}.keyword`, - type: getFieldType(undefined), - } - : { - fieldName, - type: getFieldType(cT.schema), - }; - }), - isDefaultQuery(query) ? defaultQuery : queryWithBaseFilterCriteria, - combinedRuntimeMappings - ); - - if (!isFieldHistogramsResponseSchema(columnChartsData)) { - showDataGridColumnChartErrorMessageToast(columnChartsData, toastNotifications); - return; - } + if (histogramsForFieldsError !== null) { + showDataGridColumnChartErrorMessageToast(histogramsForFieldsError, toastNotifications); + } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [histogramsForFieldsError]); + useEffect(() => { + if (histogramsForFieldsData) { setColumnCharts( // revert field names with `.keyword` used to do aggregations to their original column name - columnChartsData.map((d) => ({ + histogramsForFieldsData.map((d) => ({ ...d, ...(isKeywordDuplicate(d.id, allDataViewFieldNames) ? { id: removeKeywordPostfix(d.id) } : {}), })) ); - }; - - if (chartsVisible) { - fetchColumnChartsData(); } // custom comparison // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - chartsVisible, - indexPattern, - // eslint-disable-next-line react-hooks/exhaustive-deps - JSON.stringify([query, dataGrid.visibleColumns, combinedRuntimeMappings, timeRangeMs]), - ]); + }, [histogramsForFieldsData]); const renderCellValue = useRenderCellValue(dataView, pagination, tableItems); diff --git a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx index af6018c35cecc..9ecd1b8717243 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reauthorize_transform.tsx @@ -6,31 +6,39 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; - -import type { StartTransformsRequestSchema } from '../../../common/api_schemas/start_transforms'; -import { isStartTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; +import type { + ReauthorizeTransformsRequestSchema, + ReauthorizeTransformsResponseSchema, +} from '../../../common/api_schemas/reauthorize_transforms'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useReauthorizeTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - - return async (transformsInfo: StartTransformsRequestSchema) => { - const results = await api.reauthorizeTransforms(transformsInfo); - if (!isStartTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: ReauthorizeTransformsRequestSchema) => + http.post( + addInternalBasePath('reauthorize_transforms'), + { + body: JSON.stringify(reqBody), + version: '1', + } + ), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.reauthorizeTransformResponseSchemaErrorMessage', @@ -38,44 +46,37 @@ export const useReauthorizeTransforms = () => { defaultMessage: 'An error occurred calling the reauthorize transforms request.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.reauthorizeTransformSuccessMessage', { - defaultMessage: 'Request to reauthorize transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addError(new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - title: i18n.translate( - 'xpack.transform.transformList.reauthorizeTransformErrorMessage', + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }), + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const result = results[transformId]; + if (!result.success) { + toastNotifications.addError( + new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - defaultMessage: 'An error occurred reauthorizing the transform {transformId}', - values: { transformId }, + title: i18n.translate( + 'xpack.transform.transformList.reauthorizeTransformErrorMessage', + { + defaultMessage: 'An error occurred reauthorizing the transform {transformId}', + values: { transformId }, + } + ), + toastMessage: result.error!.reason, } - ), - toastMessage: result.error!.reason, - }); + ); + } } } - } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - }; + refreshTransformList(); + }, + }); + + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts new file mode 100644 index 0000000000000..651886ba76f7b --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_refresh_transform_list.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useQueryClient } from '@tanstack/react-query'; + +import { TRANSFORM_REACT_QUERY_KEYS } from '../../../common/constants'; + +export const useRefreshTransformList = () => { + const queryClient = useQueryClient(); + + return () => { + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_NODES]); + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORMS]); + queryClient.invalidateQueries([TRANSFORM_REACT_QUERY_KEYS.GET_TRANSFORM_AUDIT_MESSAGES]); + }; +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx index c33cec3f5b93f..1f415eae1ad20 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_reset_transform.tsx @@ -6,107 +6,72 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; + import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; + import type { - ResetTransformStatus, ResetTransformsRequestSchema, + ResetTransformsResponseSchema, } from '../../../common/api_schemas/reset_transforms'; -import { isResetTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; +import { addInternalBasePath } from '../../../common/constants'; import { getErrorMessage } from '../../../common/utils/errors'; + import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { REFRESH_TRANSFORM_LIST_STATE, refreshTransformList$ } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; -type SuccessCountField = keyof Omit; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useResetTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - - return async (reqBody: ResetTransformsRequestSchema) => { - const results = await api.resetTransforms(reqBody); - if (!isResetTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: ResetTransformsRequestSchema) => + http.post(addInternalBasePath('reset_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate('xpack.transform.transformList.resetTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to reset transforms.', }), text: toMountPoint( - , - { theme$: theme.theme$ } + , + { + theme, + i18n: i18nStart, + } ), - }); - return; - } - - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformReset: 0, - }; - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const status = results[transformId]; + }), + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const status = results[transformId]; - // if we are only resetting one transform, show the success toast messages - if (!isBulk && status.transformReset) { - if (status.transformReset?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.resetTransformSuccessMessage', { - defaultMessage: 'Request to reset transform {transformId} acknowledged.', + if (status.transformReset?.error) { + const error = status.transformReset.error.reason; + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.transformList.resetTransformErrorMessage', { + defaultMessage: 'An error occurred resetting the transform {transformId}', values: { transformId }, - }) - ); + }), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); } - } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } - if (status.transformReset?.error) { - const error = status.transformReset.error.reason; - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.transformList.resetTransformErrorMessage', { - defaultMessage: 'An error occurred resetting the transform {transformId}', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); } } - } - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformReset > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkResetTransformSuccessMessage', { - defaultMessage: - 'Successfully reset {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformReset }, - }) - ); - } - } + refreshTransformList(); + }, + }); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - }; + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx index 8454580867391..bb568673a5758 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_schedule_now_transform.tsx @@ -6,31 +6,38 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '@kbn/react-kibana-mount'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; - -import type { ScheduleNowTransformsRequestSchema } from '../../../common/api_schemas/schedule_now_transforms'; -import { isScheduleNowTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; - +import { addInternalBasePath } from '../../../common/constants'; +import type { + ScheduleNowTransformsRequestSchema, + ScheduleNowTransformsResponseSchema, +} from '../../../common/api_schemas/schedule_now_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useScheduleNowTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - return async (transformsInfo: ScheduleNowTransformsRequestSchema) => { - const results = await api.scheduleNowTransforms(transformsInfo); - - if (!isScheduleNowTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: ScheduleNowTransformsRequestSchema) => + http.post( + addInternalBasePath('schedule_now_transforms'), + { + body: JSON.stringify(reqBody), + version: '1', + } + ), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.scheduleNowTransformResponseSchemaErrorMessage', @@ -39,46 +46,38 @@ export const useScheduleNowTransforms = () => { 'An error occurred calling the request to schedule the transform to process data instantly.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.scheduleNowTransformSuccessMessage', { - defaultMessage: - 'Request to schedule transform {transformId} to process data instantly acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addError(new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - title: i18n.translate( - 'xpack.transform.transformList.scheduleNowTransformErrorMessage', + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }), + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const result = results[transformId]; + if (!result.success) { + toastNotifications.addError( + new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - defaultMessage: - 'An error occurred scheduling transform {transformId} to process data instantly.', - values: { transformId }, + title: i18n.translate( + 'xpack.transform.transformList.scheduleNowTransformErrorMessage', + { + defaultMessage: + 'An error occurred scheduling transform {transformId} to process data instantly.', + values: { transformId }, + } + ), + toastMessage: result.error!.reason, } - ), - toastMessage: result.error!.reason, - }); + ); + } } } - } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - }; + refreshTransformList(); + }, + }); + + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx index e4d9bdfe431a9..104c3145fc259 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_start_transform.tsx @@ -6,31 +6,35 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; +import { toMountPoint } from '@kbn/react-kibana-mount'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; - -import type { StartTransformsRequestSchema } from '../../../common/api_schemas/start_transforms'; -import { isStartTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; - +import { addInternalBasePath } from '../../../common/constants'; +import type { + StartTransformsRequestSchema, + StartTransformsResponseSchema, +} from '../../../common/api_schemas/start_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useStartTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - return async (transformsInfo: StartTransformsRequestSchema) => { - const results = await api.startTransforms(transformsInfo); - - if (!isStartTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: StartTransformsRequestSchema) => + http.post(addInternalBasePath('start_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.stepCreateForm.startTransformResponseSchemaErrorMessage', @@ -38,41 +42,34 @@ export const useStartTransforms = () => { defaultMessage: 'An error occurred calling the start transforms request.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - const result = results[transformId]; - if (result.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.startTransformSuccessMessage', { - defaultMessage: 'Request to start transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addError(new Error(JSON.stringify(result.error!.caused_by, null, 2)), { - title: i18n.translate('xpack.transform.transformList.startTransformErrorMessage', { - defaultMessage: 'An error occurred starting the transform {transformId}', - values: { transformId }, - }), - toastMessage: result.error!.reason, - }); + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }), + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + const result = results[transformId]; + if (!result.success) { + toastNotifications.addError( + new Error(JSON.stringify(result.error!.caused_by, null, 2)), + { + title: i18n.translate('xpack.transform.transformList.startTransformErrorMessage', { + defaultMessage: 'An error occurred starting the transform {transformId}', + values: { transformId }, + }), + toastMessage: result.error!.reason, + } + ); + } } } - } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - }; + refreshTransformList(); + }, + }); + + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx index 39d009e471180..564b17feac3f9 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_stop_transform.tsx @@ -6,31 +6,36 @@ */ import React from 'react'; +import { useMutation } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; - -import type { StopTransformsRequestSchema } from '../../../common/api_schemas/stop_transforms'; -import { isStopTransformsResponseSchema } from '../../../common/api_schemas/type_guards'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { addInternalBasePath } from '../../../common/constants'; +import type { + StopTransformsRequestSchema, + StopTransformsResponseSchema, +} from '../../../common/api_schemas/stop_transforms'; import { getErrorMessage } from '../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; +import { useRefreshTransformList } from './use_refresh_transform_list'; export const useStopTransforms = () => { - const { overlays, theme } = useAppDependencies(); + const { http, i18n: i18nStart, theme } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); const toastNotifications = useToastNotifications(); - const api = useApi(); - - return async (transformsInfo: StopTransformsRequestSchema) => { - const results = await api.stopTransforms(transformsInfo); - if (!isStopTransformsResponseSchema(results)) { + const mutation = useMutation({ + mutationFn: (reqBody: StopTransformsRequestSchema) => + http.post(addInternalBasePath('stop_transforms'), { + body: JSON.stringify(reqBody), + version: '1', + }), + onError: (error) => toastNotifications.addDanger({ title: i18n.translate( 'xpack.transform.transformList.stopTransformResponseSchemaErrorMessage', @@ -38,39 +43,29 @@ export const useStopTransforms = () => { defaultMessage: 'An error occurred called the stop transforms request.', } ), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - return; - } - - for (const transformId in results) { - // hasOwnProperty check to ensure only properties on object itself, and not its prototypes - if (results.hasOwnProperty(transformId)) { - if (results[transformId].success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.stopTransformSuccessMessage', { - defaultMessage: 'Request to stop data frame transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } else { - toastNotifications.addDanger( - i18n.translate('xpack.transform.transformList.stopTransformErrorMessage', { - defaultMessage: 'An error occurred stopping the data frame transform {transformId}', - values: { transformId }, - }) - ); + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }), + onSuccess: (results) => { + for (const transformId in results) { + // hasOwnProperty check to ensure only properties on object itself, and not its prototypes + if (results.hasOwnProperty(transformId)) { + if (!results[transformId].success) { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.stopTransformErrorMessage', { + defaultMessage: 'An error occurred stopping the data frame transform {transformId}', + values: { transformId }, + }) + ); + } } } - } - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); - }; + refreshTransformList(); + }, + }); + + return mutation.mutate; }; diff --git a/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts new file mode 100644 index 0000000000000..f497da3bd51de --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_transform_capabilities.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + getInitialTransformCapabilities, + isTransformCapabilities, +} from '../../../common/types/capabilities'; + +import { useAppDependencies } from '../app_dependencies'; + +export const useTransformCapabilities = () => { + const { application } = useAppDependencies(); + + if (isTransformCapabilities(application?.capabilities?.transform)) { + return application.capabilities.transform; + } + + return getInitialTransformCapabilities(); +}; diff --git a/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts b/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts index f96a0f72194c6..0871dd7877c14 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_transform_config_data.ts @@ -29,14 +29,13 @@ import { } from '@kbn/ml-data-grid'; import type { PreviewMappingsProperties } from '../../../common/api_schemas/transforms'; -import { isPostTransformsPreviewResponseSchema } from '../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../common/utils/errors'; import { getPreviewTransformRequestBody, type TransformConfigQuery } from '../common'; import { SearchItems } from './use_search_items'; -import { useApi } from './use_api'; +import { useGetTransformsPreview } from './use_get_transforms_preview'; import { StepDefineExposedState } from '../sections/create_transform/components/step_define'; import { isLatestPartialRequest, @@ -111,7 +110,6 @@ export const useTransformConfigData = ( ): UseIndexDataReturnType => { const [previewMappingsProperties, setPreviewMappingsProperties] = useState({}); - const api = useApi(); // Filters mapping properties of type `object`, which get returned for nested field parents. const columnKeys = Object.keys(previewMappingsProperties).filter( @@ -147,84 +145,100 @@ export const useTransformConfigData = ( tableItems, } = dataGrid; - const getPreviewData = async () => { - if (!validationStatus.isValid) { + const previewRequest = useMemo( + () => + getPreviewTransformRequestBody( + dataView, + query, + requestPayload, + combinedRuntimeMappings, + timeRangeMs + ), + [dataView, query, requestPayload, combinedRuntimeMappings, timeRangeMs] + ); + + const { + error: previewError, + data: previewData, + isError, + isLoading, + } = useGetTransformsPreview(previewRequest, validationStatus.isValid); + + useEffect(() => { + if (isLoading) { + setErrorMessage(''); + setNoDataMessage(''); + setStatus(INDEX_STATUS.LOADING); + } else if (isError) { + setErrorMessage(getErrorMessage(previewError)); setTableItems([]); setRowCountInfo({ rowCount: 0, rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, }); - setNoDataMessage(validationStatus.errorMessage!); - return; + setPreviewMappingsProperties({}); + setStatus(INDEX_STATUS.ERROR); + } else if (!isLoading && !isError && previewData !== undefined) { + // To improve UI performance with a latest configuration for indices with a large number + // of fields, we reduce the number of available columns to those populated with values. + + // 1. Flatten the returned object structure object documents to match mapping properties + const docs = previewData.preview.map(getFlattenedObject); + + // 2. Get all field names for each returned doc and flatten it + // to a list of unique field names used across all docs. + const populatedFields = [...new Set(docs.map(Object.keys).flat(1))]; + + // 3. Filter mapping properties by populated fields + let populatedProperties: PreviewMappingsProperties = Object.entries( + previewData.generated_dest_index.mappings.properties + ) + .filter(([key]) => populatedFields.includes(key)) + .reduce( + (p, [key, value]) => ({ + ...p, + [key]: value, + }), + {} + ); + + populatedProperties = getCombinedProperties(populatedProperties, docs); + + setTableItems(docs); + setRowCountInfo({ + rowCount: docs.length, + rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, + }); + setPreviewMappingsProperties(populatedProperties); + setStatus(INDEX_STATUS.LOADED); + + if (docs.length === 0) { + setNoDataMessage( + i18n.translate('xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', { + defaultMessage: + 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', + }) + ); + } else { + setNoDataMessage(''); + } } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isError, isLoading, previewData]); - setErrorMessage(''); - setNoDataMessage(''); - setStatus(INDEX_STATUS.LOADING); - - const previewRequest = getPreviewTransformRequestBody( - dataView, - query, - requestPayload, - combinedRuntimeMappings, - timeRangeMs - ); - const resp = await api.getTransformsPreview(previewRequest); - - if (!isPostTransformsPreviewResponseSchema(resp)) { - setErrorMessage(getErrorMessage(resp)); + useEffect(() => { + if (!validationStatus.isValid) { setTableItems([]); setRowCountInfo({ rowCount: 0, rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, }); - setPreviewMappingsProperties({}); - setStatus(INDEX_STATUS.ERROR); - return; - } - - // To improve UI performance with a latest configuration for indices with a large number - // of fields, we reduce the number of available columns to those populated with values. - - // 1. Flatten the returned object structure object documents to match mapping properties - const docs = resp.preview.map(getFlattenedObject); - - // 2. Get all field names for each returned doc and flatten it - // to a list of unique field names used across all docs. - const populatedFields = [...new Set(docs.map(Object.keys).flat(1))]; - - // 3. Filter mapping properties by populated fields - let populatedProperties: PreviewMappingsProperties = Object.entries( - resp.generated_dest_index.mappings.properties - ) - .filter(([key]) => populatedFields.includes(key)) - .reduce( - (p, [key, value]) => ({ - ...p, - [key]: value, - }), - {} - ); - - populatedProperties = getCombinedProperties(populatedProperties, docs); - - setTableItems(docs); - setRowCountInfo({ - rowCount: docs.length, - rowCountRelation: ES_CLIENT_TOTAL_HITS_RELATION.EQ, - }); - setPreviewMappingsProperties(populatedProperties); - setStatus(INDEX_STATUS.LOADED); - - if (docs.length === 0) { - setNoDataMessage( - i18n.translate('xpack.transform.pivotPreview.PivotPreviewNoDataCalloutBody', { - defaultMessage: - 'The preview request did not return any data. Please ensure the optional query returns data and that values exist for the field used by group-by and aggregation fields.', - }) - ); + setNoDataMessage(validationStatus.errorMessage!); } - }; + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [validationStatus.isValid]); useEffect(() => { resetPagination(); @@ -232,15 +246,6 @@ export const useTransformConfigData = ( // eslint-disable-next-line react-hooks/exhaustive-deps }, [JSON.stringify(query)]); - useEffect(() => { - getPreviewData(); - // custom comparison - /* eslint-disable react-hooks/exhaustive-deps */ - }, [ - dataView.getIndexPattern(), - JSON.stringify([requestPayload, query, combinedRuntimeMappings, timeRangeMs]), - ]); - if (sortingColumns.length > 0) { const sortingColumnsWithTypes = sortingColumns.map((c) => { // Since items might contain undefined/null values, we want to accurate find the data type @@ -291,13 +296,7 @@ export const useTransformConfigData = ( return cellValue; }; - }, [ - pageData, - pagination.pageIndex, - pagination.pageSize, - previewMappingsProperties, - formatHumanReadableDateTimeSeconds, - ]); + }, [pageData, pagination.pageIndex, pagination.pageSize, previewMappingsProperties]); return { ...dataGrid, diff --git a/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts new file mode 100644 index 0000000000000..3859f9a8353f0 --- /dev/null +++ b/x-pack/plugins/transform/public/app/hooks/use_update_transform.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useMutation } from '@tanstack/react-query'; + +import type { + PostTransformsUpdateRequestSchema, + PostTransformsUpdateResponseSchema, +} from '../../../common/api_schemas/update_transforms'; +import { addInternalBasePath } from '../../../common/constants'; +import type { TransformId } from '../../../common/types/transform'; + +import { useAppDependencies } from '../app_dependencies'; + +import { useRefreshTransformList } from './use_refresh_transform_list'; + +export const useUpdateTransform = ( + transformId: TransformId, + transformConfig: PostTransformsUpdateRequestSchema +) => { + const { http } = useAppDependencies(); + const refreshTransformList = useRefreshTransformList(); + + const mutation = useMutation({ + mutationFn: () => + http.post( + addInternalBasePath(`transforms/${transformId}/_update`), + { + body: JSON.stringify(transformConfig), + version: '1', + } + ), + onSuccess: () => refreshTransformList(), + }); + + return mutation.mutate; +}; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx deleted file mode 100644 index 02bbe4e40a969..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/authorization_provider.tsx +++ /dev/null @@ -1,83 +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, { createContext } from 'react'; -import { useQuery } from '@tanstack/react-query'; - -import type { IHttpFetchError } from '@kbn/core-http-browser'; - -import type { Privileges } from '../../../../../common/types/privileges'; - -import { - type PrivilegesAndCapabilities, - type TransformCapabilities, - INITIAL_CAPABILITIES, -} from '../../../../../common/privilege/has_privilege_factory'; - -import { useAppDependencies } from '../../../app_dependencies'; - -interface Authorization { - isLoading: boolean; - apiError: Error | null; - privileges: Privileges; - capabilities: TransformCapabilities; -} - -const initialValue: Authorization = { - isLoading: true, - apiError: null, - privileges: { - hasAllPrivileges: false, - missingPrivileges: {}, - }, - capabilities: INITIAL_CAPABILITIES, -}; - -export const AuthorizationContext = createContext({ ...initialValue }); - -interface Props { - privilegesEndpoint: { path: string; version: string }; - children: React.ReactNode; -} - -export const AuthorizationProvider = ({ privilegesEndpoint, children }: Props) => { - const { http } = useAppDependencies(); - - const { path, version } = privilegesEndpoint; - - const { - isLoading, - error, - data: privilegesData, - } = useQuery( - ['transform-privileges-and-capabilities'], - async ({ signal }) => { - return await http.fetch(path, { - version, - method: 'GET', - signal, - }); - } - ); - - const value = { - isLoading, - privileges: - isLoading || privilegesData === undefined - ? { ...initialValue.privileges } - : privilegesData.privileges, - capabilities: - isLoading || privilegesData === undefined - ? { ...INITIAL_CAPABILITIES } - : privilegesData.capabilities, - apiError: error ? error : null, - }; - - return ( - {children} - ); -}; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts b/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts deleted file mode 100644 index cb0f248efc165..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { createCapabilityFailureMessage } from '../../../../../common/privilege/has_privilege_factory'; -export { AuthorizationProvider, AuthorizationContext } from './authorization_provider'; -export { PrivilegesWrapper } from './with_privileges'; -export { NotAuthorizedSection } from './not_authorized_section'; diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx deleted file mode 100644 index 1ab942d59c787..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/not_authorized_section.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiPageTemplate } from '@elastic/eui'; - -interface Props { - title: React.ReactNode; - message: React.ReactNode | string; -} - -export const NotAuthorizedSection = ({ title, message }: Props) => ( - {title}} - body={

{message}

} - /> -); diff --git a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx b/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx deleted file mode 100644 index a8069b2156239..0000000000000 --- a/x-pack/plugins/transform/public/app/lib/authorization/components/with_privileges.tsx +++ /dev/null @@ -1,125 +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, { useContext, FC } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { MissingPrivileges } from '../../../../../common/types/privileges'; -import { SectionLoading } from '../../../components'; -import { AuthorizationContext } from './authorization_provider'; -import { NotAuthorizedSection } from './not_authorized_section'; -import { - hasPrivilegeFactory, - toArray, - Privilege, -} from '../../../../../common/privilege/has_privilege_factory'; - -interface Props { - /** - * Each required privilege must have the format "section.privilege". - * To indicate that *all* privileges from a section are required, we can use the asterix - * e.g. "index.*" - */ - privileges: string | string[]; - children: (childrenProps: { - isLoading: boolean; - hasPrivileges: boolean; - privilegesMissing: MissingPrivileges; - }) => JSX.Element; -} - -export const WithPrivileges = ({ privileges: requiredPrivileges, children }: Props) => { - const { isLoading, privileges } = useContext(AuthorizationContext); - - const privilegesToArray: Privilege[] = toArray(requiredPrivileges).map((p) => { - const [section, privilege] = p.split('.'); - if (!privilege) { - // Oh! we forgot to use the dot "." notation. - throw new Error('Required privilege must have the format "section.privilege"'); - } - return [section, privilege]; - }); - - const hasPrivilege = hasPrivilegeFactory(privileges); - const hasPrivileges = isLoading ? false : privilegesToArray.every(hasPrivilege); - - const privilegesMissing = privilegesToArray.reduce((acc, [section, privilege]) => { - if (privilege === '*') { - acc[section] = privileges.missingPrivileges[section] || []; - } else if ( - privileges.missingPrivileges[section] && - privileges.missingPrivileges[section]!.includes(privilege) - ) { - const missing: string[] = acc[section] || []; - acc[section] = [...missing, privilege]; - } - - return acc; - }, {} as MissingPrivileges); - - return children({ isLoading, hasPrivileges, privilegesMissing }); -}; - -interface MissingClusterPrivilegesProps { - missingPrivileges: string; - privilegesCount: number; -} - -const MissingClusterPrivileges: FC = ({ - missingPrivileges, - privilegesCount, -}) => ( - - } - message={ - - } - /> -); - -export const PrivilegesWrapper: FC<{ privileges: string | string[] }> = ({ - children, - privileges, -}) => ( - - {({ isLoading, hasPrivileges, privilegesMissing }) => { - if (isLoading) { - return ( - - - - ); - } - - if (!hasPrivileges) { - return ( - - ); - } - - return <>{children}; - }} - -); diff --git a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx index 63964bc422130..47fa44a53d182 100644 --- a/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/clone_transform/clone_transform_section.tsx @@ -13,16 +13,15 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty, EuiCallOut, EuiPageTemplate, EuiSpacer } from '@elastic/eui'; -import { isHttpFetchError } from '@kbn/core-http-browser'; -import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; + import { TransformConfigUnion } from '../../../../common/types/transform'; -import { useApi } from '../../hooks/use_api'; +import { useGetTransform } from '../../hooks'; import { useDocumentationLinks } from '../../hooks/use_documentation_links'; import { useSearchItems } from '../../hooks/use_search_items'; import { BREADCRUMB_SECTION, breadcrumbService, docTitleService } from '../../services/navigation'; -import { PrivilegesWrapper } from '../../lib/authorization'; +import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; import { Wizard } from '../create_transform/components/wizard'; import { overrideTransformForCloning } from '../../common/transform'; @@ -39,8 +38,6 @@ export const CloneTransformSection: FC = ({ match, location }) => { docTitleService.setTitle('createTransform'); }, []); - const api = useApi(); - const { esTransform } = useDocumentationLinks(); const transformId = match.params.transformId; @@ -50,52 +47,55 @@ export const CloneTransformSection: FC = ({ match, location }) => { const [isInitialized, setIsInitialized] = useState(false); const { error: searchItemsError, searchItems, setSavedObjectId } = useSearchItems(undefined); - const fetchTransformConfig = async () => { + useEffect(() => { + if (dataViewId === undefined) { + setErrorMessage( + i18n.translate('xpack.transform.clone.fetchErrorPromptText', { + defaultMessage: 'Could not fetch the Kibana data view ID.', + }) + ); + } else { + setSavedObjectId(dataViewId); + } + }, [dataViewId, setSavedObjectId]); + + useEffect(() => { if (searchItemsError !== undefined) { setTransformConfig(undefined); setErrorMessage(searchItemsError); setIsInitialized(true); - return; } + }, [searchItemsError]); + + const { data: transformConfigs, error } = useGetTransform( + transformId, + searchItemsError === undefined + ); - const transformConfigs = await api.getTransform(transformId); - if (isHttpFetchError(transformConfigs)) { + useEffect(() => { + if (error !== null && error.message !== errorMessage) { setTransformConfig(undefined); - setErrorMessage(transformConfigs.message); + setErrorMessage(error.message); setIsInitialized(true); return; } - try { - if (dataViewId === undefined) { - throw new Error( - i18n.translate('xpack.transform.clone.fetchErrorPromptText', { - defaultMessage: 'Could not fetch the Kibana data view ID.', - }) - ); - } - - setSavedObjectId(dataViewId); - - setTransformConfig(overrideTransformForCloning(transformConfigs.transforms[0])); - setErrorMessage(undefined); - setIsInitialized(true); - } catch (e) { - setTransformConfig(undefined); - if (e.message !== undefined) { - setErrorMessage(e.message); - } else { - setErrorMessage(JSON.stringify(e, null, 2)); + if (transformConfigs !== undefined) { + try { + setTransformConfig(overrideTransformForCloning(transformConfigs.transforms[0])); + setErrorMessage(undefined); + setIsInitialized(true); + } catch (e) { + setTransformConfig(undefined); + if (e.message !== undefined) { + setErrorMessage(e.message); + } else { + setErrorMessage(JSON.stringify(e, null, 2)); + } + setIsInitialized(true); } - setIsInitialized(true); } - }; - - useEffect(() => { - fetchTransformConfig(); - // The effect should only be called once. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [error, errorMessage, transformConfigs]); const docsLink = ( = ({ match, location }) => { ); return ( - + = ({ match, location }) => { )} - + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx index 900af603266b8..a125da52b0cae 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_pivot_editor_switch/advanced_pivot_editor_switch.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSwitch } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx index 43c6684a5a2bc..cb21e7026f27b 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_query_editor_switch/advanced_query_editor_switch.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiSwitch } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx index 2ee8bc9995df6..c53c5dae0b4ad 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/advanced_runtime_mappings_editor_switch.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiSwitch } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { SwitchModal } from './switch_modal'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx index ff08ab37bb3e6..37dd6dd01f98e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_editor_switch/switch_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiConfirmModal } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx index db617690efc5f..8b76b8d7d7e1a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_runtime_mappings_settings/advanced_runtime_mappings_settings.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiButton, EuiButtonIcon, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx index 665c9986e6e69..4fea2f43bd5db 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/advanced_source_editor/advanced_source_editor.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap deleted file mode 100644 index 09056b8529f16..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/agg_label_form.test.tsx.snap +++ /dev/null @@ -1,72 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Date histogram aggregation 1`] = ` - - - - - the-group-by-agg-name - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap deleted file mode 100644 index 89b54e6d0a22f..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_form.test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap deleted file mode 100644 index f08d7fab7c829..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/list_summary.test.tsx.snap +++ /dev/null @@ -1,18 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - -
- the-agg -
-
- -
-`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap deleted file mode 100644 index f7b4e836ee784..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/__snapshots__/popover_form.test.tsx.snap +++ /dev/null @@ -1,48 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Aggregation Minimal initialization 1`] = ` - - - - - - - Apply - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx index fc9f91f96b3ff..b036016314754 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/agg_label_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { AggName } from '../../../../../../common/types/aggregations'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -31,8 +31,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx index 1525aa1a3320b..205fb93479339 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -29,8 +29,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx index 71d728798c8fb..d1078f4d5a87a 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/list_summary.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -26,8 +26,8 @@ describe('Transform: ', () => { list: { 'the-agg': item }, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toBe('the-agg'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx index 0587d4f0e1c46..88cdad407bd62 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/aggregation_list/popover_form.test.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { shallow } from 'enzyme'; import { fireEvent, render } from '@testing-library/react'; import React from 'react'; import { AggName } from '../../../../../../common/types/aggregations'; @@ -29,7 +28,7 @@ describe('Transform: Aggregation ', () => { const otherAggNames: AggName[] = []; const onChange = (item: PivotAggsConfig) => {}; - const wrapper = shallow( + const { getByTestId } = render( ', () => { /> ); - expect(wrapper).toMatchSnapshot(); + const input = getByTestId('transformAggName'); + expect(input).toHaveValue('the-group-by-agg-name'); }); test('preserves the field for unsupported aggs', async () => { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx index a57d83b75aa10..2f5672d3ec592 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/date_picker_apply_switch/date_picker_apply_switch.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiSwitch } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap deleted file mode 100644 index 0bb11827655e0..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_form.test.tsx.snap +++ /dev/null @@ -1,234 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Date histogram aggregation 1`] = ` - - - - the-group-by-agg-name - - - - - 1m - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformIntervalFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - -`; - -exports[`Transform: Histogram aggregation 1`] = ` - - - - the-group-by-agg-name - - - - - 100 - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformIntervalFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - -`; - -exports[`Transform: Terms aggregation 1`] = ` - - - - the-group-by-agg-name - - - - - } - closePopover={[Function]} - display="inline-block" - hasArrow={true} - id="transformIntervalFormPopover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - > - - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap deleted file mode 100644 index b1d3afeff412c..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/group_by_label_summary.test.tsx.snap +++ /dev/null @@ -1,77 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Date histogram aggregation 1`] = ` - - - - the-options-data-id - - - - - 1m - - - -`; - -exports[`Transform: Histogram aggregation 1`] = ` - - - - the-options-data-id - - - - - 100 - - - -`; - -exports[`Transform: Terms aggregation 1`] = ` - - - - the-options-data-id - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap deleted file mode 100644 index da1e9a79680ad..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_form.test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap deleted file mode 100644 index 724433a80d3a8..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/list_summary.test.tsx.snap +++ /dev/null @@ -1,24 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap deleted file mode 100644 index 9c9fb59eea4b1..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/__snapshots__/popover_form.test.tsx.snap +++ /dev/null @@ -1,18 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Group By Minimal initialization 1`] = ` - -`; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx index 09ec34f90d751..2edcfc7a9bd2c 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -29,9 +29,9 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); test('Histogram aggregation', () => { @@ -50,9 +50,9 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); test('Terms aggregation', () => { @@ -70,8 +70,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx index 689c27f5f81be..5c03d3bc8f320 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/group_by_label_summary.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -26,9 +26,9 @@ describe('Transform: ', () => { optionsDataId: 'the-options-data-id', }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); test('Histogram aggregation', () => { @@ -44,9 +44,9 @@ describe('Transform: ', () => { optionsDataId: 'the-options-data-id', }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); test('Terms aggregation', () => { @@ -61,8 +61,8 @@ describe('Transform: ', () => { optionsDataId: 'the-options-data-id', }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx index 61a11a8b551b3..eb942cad63b01 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -27,8 +27,8 @@ describe('Transform: ', () => { onChange() {}, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-group-by-agg-name'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx index 201b36a41b09c..eadddd8356e42 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/list_summary.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { PivotGroupByConfig, PIVOT_SUPPORTED_GROUP_BY_AGGS } from '../../../../common'; @@ -24,8 +24,8 @@ describe('Transform: ', () => { list: { 'the-options-data-id': item }, }; - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-options-data-id'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx index d5b1139e6cdae..4ef6cbbaf51be 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/group_by_list/popover_form.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; @@ -101,7 +101,7 @@ describe('Transform: Group By ', () => { appName: 'the-test-app', }; - const wrapper = shallow( + const { getByDisplayValue } = render( ', () => { ); - expect(wrapper.find(PopoverForm)).toMatchSnapshot(); + expect(getByDisplayValue('the-agg-name')).toBeInTheDocument(); + expect(getByDisplayValue('1m')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx index e0a52978c0b4a..42b9d556f9dc2 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/source_search_bar/source_search_bar.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiCode, EuiInputPopover } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx index 2e785c2d6680b..e2fa8912fc932 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { StepCreateForm, StepCreateFormProps } from './step_create_form'; @@ -16,6 +17,7 @@ jest.mock('../../../../app_dependencies'); describe('Transform: ', () => { test('Minimal initialization', () => { // Arrange + const queryClient = new QueryClient(); const props: StepCreateFormProps = { createDataView: false, transformId: 'the-transform-id', @@ -35,7 +37,11 @@ describe('Transform: ', () => { onChange() {}, }; - const { getByText } = render(); + const { getByText } = render( + + + + ); // Act // Assert diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx index d61b18632cef4..3c78757a6f257 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_form.tsx @@ -24,25 +24,19 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; import { DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common'; import { DuplicateDataViewError } from '@kbn/data-plugin/public'; import type { RuntimeField } from '@kbn/data-views-plugin/common'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; -import type { PutTransformsResponseSchema } from '../../../../../../common/api_schemas/transforms'; -import { - isGetTransformsStatsResponseSchema, - isPutTransformsResponseSchema, - isStartTransformsResponseSchema, -} from '../../../../../../common/api_schemas/type_guards'; import { PROGRESS_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; import { getErrorMessage } from '../../../../../../common/utils/errors'; import { getTransformProgress } from '../../../../common'; -import { useApi } from '../../../../hooks/use_api'; +import { useCreateTransform, useGetTransformStats, useStartTransforms } from '../../../../hooks'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { RedirectToTransformManagement } from '../../../../common/navigation'; import { ToastNotificationText } from '../../../../components'; @@ -92,11 +86,10 @@ export const StepCreateForm: FC = React.memo( ); const [discoverLink, setDiscoverLink] = useState(); - const deps = useAppDependencies(); - const { share } = deps; - const dataViews = deps.data.dataViews; const toastNotifications = useToastNotifications(); - const isDiscoverAvailable = deps.application.capabilities.discover?.show ?? false; + const { application, data, i18n: i18nStart, share, theme } = useAppDependencies(); + const dataViews = data.dataViews; + const isDiscoverAvailable = application.capabilities.discover?.show ?? false; useEffect(() => { let unmounted = false; @@ -128,104 +121,38 @@ export const StepCreateForm: FC = React.memo( // eslint-disable-next-line react-hooks/exhaustive-deps }, [created, started, dataViewId]); - const { overlays, theme } = useAppDependencies(); - const api = useApi(); + const startTransforms = useStartTransforms(); + const createTransform = useCreateTransform(); - async function createTransform() { + function createTransformHandler(startAfterCreation = false) { setLoading(true); - const resp = await api.createTransform(transformId, transformConfig); - - if (!isPutTransformsResponseSchema(resp) || resp.errors.length > 0) { - let respErrors: - | PutTransformsResponseSchema['errors'] - | PutTransformsResponseSchema['errors'][number] - | undefined; - - if (isPutTransformsResponseSchema(resp) && resp.errors.length > 0) { - respErrors = resp.errors.length === 1 ? resp.errors[0] : resp.errors; + createTransform( + { transformId, transformConfig }, + { + onError: () => setCreated(false), + onSuccess: () => { + setCreated(true); + if (createDataView) { + createKibanaDataView(); + } + if (startAfterCreation) { + startTransform(); + } + }, + onSettled: () => setLoading(false), } - - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.createTransformErrorMessage', { - defaultMessage: 'An error occurred creating the transform {transformId}:', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - setCreated(false); - setLoading(false); - return false; - } - - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.createTransformSuccessMessage', { - defaultMessage: 'Request to create transform {transformId} acknowledged.', - values: { transformId }, - }) ); - setCreated(true); - setLoading(false); - - if (createDataView) { - createKibanaDataView(); - } - - return true; } - async function startTransform() { + function startTransform() { setLoading(true); - const resp = await api.startTransforms([{ id: transformId }]); - - if (isStartTransformsResponseSchema(resp) && resp[transformId]?.success === true) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.startTransformSuccessMessage', { - defaultMessage: 'Request to start transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - setStarted(true); - setLoading(false); - return; - } - - const errorMessage = - isStartTransformsResponseSchema(resp) && resp[transformId]?.success === false - ? resp[transformId].error - : resp; - - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.startTransformErrorMessage', { - defaultMessage: 'An error occurred starting the transform {transformId}:', - values: { transformId }, - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + startTransforms([{ id: transformId }], { + onError: () => setStarted(false), + onSuccess: (resp) => setStarted(resp[transformId]?.success === true), + onSettled: () => setLoading(false), }); - setStarted(false); - setLoading(false); - } - - async function createAndStartTransform() { - const acknowledged = await createTransform(); - if (acknowledged) { - await startTransform(); - } } const createKibanaDataView = async () => { @@ -250,13 +177,6 @@ export const StepCreateForm: FC = React.memo( true ); - toastNotifications.addSuccess( - i18n.translate('xpack.transform.stepCreateForm.createDataViewSuccessMessage', { - defaultMessage: 'Kibana data view {dataViewName} created successfully.', - values: { dataViewName }, - }) - ); - setDataViewId(newDataView.id); setLoading(false); return true; @@ -275,10 +195,10 @@ export const StepCreateForm: FC = React.memo( defaultMessage: 'An error occurred creating the Kibana data view {dataViewName}:', values: { dataViewName }, }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), }); setLoading(false); return false; @@ -288,57 +208,59 @@ export const StepCreateForm: FC = React.memo( const isBatchTransform = typeof transformConfig.sync === 'undefined'; - if ( - loading === false && - started === true && - progressPercentComplete === undefined && - isBatchTransform - ) { - // wrapping in function so we can keep the interval id in local scope - function startProgressBar() { - const interval = setInterval(async () => { - const stats = await api.getTransformStats(transformId); - - if ( - isGetTransformsStatsResponseSchema(stats) && - Array.isArray(stats.transforms) && - stats.transforms.length > 0 - ) { - const percent = - getTransformProgress({ - id: transformId, - config: { - ...transformConfig, - id: transformId, - }, - stats: stats.transforms[0], - }) || 0; - setProgressPercentComplete(percent); - if (percent >= 100) { - clearInterval(interval); - } - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { - defaultMessage: 'An error occurred getting the progress percentage:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - clearInterval(interval); - } - }, PROGRESS_REFRESH_INTERVAL_MS); + useEffect(() => { + if ( + loading === false && + started === true && + progressPercentComplete === undefined && + isBatchTransform + ) { setProgressPercentComplete(0); } + }, [loading, started, progressPercentComplete, isBatchTransform]); + + const progressBarRefetchEnabled = + isBatchTransform && + typeof progressPercentComplete === 'number' && + progressPercentComplete < 100; + const progressBarRefetchInterval = progressBarRefetchEnabled + ? PROGRESS_REFRESH_INTERVAL_MS + : false; + + const { data: stats } = useGetTransformStats( + transformId, + progressBarRefetchEnabled, + progressBarRefetchInterval + ); + + useEffect(() => { + if (stats === undefined) { + return; + } - startProgressBar(); - } + if (stats && Array.isArray(stats.transforms) && stats.transforms.length > 0) { + const percent = + getTransformProgress({ + id: transformId, + config: { + ...transformConfig, + id: transformId, + }, + stats: stats.transforms[0], + }) || 0; + setProgressPercentComplete(percent); + } else { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepCreateForm.progressErrorMessage', { + defaultMessage: 'An error occurred getting the progress percentage:', + }), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); + } + }, [i18nStart, stats, theme, toastNotifications, transformConfig, transformId]); function getTransformConfigDevConsoleStatement() { return `PUT _transform/${transformId}\n${JSON.stringify(transformConfig, null, 2)}\n\n`; @@ -362,7 +284,7 @@ export const StepCreateForm: FC = React.memo( createTransformHandler(true)} data-test-subj="transformWizardCreateAndStartButton" > {i18n.translate('xpack.transform.stepCreateForm.createAndStartTransformButton', { @@ -436,7 +358,7 @@ export const StepCreateForm: FC = React.memo( createTransformHandler()} data-test-subj="transformWizardCreateButton" > {i18n.translate('xpack.transform.stepCreateForm.createTransformButton', { diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx index b7704044fe0b3..2be067c777a1e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_create/step_create_summary.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; export const StepCreateSummary: FC = React.memo(() => { return null; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx index 0c6fae30fd1f0..c35cca74c72ac 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/common/filter_agg/components/filter_term_form.tsx @@ -6,7 +6,7 @@ */ import { debounce } from 'lodash'; -import React, { useCallback, useContext, useEffect, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; import useUpdateEffect from 'react-use/lib/useUpdateEffect'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -18,7 +18,6 @@ import { i18n } from '@kbn/i18n'; import { isMultiBucketAggregate } from '@kbn/ml-agg-utils'; import { useDataSearch } from '../../../../../../../hooks/use_data_search'; -import { isEsSearchResponseWithAggregations } from '../../../../../../../../../common/api_schemas/type_guards'; import { CreateTransformWizardContext } from '../../../../wizard/wizard'; import { useToastNotifications } from '../../../../../../../app_dependencies'; @@ -33,16 +32,22 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm selectedField, }) => { const { dataView, runtimeMappings } = useContext(CreateTransformWizardContext); - const dataSearch = useDataSearch(); const toastNotifications = useToastNotifications(); - const [options, setOptions] = useState([]); - const [isLoading, setIsLoading] = useState(true); const [searchValue, setSearchValue] = useState(''); + const debouncedOnSearchChange = useMemo( + () => debounce((d: string) => setSearchValue(d), 600), + [] + ); - const onSearchChange = (newSearchValue: string) => { - setSearchValue(newSearchValue); - }; + useEffect(() => { + // Simulate initial load. + debouncedOnSearchChange(''); + // Cancel debouncing when unmounting + return () => debouncedOnSearchChange.cancel(); + // Only call on mount + /* eslint-disable-next-line react-hooks/exhaustive-deps */ + }, []); const updateConfig = useCallback( (update) => { @@ -56,80 +61,53 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm [config, onChange] ); - useEffect(() => { - const abortController = new AbortController(); - - const fetchOptions = debounce(async () => { - if (selectedField === undefined) return; - - setIsLoading(true); - setOptions([]); - - const esSearchRequest = { - index: dataView!.title, - body: { - ...(runtimeMappings !== undefined ? { runtime_mappings: runtimeMappings } : {}), - query: { - wildcard: { - [selectedField!]: { - value: `*${searchValue}*`, - }, + const { data, isError, isLoading } = useDataSearch( + { + index: dataView!.title, + body: { + ...(runtimeMappings !== undefined ? { runtime_mappings: runtimeMappings } : {}), + query: { + wildcard: { + [selectedField!]: { + value: `*${searchValue}*`, }, }, - aggs: { - field_values: { - terms: { - field: selectedField, - size: 10, - }, + }, + aggs: { + field_values: { + terms: { + field: selectedField, + size: 10, }, }, - size: 0, }, - }; - - const response = await dataSearch(esSearchRequest, abortController.signal); - - setIsLoading(false); - - if ( - !( - isEsSearchResponseWithAggregations(response) && - isMultiBucketAggregate( - response.aggregations.field_values - ) - ) - ) { - toastNotifications.addWarning( - i18n.translate('xpack.transform.agg.popoverForm.filerAgg.term.errorFetchSuggestions', { - defaultMessage: 'Unable to fetch suggestions', - }) - ); - return; - } + size: 0, + }, + }, + // Check whether fetching should be enabled + selectedField !== undefined + ); - setOptions( - ( - response.aggregations.field_values - .buckets as estypes.AggregationsSignificantLongTermsBucket[] - ).map((value) => ({ label: value.key + '' })) + useEffect(() => { + if (isError) { + toastNotifications.addWarning( + i18n.translate('xpack.transform.agg.popoverForm.filerAgg.term.errorFetchSuggestions', { + defaultMessage: 'Unable to fetch suggestions', + }) ); - }, 600); - - fetchOptions(); - - return () => { - // make sure the ongoing request is canceled - fetchOptions.cancel(); - abortController.abort(); - }; + } /* eslint-disable-next-line react-hooks/exhaustive-deps */ - }, [selectedField]); - - useEffect(() => { - // Simulate initial load. - onSearchChange(''); - }, []); + }, [isError]); + + const options: EuiComboBoxOptionOption[] = + isMultiBucketAggregate( + data?.aggregations?.field_values + ) + ? ( + data?.aggregations?.field_values + .buckets as estypes.AggregationsSignificantLongTermsBucket[] + ).map((value) => ({ label: value.key + '' })) + : []; useUpdateEffect(() => { // Reset value control on field change @@ -168,7 +146,7 @@ export const FilterTermForm: FilterAggConfigTerm['aggTypeConfig']['FilterAggForm onCreateOption={(value) => { updateConfig({ value }); }} - onSearchChange={onSearchChange} + onSearchChange={debouncedOnSearchChange} data-test-subj="transformFilterTermValueSelector" /> diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx index a83c7c7a5871c..ba0d9e93e2cce 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/latest_function_form.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButtonIcon, EuiCallOut, EuiComboBox, EuiCopy, EuiFormRow } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx index efa28de596a18..861aeb778af74 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/pivot_function_form.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiButton, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx index 6d5d6d0ea6fc9..3470cf5706a2e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { I18nProvider } from '@kbn/i18n-react'; import { DatePickerContextProvider, type DatePickerDependencies } from '@kbn/ml-date-picker'; @@ -66,6 +67,7 @@ const createMockStorage = () => ({ describe('Transform: ', () => { test('Minimal initialization', async () => { // Arrange + const queryClient = new QueryClient(); const mlSharedImports = await getMlSharedImports(); const searchItems = { @@ -87,13 +89,15 @@ describe('Transform: ', () => { const { getByText } = render( - - - - - - - + + + + + + + + + ); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx index 81bdb47735a37..246460d11d3ee 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_form.tsx @@ -78,6 +78,9 @@ const ALLOW_TIME_RANGE_ON_TRANSFORM_CONFIG = false; const advancedEditorsSidebarWidth = '220px'; +type PopulatedFields = Set; +const isPopulatedFields = (arg: unknown): arg is PopulatedFields => arg instanceof Set; + export const ConfigSectionTitle: FC<{ title: string }> = ({ title }) => ( <> @@ -132,7 +135,9 @@ export const StepDefineForm: FC = React.memo((props) => { transformConfigQuery, runtimeMappings, timeRangeMs, - fieldStatsContext?.populatedFields ?? null + isPopulatedFields(fieldStatsContext?.populatedFields) + ? [...fieldStatsContext.populatedFields] + : [] ), dataTestSubj: 'transformIndexPreview', toastNotifications, diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx index 85cef1fb2958e..4f378d4394da0 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/step_define_summary.test.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { PIVOT_SUPPORTED_AGGS } from '../../../../../../common/types/pivot_aggs'; @@ -30,6 +31,7 @@ describe('Transform: ', () => { // Using the async/await wait()/done() pattern to avoid act() errors. test('Minimal initialization', async () => { // Arrange + const queryClient = new QueryClient(); const mlSharedImports = await getMlSharedImports(); const searchItems = { @@ -78,9 +80,11 @@ describe('Transform: ', () => { }; const { queryByText } = render( - - - + + + + + ); // Act diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx index 3aec137a3adf8..441e18ebb43d2 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_define/transform_function_selector.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiCard, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; import { TRANSFORM_FUNCTION, TransformFunction } from '../../../../../../common/constants'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx index 4e8104a7645ee..da9ebbf9b2ef7 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_form.tsx @@ -25,15 +25,9 @@ import { } from '@elastic/eui'; import { KBN_FIELD_TYPES } from '@kbn/field-types'; -import { toMountPoint } from '@kbn/kibana-react-plugin/public'; +import { toMountPoint } from '@kbn/react-kibana-mount'; -import { isHttpFetchError } from '@kbn/core-http-browser'; import { retentionPolicyMaxAgeInvalidErrorMessage } from '../../../../common/constants/validation_messages'; -import { - isEsIndices, - isEsIngestPipelines, - isPostTransformsPreviewResponseSchema, -} from '../../../../../../common/api_schemas/type_guards'; import { DEFAULT_TRANSFORM_FREQUENCY } from '../../../../../../common/constants'; import { TransformId } from '../../../../../../common/types/transform'; import { isValidIndexName } from '../../../../../../common/utils/es_utils'; @@ -42,16 +36,22 @@ import { getErrorMessage } from '../../../../../../common/utils/errors'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { ToastNotificationText } from '../../../../components'; -import { useDocumentationLinks } from '../../../../hooks/use_documentation_links'; +import { + useDocumentationLinks, + useGetDataViewTitles, + useGetEsIndices, + useGetEsIngestPipelines, + useGetTransforms, + useGetTransformsPreview, +} from '../../../../hooks'; import { SearchItems } from '../../../../hooks/use_search_items'; -import { useApi } from '../../../../hooks/use_api'; import { StepDetailsTimeField } from './step_details_time_field'; import { getTransformConfigQuery, getPreviewTransformRequestBody, isTransformIdValid, } from '../../../../common'; -import { EsIndexName, DataViewTitle } from './common'; +import { EsIndexName } from './common'; import { continuousModeDelayValidator, integerRangeMinus1To100Validator, @@ -73,8 +73,8 @@ interface StepDetailsFormProps { export const StepDetailsForm: FC = React.memo( ({ overrides = {}, onChange, searchItems, stepDefineState }) => { - const deps = useAppDependencies(); - const { capabilities } = deps.application; + const { application, i18n: i18nStart, theme } = useAppDependencies(); + const { capabilities } = application; const toastNotifications = useToastNotifications(); const { esIndicesCreateIndex } = useDocumentationLinks(); @@ -90,19 +90,15 @@ export const StepDetailsForm: FC = React.memo( const [destinationIngestPipeline, setDestinationIngestPipeline] = useState( defaults.destinationIngestPipeline ); - const [transformIds, setTransformIds] = useState([]); - const [indexNames, setIndexNames] = useState([]); - const [ingestPipelineNames, setIngestPipelineNames] = useState([]); const canCreateDataView = useMemo( () => - capabilities.savedObjectsManagement.edit === true || - capabilities.indexPatterns.save === true, + capabilities.savedObjectsManagement?.edit === true || + capabilities.indexPatterns?.save === true, [capabilities] ); // Index pattern state - const [dataViewTitles, setDataViewTitles] = useState([]); const [createDataView, setCreateDataView] = useState( canCreateDataView === false ? false : defaults.createDataView ); @@ -125,126 +121,122 @@ export const StepDetailsForm: FC = React.memo( [setDataViewTimeField, dataViewAvailableTimeFields] ); - const { overlays, theme } = useAppDependencies(); - const api = useApi(); + const { + error: transformsError, + data: { transformIds }, + } = useGetTransforms(); + + useEffect(() => { + if (transformsError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { + defaultMessage: 'An error occurred getting the existing transform IDs:', + }), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); + } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [transformsError]); + + const previewRequest = useMemo(() => { + const { searchQuery, previewRequest: partialPreviewRequest } = stepDefineState; + const transformConfigQuery = getTransformConfigQuery(searchQuery); + return getPreviewTransformRequestBody( + searchItems.dataView, + transformConfigQuery, + partialPreviewRequest, + stepDefineState.runtimeMappings + ); + }, [searchItems.dataView, stepDefineState]); + const { error: transformsPreviewError, data: transformPreview } = + useGetTransformsPreview(previewRequest); - // fetch existing transform IDs and indices once for form validation useEffect(() => { - // use an IIFE to avoid returning a Promise to useEffect. - (async function () { - const { searchQuery, previewRequest: partialPreviewRequest } = stepDefineState; - const transformConfigQuery = getTransformConfigQuery(searchQuery); - const previewRequest = getPreviewTransformRequestBody( - searchItems.dataView, - transformConfigQuery, - partialPreviewRequest, - stepDefineState.runtimeMappings + if (transformPreview) { + const properties = transformPreview.generated_dest_index.mappings.properties; + const timeFields: string[] = Object.keys(properties).filter( + (col) => properties[col].type === 'date' ); - const transformPreview = await api.getTransformsPreview(previewRequest); - - if (isPostTransformsPreviewResponseSchema(transformPreview)) { - const properties = transformPreview.generated_dest_index.mappings.properties; - const timeFields: string[] = Object.keys(properties).filter( - (col) => properties[col].type === 'date' - ); - - setDataViewAvailableTimeFields(timeFields); - setDataViewTimeField(timeFields[0]); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformPreview', { - defaultMessage: 'An error occurred fetching the transform preview', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } + setDataViewAvailableTimeFields(timeFields); + setDataViewTimeField(timeFields[0]); + } + }, [transformPreview]); - const resp = await api.getTransforms(); - - if (isHttpFetchError(resp)) { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformList', { - defaultMessage: 'An error occurred getting the existing transform IDs:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } else { - setTransformIds(resp.transforms.map((transform) => transform.id)); - } + useEffect(() => { + if (transformsPreviewError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingTransformPreview', { + defaultMessage: 'An error occurred fetching the transform preview', + }), + text: toMountPoint( + , + { theme, i18n: i18nStart } + ), + }); + } + // custom comparison + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [transformsPreviewError]); - const [indices, ingestPipelines] = await Promise.all([ - api.getEsIndices(), - api.getEsIngestPipelines(), - ]); - - if (isEsIndices(indices)) { - setIndexNames(indices.map((index) => index.name)); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { - defaultMessage: 'An error occurred getting the existing index names:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } + const { error: esIndicesError, data: esIndicesData } = useGetEsIndices(); + const indexNames = esIndicesData?.map((index) => index.name) ?? []; - if (isEsIngestPipelines(ingestPipelines)) { - setIngestPipelineNames(ingestPipelines.map(({ name }) => name)); - } else { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIngestPipelines', { - defaultMessage: 'An error occurred getting the existing ingest pipeline names:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } + useEffect(() => { + if (esIndicesError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIndexNames', { + defaultMessage: 'An error occurred getting the existing index names:', + }), + text: toMountPoint(, { + theme, + i18n: i18nStart, + }), + }); + } + // custom comparison + /* eslint-disable react-hooks/exhaustive-deps */ + }, [esIndicesError]); - try { - setDataViewTitles(await deps.data.dataViews.getTitles()); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingDataViewTitles', { - defaultMessage: 'An error occurred getting the existing data view titles:', - }), - text: toMountPoint( - , - { theme$: theme.theme$ } - ), - }); - } - })(); - // run once - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const { error: esIngestPipelinesError, data: esIngestPipelinesData } = + useGetEsIngestPipelines(); + const ingestPipelineNames = esIngestPipelinesData?.map(({ name }) => name) ?? []; + + useEffect(() => { + if (esIngestPipelinesError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingIngestPipelines', { + defaultMessage: 'An error occurred getting the existing ingest pipeline names:', + }), + text: toMountPoint( + , + { theme, i18n: i18nStart } + ), + }); + } + // custom comparison + /* eslint-disable react-hooks/exhaustive-deps */ + }, [esIngestPipelinesError]); + + const { error: dataViewTitlesError, data: dataViewTitles } = useGetDataViewTitles(); + + useEffect(() => { + if (dataViewTitlesError !== null) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.transform.stepDetailsForm.errorGettingDataViewTitles', { + defaultMessage: 'An error occurred getting the existing data view titles:', + }), + text: toMountPoint( + , + { theme, i18n: i18nStart } + ), + }); + } + }, [dataViewTitlesError]); const dateFieldNames = searchItems.dataView.fields .filter((f) => f.type === KBN_FIELD_TYPES.DATE) @@ -284,7 +276,6 @@ export const StepDetailsForm: FC = React.memo( ); setRetentionPolicyMaxAge(''); } - // eslint-disable-next-line react-hooks/exhaustive-deps }, [isRetentionPolicyEnabled]); const transformIdExists = transformIds.some((id) => transformId === id); @@ -294,7 +285,7 @@ export const StepDetailsForm: FC = React.memo( const indexNameExists = indexNames.some((name) => destinationIndex === name); const indexNameEmpty = destinationIndex === ''; const indexNameValid = isValidIndexName(destinationIndex); - const dataViewTitleExists = dataViewTitles.some((name) => destinationIndex === name); + const dataViewTitleExists = dataViewTitles?.some((name) => destinationIndex === name) ?? false; const [transformFrequency, setTransformFrequency] = useState(defaults.transformFrequency); const isTransformFrequencyValid = transformFrequencyValidator(transformFrequency); diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx index 80203af34e105..b3b11a6e4764e 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_summary.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx index d750bf6c7e1fd..76ce803bdb415 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/step_details/step_details_time_field.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiFormRow, EuiSelect } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx index 2d2a5b1fcad93..cbc53383541ed 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/switch_modal/switch_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiConfirmModal } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx index 103b8378cef7f..2ffb8437d4861 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/components/wizard_nav/wizard_nav.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx b/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx index e8780ba180e8d..6ee4d5c812f73 100644 --- a/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/create_transform/create_transform_section.tsx @@ -8,12 +8,14 @@ import React, { FC, useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n-react'; + import { EuiButtonEmpty, EuiCallOut, EuiPageTemplate, EuiSpacer } from '@elastic/eui'; -import { APP_CREATE_TRANSFORM_CLUSTER_PRIVILEGES } from '../../../../common/constants'; + import { useDocumentationLinks } from '../../hooks/use_documentation_links'; import { useSearchItems } from '../../hooks/use_search_items'; -import { BREADCRUMB_SECTION, breadcrumbService, docTitleService } from '../../services/navigation'; -import { PrivilegesWrapper } from '../../lib/authorization'; +import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; +import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; + import { Wizard } from './components/wizard'; type Props = RouteComponentProps<{ savedObjectId: string }>; @@ -43,7 +45,14 @@ export const CreateTransformSection: FC = ({ match }) => { ); return ( - + = ({ match }) => { )} {searchItems !== undefined && } - + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap deleted file mode 100644 index 8348f93b32140..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/__snapshots__/transform_management_section.test.tsx.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Minimal initialization 1`] = ` - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx index e6f3eeb4a9064..21c33361e398b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/clone_action_name.tsx @@ -5,11 +5,12 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; export const cloneActionNameText = i18n.translate( 'xpack.transform.transformList.cloneActionNameText', diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx index 35d5e9f05c315..d78211e19bdb4 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_clone/use_clone_action.tsx @@ -5,14 +5,13 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; import { SECTION_SLUG } from '../../../../common/constants'; -import { useSearchItems } from '../../../../hooks/use_search_items'; +import { useTransformCapabilities, useSearchItems } from '../../../../hooks'; import { useAppDependencies, useToastNotifications } from '../../../../app_dependencies'; import { cloneActionNameText, CloneActionName } from './clone_action_name'; @@ -26,7 +25,7 @@ export const useCloneAction = (forceDisable: boolean, transformNodes: number) => const { getDataViewIdByTitle, loadDataViews } = useSearchItems(undefined); - const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + const { canCreateTransform } = useTransformCapabilities(); const clickHandler = useCallback( async (item: TransformListRow) => { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx index c8d67a86d579a..fec35288d80b5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/create_alert_rule_action_name.tsx @@ -5,11 +5,13 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; + +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; interface CreateAlertRuleActionProps { disabled: boolean; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx index 070f1eb08ac60..af75222fa85e7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_create_alert/use_create_alert_rule_action.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo } from 'react'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import React, { useCallback, useMemo } from 'react'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListAction, TransformListRow } from '../../../../common'; import { crateAlertRuleActionNameText, @@ -17,7 +17,7 @@ import { isContinuousTransform } from '../../../../../../common/types/transform' export type CreateAlertRuleAction = ReturnType; export const useCreateAlertRuleAction = (forceDisable: boolean) => { - const { canCreateTransformAlerts } = useContext(AuthorizationContext).capabilities; + const { canCreateTransformAlerts } = useTransformCapabilities(); const { setCreateAlertRule } = useAlertRuleFlyout(); const clickHandler = useCallback( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap deleted file mode 100644 index fe1e813ca9843..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/__snapshots__/delete_action_name.test.tsx.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - Delete - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx index 1fb0d69682cda..37daeeb75e138 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { DeleteActionName, DeleteActionNameProps } from './delete_action_name'; @@ -21,7 +21,7 @@ describe('Transform: Transform List Actions ', () => { isBulkAction: false, }; - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + const { container } = render(); + expect(container.textContent).toBe('Delete'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx index fa1142938efe7..93e346e6c7a1d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/delete_action_name.tsx @@ -5,11 +5,15 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; + import { EuiToolTip } from '@elastic/eui'; + import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + import { TransformListRow } from '../../../../common'; export const deleteActionNameText = i18n.translate( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx index 357809b54746b..5996e271604e3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_delete/use_delete_action.tsx @@ -5,13 +5,16 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useDeleteIndexAndTargetIndex, useDeleteTransforms } from '../../../../hooks'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { + useDeleteIndexAndTargetIndex, + useDeleteTransforms, + useTransformCapabilities, +} from '../../../../hooks'; import { deleteActionNameText, @@ -21,7 +24,7 @@ import { export type DeleteAction = ReturnType; export const useDeleteAction = (forceDisable: boolean) => { - const { canDeleteTransform } = useContext(AuthorizationContext).capabilities; + const { canDeleteTransform } = useTransformCapabilities(); const deleteTransforms = useDeleteTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx index f7cc72c2236b0..c3d359e648c28 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_discover/discover_action_name.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx index 3bf5ee8e611f6..7fc16ebfff278 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/edit_action_name.tsx @@ -5,16 +5,15 @@ * 2.0. */ -import React, { useContext, FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + +import { useTransformCapabilities } from '../../../../hooks'; export const editActionNameText = i18n.translate( 'xpack.transform.transformList.editActionNameText', @@ -24,7 +23,7 @@ export const editActionNameText = i18n.translate( ); export const EditActionName: FC = () => { - const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + const { canCreateTransform } = useTransformCapabilities(); if (!canCreateTransform) { return ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx index 19d60b8b64381..40e7334197b0c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_edit/use_edit_action.tsx @@ -5,12 +5,12 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; import { editActionNameText, EditActionName } from './edit_action_name'; import { useSearchItems } from '../../../../hooks/use_search_items'; @@ -19,7 +19,7 @@ import { TransformConfigUnion } from '../../../../../../common/types/transform'; export type EditAction = ReturnType; export const useEditAction = (forceDisable: boolean, transformNodes: number) => { - const { canCreateTransform } = useContext(AuthorizationContext).capabilities; + const { canCreateTransform } = useTransformCapabilities(); const [config, setConfig] = useState(); const [isFlyoutVisible, setIsFlyoutVisible] = useState(false); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx index 9e848fdd8323e..edfde117abbd7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EUI_MODAL_CONFIRM_BUTTON, EuiConfirmModal } from '@elastic/eui'; import type { ReauthorizeAction } from './use_reauthorize_action'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx index e07ae03ec46b0..ee883a3e7e77b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/reauthorize_action_name.tsx @@ -5,14 +5,16 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; -import { i18n } from '@kbn/i18n'; +import React, { type FC } from 'react'; + import { EuiToolTip, EuiText } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + import { needsReauthorization } from '../../../../common/reauthorization_utils'; -import { - AuthorizationContext, - createCapabilityFailureMessage, -} from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListRow } from '../../../../common'; export const reauthorizeActionNameText = i18n.translate( @@ -45,7 +47,7 @@ export const ReauthorizeActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useTransformCapabilities(); // Disable start for batch transforms which have completed. const someNeedsReauthorization = items.some(needsReauthorization); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx index 086f5451d53be..67e618765e42e 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reauthorize/use_reauthorize_action.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { sortTransformsToReauthorize } from './sort_transforms_to_reauthorize'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; @@ -17,11 +17,11 @@ import { } from './reauthorize_action_name'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; export type ReauthorizeAction = ReturnType; export const useReauthorizeAction = (forceDisable: boolean, transformNodes: number) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const reauthorizeTransforms = useReauthorizeTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx index c6ea0f5f7270d..6d5f56d3e7297 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/reset_action_name.tsx @@ -5,11 +5,15 @@ * 2.0. */ -import React, { FC } from 'react'; -import { i18n } from '@kbn/i18n'; +import React, { type FC } from 'react'; + import { EuiToolTip } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; + import { TransformState, TRANSFORM_STATE } from '../../../../../../common/constants'; -import { createCapabilityFailureMessage } from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + import { TransformListRow } from '../../../../common'; export const resetActionNameText = i18n.translate( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx index 70164bc22a63c..23a399fdb9086 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_reset/use_reset_action.tsx @@ -5,19 +5,18 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useResetTransforms } from '../../../../hooks'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useTransformCapabilities, useResetTransforms } from '../../../../hooks'; import { resetActionNameText, isResetActionDisabled, ResetActionName } from './reset_action_name'; export type ResetAction = ReturnType; export const useResetAction = (forceDisable: boolean) => { - const { canResetTransform } = useContext(AuthorizationContext).capabilities; + const { canResetTransform } = useTransformCapabilities(); const resetTransforms = useResetTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx index 71b6a055c0d94..0c3be1cdad70b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/schedule_now_action_name.tsx @@ -5,14 +5,15 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; -import { i18n } from '@kbn/i18n'; +import React, { type FC } from 'react'; + import { EuiToolTip } from '@elastic/eui'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { i18n } from '@kbn/i18n'; + +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListRow, isCompletedBatchTransform } from '../../../../common'; export const scheduleNowActionNameText = i18n.translate( @@ -48,7 +49,7 @@ export const ScheduleNowActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canScheduleNowTransform } = useContext(AuthorizationContext).capabilities; + const { canScheduleNowTransform } = useTransformCapabilities(); const isBulkAction = items.length > 1; // Disable schedule-now for batch transforms which have completed. diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx index dda70deb225a6..a13d3da89f677 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_schedule_now/use_schedule_now_action.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import React, { useContext, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListAction, TransformListRow } from '../../../../common'; import { useScheduleNowTransforms } from '../../../../hooks'; @@ -21,8 +21,7 @@ import { export type ScheduleNowAction = ReturnType; export const useScheduleNowAction = (forceDisable: boolean, transformNodes: number) => { - const { canScheduleNowTransform } = useContext(AuthorizationContext).capabilities; - + const { canScheduleNowTransform } = useTransformCapabilities(); const scheduleNowTransforms = useScheduleNowTransforms(); const action: TransformListAction = useMemo( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap deleted file mode 100644 index 20b0691b55bf9..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/__snapshots__/start_action_name.test.tsx.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - Start - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx index 7ad6897034e10..ab98f36222957 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_modal.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiConfirmModal, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; import { StartAction } from './use_start_action'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx index ba4619b022620..6ef0a995186c7 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.test.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformListRow } from '../../../../common'; import { StartActionName, StartActionNameProps } from './start_action_name'; @@ -16,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); +const queryClient = new QueryClient(); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { // @ts-expect-error mock data is too loosely typed @@ -26,8 +29,11 @@ describe('Transform: Transform List Actions ', () => { transformNodes: 1, }; - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); + const { container } = render( + + + + ); + expect(container.textContent).toBe('Start'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx index 844d9755d7073..c50c83d25edc5 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/start_action_name.tsx @@ -5,16 +5,14 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; import { TransformListRow, isCompletedBatchTransform } from '../../../../common'; export const startActionNameText = i18n.translate( @@ -55,7 +53,7 @@ export const StartActionName: FC = ({ forceDisable, transformNodes, }) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const isBulkAction = items.length > 1; // Disable start for batch transforms which have completed. diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx index 20910cf5fa0a5..168174730b706 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_start/use_start_action.tsx @@ -5,19 +5,18 @@ * 2.0. */ -import React, { useContext, useMemo, useState } from 'react'; +import React, { useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useStartTransforms } from '../../../../hooks'; +import { useTransformCapabilities, useStartTransforms } from '../../../../hooks'; import { isStartActionDisabled, startActionNameText, StartActionName } from './start_action_name'; export type StartAction = ReturnType; export const useStartAction = (forceDisable: boolean, transformNodes: number) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const startTransforms = useStartTransforms(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap deleted file mode 100644 index fd97412fa1875..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/__snapshots__/stop_action_name.test.tsx.snap +++ /dev/null @@ -1,12 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Actions Minimal initialization 1`] = ` - - Stop - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx index 9496dbd82c70d..e32bf043a2221 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.test.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformListRow } from '../../../../common'; import { StopActionName, StopActionNameProps } from './stop_action_name'; @@ -16,6 +17,8 @@ import transformListRow from '../../../../common/__mocks__/transform_list_row.js jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); +const queryClient = new QueryClient(); + describe('Transform: Transform List Actions ', () => { test('Minimal initialization', () => { // @ts-expect-error mock data is too loosely typed @@ -25,8 +28,11 @@ describe('Transform: Transform List Actions ', () => { items: [item], }; - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); + const { container } = render( + + + + ); + expect(container.textContent).toBe('Stop'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx index 1c729555f7df3..e5bc1425cdd99 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/stop_action_name.tsx @@ -5,17 +5,15 @@ * 2.0. */ -import React, { FC, useContext } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; import { TransformListRow } from '../../../../common'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; export const stopActionNameText = i18n.translate( 'xpack.transform.transformList.stopActionNameText', @@ -43,7 +41,7 @@ export interface StopActionNameProps { } export const StopActionName: FC = ({ items, forceDisable }) => { const isBulkAction = items.length > 1; - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useTransformCapabilities(); // Disable stop action if one of the transforms is stopped already const stoppedTransform = items.some( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx index ac53ee83f6f65..e410704341177 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/action_stop/use_stop_action.tsx @@ -5,32 +5,28 @@ * 2.0. */ -import React, { useCallback, useContext, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { TRANSFORM_STATE } from '../../../../../../common/constants'; -import { AuthorizationContext } from '../../../../lib/authorization'; import { TransformListAction, TransformListRow } from '../../../../common'; -import { useStopTransforms } from '../../../../hooks'; +import { useTransformCapabilities, useStopTransforms } from '../../../../hooks'; import { isStopActionDisabled, stopActionNameText, StopActionName } from './stop_action_name'; import { isManagedTransform } from '../../../../common/managed_transforms_utils'; export type StopAction = ReturnType; export const useStopAction = (forceDisable: boolean) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; - + const { canStartStopTransform } = useTransformCapabilities(); const stopTransforms = useStopTransforms(); const [isModalVisible, setModalVisible] = useState(false); const [items, setItems] = useState([]); const closeModal = () => setModalVisible(false); - const openModal = (newItems: TransformListRow[]) => { if (Array.isArray(newItems)) { setItems(newItems); setModalVisible(true); } }; - const stopAndCloseModal = useCallback( (transformSelection: TransformListRow[]) => { setModalVisible(false); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap deleted file mode 100644 index a529ef04f9230..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/__snapshots__/create_transform_button.test.tsx.snap +++ /dev/null @@ -1,26 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Minimal initialization 1`] = ` - - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx index 0a7324fd09ffc..da84ef2faa8e3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.test.tsx @@ -5,17 +5,23 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { CreateTransformButton } from './create_transform_button'; jest.mock('../../../../../shared_imports'); +const queryClient = new QueryClient(); + describe('Transform: Transform List ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); + const { container } = render( + + + + ); + expect(container.textContent).toBe('Create a transform'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx index 14697f9af4080..9c1fa4be8c101 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/create_transform_button/create_transform_button.tsx @@ -5,16 +5,15 @@ * 2.0. */ -import React, { useContext, FC, MouseEventHandler } from 'react'; +import React, { type FC, type MouseEventHandler } from 'react'; import { EuiButton, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { - createCapabilityFailureMessage, - AuthorizationContext, -} from '../../../../lib/authorization'; +import { createCapabilityFailureMessage } from '../../../../../../common/utils/create_capability_failure_message'; + +import { useTransformCapabilities } from '../../../../hooks'; interface CreateTransformButtonProps { onClick: MouseEventHandler; @@ -25,7 +24,7 @@ export const CreateTransformButton: FC = ({ onClick, transformNodes, }) => { - const { capabilities } = useContext(AuthorizationContext); + const capabilities = useTransformCapabilities(); const disabled = !capabilities.canCreateTransform || diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx index 75f333960fa54..cdaabb3a3b200 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_callout.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx index a337d73ca54b3..d9310762ef3e0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_flyout_form_text_input.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiFieldText, EuiFormRow } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx index b5bb7f3fb258f..519bdc94011e1 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_ingest_pipeline.tsx @@ -5,15 +5,13 @@ * 2.0. */ -import React, { useEffect, useState, type FC } from 'react'; +import React, { type FC } from 'react'; import { useEuiTheme, EuiComboBox, EuiFormRow, EuiSkeletonRectangle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { isEsIngestPipelines } from '../../../../../../common/api_schemas/type_guards'; - -import { useApi } from '../../../../hooks/use_api'; +import { useGetEsIngestPipelines } from '../../../../hooks'; import { EditTransformFlyoutFormTextInput } from './edit_transform_flyout_form_text_input'; import { useEditTransformFlyout } from './use_edit_transform_flyout'; @@ -30,35 +28,8 @@ export const EditTransformIngestPipeline: FC = () => { const { errorMessages, value } = useEditTransformFlyout('destinationIngestPipeline'); const { formField } = useEditTransformFlyout('actions'); - const api = useApi(); - - const [ingestPipelineNames, setIngestPipelineNames] = useState([]); - const [isLoading, setIsLoading] = useState(true); - - useEffect(function fetchPipelinesOnMount() { - let unmounted = false; - - async function getIngestPipelineNames() { - try { - const ingestPipelines = await api.getEsIngestPipelines(); - - if (!unmounted && isEsIngestPipelines(ingestPipelines)) { - setIngestPipelineNames(ingestPipelines.map(({ name }) => name)); - } - } finally { - if (!unmounted) { - setIsLoading(false); - } - } - } - - getIngestPipelineNames(); - - return () => { - unmounted = true; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const { data: esIngestPipelinesData, isLoading } = useGetEsIngestPipelines(); + const ingestPipelineNames = esIngestPipelinesData?.map(({ name }) => name) ?? []; return ( <> diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx index 06e30d584de46..b55b6f90a0aa3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/edit_transform_flyout/edit_transform_update_button.tsx @@ -11,12 +11,9 @@ import { EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { isPostTransformsUpdateResponseSchema } from '../../../../../../common/api_schemas/type_guards'; import { getErrorMessage } from '../../../../../../common/utils/errors'; -import { refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../../../../common'; -import { useToastNotifications } from '../../../../app_dependencies'; -import { useApi } from '../../../../hooks/use_api'; +import { useUpdateTransform } from '../../../../hooks'; import { useEditTransformFlyout } from './use_edit_transform_flyout'; @@ -25,33 +22,20 @@ interface EditTransformUpdateButtonProps { } export const EditTransformUpdateButton: FC = ({ closeFlyout }) => { - const api = useApi(); - const toastNotifications = useToastNotifications(); - const requestConfig = useEditTransformFlyout('requestConfig'); const isUpdateButtonDisabled = useEditTransformFlyout('isUpdateButtonDisabled'); const config = useEditTransformFlyout('config'); const { apiError } = useEditTransformFlyout('actions'); + const updateTransfrom = useUpdateTransform(config.id, requestConfig); + async function submitFormHandler() { apiError(undefined); - const transformId = config.id; - - const resp = await api.updateTransform(transformId, requestConfig); - - if (!isPostTransformsUpdateResponseSchema(resp)) { - apiError(getErrorMessage(resp)); - return; - } - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.editTransformSuccessMessage', { - defaultMessage: 'Transform {transformId} updated.', - values: { transformId }, - }) - ); - closeFlyout(); - refreshTransformList$.next(REFRESH_TRANSFORM_LIST_STATE.REFRESH); + updateTransfrom(undefined, { + onError: (error) => apiError(getErrorMessage(error)), + onSuccess: () => closeFlyout(), + }); } return ( diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx index d0ea13ec11df1..efd4fb1d500af 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/refresh_transform_list_button/refresh_transform_list_button.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx index 5647060ee7a72..3f2bd7fb70c0c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/search_selection/search_selection.tsx @@ -8,7 +8,8 @@ import { EuiModalBody, EuiModalHeader, EuiModalHeaderTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { SavedObjectFinder } from '@kbn/saved-objects-finder-plugin/public'; import { useAppDependencies } from '../../../../app_dependencies'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx index 810d60f3b8fd7..cfd0d112ba90b 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stat.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; export interface StatsBarStat { label: string; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx index 21674ae24301c..849c651b37ea0 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/stats_bar/stats_bar.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; + import { Stat, StatsBarStat } from './stat'; interface Stats { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap deleted file mode 100644 index 39964399f66db..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_details_pane.test.tsx.snap +++ /dev/null @@ -1,66 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Job List Expanded Row Minimal initialization 1`] = ` -
- - - -
- - - -
-`; - -exports[`Transform: Job List Expanded Row
Minimal initialization 1`] = ` - - - - the-section-title - - - - -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap deleted file mode 100644 index 19a5055954d84..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/expanded_row_json_pane.test.tsx.snap +++ /dev/null @@ -1,66 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Expanded Row Minimal initialization 1`] = ` -
- - - - - { - "id": "fq_date_histogram_1m_1441", - "source": { - "index": [ - "farequote-2019" - ], - "query": { - "match_all": {} - } - }, - "dest": { - "index": "fq_date_histogram_1m_1441" - }, - "pivot": { - "group_by": { - "@timestamp": { - "date_histogram": { - "field": "@timestamp", - "calendar_interval": "1m" - } - } - }, - "aggregations": { - "responsetime.avg": { - "avg": { - "field": "responsetime" - } - } - } - }, - "version": "8.0.0", - "create_time": 1564388146667 -} - - - -   - - -
-`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap deleted file mode 100644 index 77df5dc76f68a..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/__snapshots__/transform_list.test.tsx.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Transform: Transform List Minimal initialization 1`] = ` -<_EuiPageEmptyPrompt - actions={ - Array [ - - Create your first transform - , - ] - } - color="subdued" - data-test-subj="transformNoTransformsFound" - title={ -

- No transforms found -

- } -/> -`; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx index a4c8a497d2202..ad375d47ce4cc 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_details_pane.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import { ExpandedRowDetailsPane, Section, SectionConfig } from './expanded_row_details_pane'; @@ -23,16 +23,20 @@ const section: SectionConfig = { describe('Transform: Job List Expanded Row ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const { container } = render(); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-section-title'); + expect(container.textContent).toContain('the-item-title'); + expect(container.textContent).toContain('the-item-description'); }); }); describe('Transform: Job List Expanded Row
', () => { test('Minimal initialization', () => { - const wrapper = shallow(
); + const { container } = render(
); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('the-section-title'); + expect(container.textContent).toContain('the-item-title'); + expect(container.textContent).toContain('the-item-description'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx index 7b1a5de79fae5..ff69aab3aa3eb 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.test.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; import transformListRow from '../../../../common/__mocks__/transform_list_row.json'; @@ -14,8 +14,7 @@ import { ExpandedRowJsonPane } from './expanded_row_json_pane'; describe('Transform: Transform List Expanded Row ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); + const { container } = render(); + expect(container.textContent).toContain(JSON.stringify(transformListRow.config, null, 2)); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx index c68a57ea12109..48e17d9157226 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_json_pane.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; import { EuiCodeBlock, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx index 4cf387ad2973b..2ec73e4485dd1 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/expanded_row_messages_pane.tsx @@ -15,17 +15,15 @@ import { EuiToolTip, EuiButtonIcon, } from '@elastic/eui'; -import { euiLightVars as theme } from '@kbn/ui-theme'; +import { euiLightVars as theme } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; import { DEFAULT_MAX_AUDIT_MESSAGE_SIZE, TIME_FORMAT } from '../../../../../../common/constants'; -import { isGetTransformsAuditMessagesResponseSchema } from '../../../../../../common/api_schemas/type_guards'; import { TransformMessage } from '../../../../../../common/types/messages'; -import { useApi } from '../../../../hooks/use_api'; import { JobIcon } from '../../../../components/job_icon'; -import { useRefreshTransformList } from '../../../../common'; +import { useGetTransformAuditMessages, useRefreshTransformList } from '../../../../hooks'; interface ExpandedRowMessagesPaneProps { transformId: string; @@ -37,12 +35,6 @@ interface Sorting { } export const ExpandedRowMessagesPane: FC = ({ transformId }) => { - const [messages, setMessages] = useState([]); - const [msgCount, setMsgCount] = useState(0); - - const [isLoading, setIsLoading] = useState(false); - const [errorMessage, setErrorMessage] = useState(''); - const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); const [sorting, setSorting] = useState<{ sort: Sorting }>({ @@ -52,58 +44,24 @@ export const ExpandedRowMessagesPane: FC = ({ tran }, }); - const api = useApi(); - - const getMessagesFactory = ( - sortField: keyof TransformMessage = 'timestamp', - sortDirection: 'asc' | 'desc' = 'desc' - ) => { - let concurrentLoads = 0; - - return async function getMessages() { - concurrentLoads++; - - if (concurrentLoads > 1) { - return; - } - - setIsLoading(true); - const messagesResp = await api.getTransformAuditMessages( - transformId, - sortField, - sortDirection - ); - - if (!isGetTransformsAuditMessagesResponseSchema(messagesResp)) { - setIsLoading(false); - setErrorMessage( - i18n.translate( - 'xpack.transform.transformList.transformDetails.messagesPane.errorMessage', - { - defaultMessage: 'Messages could not be loaded', - } - ) - ); - return; - } - - setIsLoading(false); - setMessages(messagesResp.messages); - setMsgCount(messagesResp.total); - - concurrentLoads--; - - if (concurrentLoads > 0) { - concurrentLoads = 0; - getMessages(); - } - }; - }; - const { refresh: refreshMessage } = useRefreshTransformList({ onRefresh: getMessagesFactory() }); + const { + isLoading, + error, + data = { messages: [], total: 0 }, + } = useGetTransformAuditMessages(transformId, sorting.sort.field, sorting.sort.direction); + const { messages, total } = data; + const errorMessage = + error !== null + ? i18n.translate('xpack.transform.transformList.transformDetails.messagesPane.errorMessage', { + defaultMessage: 'Messages could not be loaded', + }) + : ''; + + const refreshTransformList = useRefreshTransformList(); const columns = [ { - name: refreshMessage ? ( + name: refreshTransformList ? ( = ({ tran // TODO: Replace this with ML's blurButtonOnClick when it's moved to a shared package onClick={(e: MouseEvent) => { (e.currentTarget as HTMLButtonElement).blur(); - refreshMessage(); + refreshTransformList(); }} iconType="refresh" aria-label={i18n.translate('xpack.transform.transformList.refreshAriaLabel', { @@ -162,7 +120,7 @@ export const ExpandedRowMessagesPane: FC = ({ tran const getPageOfMessages = ({ index, size }: { index: number; size: number }) => { let list = messages; - if (msgCount <= DEFAULT_MAX_AUDIT_MESSAGE_SIZE) { + if (total <= DEFAULT_MAX_AUDIT_MESSAGE_SIZE) { const sortField = sorting.sort.field ?? 'timestamp'; list = messages.sort((a: TransformMessage, b: TransformMessage) => { const prev = a[sortField] as any; @@ -192,12 +150,6 @@ export const ExpandedRowMessagesPane: FC = ({ tran setPageSize(size); if (sort) { setSorting({ sort }); - - // Since we only show 500 messages, if user wants oldest messages first - // we need to make sure we fetch them from elasticsearch - if (msgCount > DEFAULT_MAX_AUDIT_MESSAGE_SIZE) { - getMessagesFactory(sort.field, sort.direction)(); - } } }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx index 430fa9478f60a..fc4bf0e24d14d 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.test.tsx @@ -5,25 +5,48 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render, waitFor } from '@testing-library/react'; +import { QueryClient, QueryClientProvider, type UseQueryResult } from '@tanstack/react-query'; +import * as ReactQuery from '@tanstack/react-query'; + +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; import { TransformList } from './transform_list'; +const useQueryMock = jest.spyOn(ReactQuery, 'useQuery').mockImplementation((queryKey) => { + switch (queryKey[0]) { + case 'transform.data_view_exists': + return { error: null, data: true } as UseQueryResult; + } + + return { error: null, data: undefined } as UseQueryResult; +}); + +const queryClient = new QueryClient(); + jest.mock('../../../../../shared_imports'); jest.mock('../../../../app_dependencies'); describe('Transform: Transform List ', () => { - test('Minimal initialization', () => { - const wrapper = shallow( - + test('Minimal initialization', async () => { + const { container } = render( + + + + + ); - expect(wrapper).toMatchSnapshot(); + await waitFor(() => { + expect(useQueryMock).toHaveBeenCalledTimes(4); + expect(container.textContent).toContain('Create your first transform'); + }); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index dc831e996b309..2e0106afc0e92 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import React, { FC, MouseEventHandler, useContext, useState } from 'react'; +import React, { type FC, type MouseEventHandler, useState } from 'react'; + import { i18n } from '@kbn/i18n'; import { EuiButton, @@ -26,12 +27,10 @@ import { useReauthorizeAction, } from '../action_reauthorize'; import type { TransformId } from '../../../../../../common/types/transform'; -import { - TRANSFORM_LIST_COLUMN, - TransformListRow, - useRefreshTransformList, -} from '../../../../common'; -import { AuthorizationContext } from '../../../../lib/authorization'; + +import { type TransformListRow, TRANSFORM_LIST_COLUMN } from '../../../../common'; +import { useRefreshTransformList, useTransformCapabilities } from '../../../../hooks'; + import { CreateTransformButton } from '../create_transform_button'; import { RefreshTransformListButton } from '../refresh_transform_list_button'; import { @@ -83,6 +82,7 @@ function getItemIdToExpandedRowMap( } interface TransformListProps { + isLoading: boolean; onCreateTransform: MouseEventHandler; transformNodes: number; transforms: TransformListRow[]; @@ -90,13 +90,13 @@ interface TransformListProps { } export const TransformList: FC = ({ + isLoading, onCreateTransform, transformNodes, transforms, transformsLoading, }) => { - const [isLoading, setIsLoading] = useState(false); - const { refresh } = useRefreshTransformList({ isLoading: setIsLoading }); + const refreshTransformList = useRefreshTransformList(); const { setEditAlertRule } = useAlertRuleFlyout(); const [query, setQuery] = useState>[0]>(); @@ -111,7 +111,7 @@ export const TransformList: FC = ({ const bulkStopAction = useStopAction(false); const bulkScheduleNowAction = useScheduleNowAction(false, transformNodes); - const { capabilities } = useContext(AuthorizationContext); + const capabilities = useTransformCapabilities(); const disabled = !capabilities.canCreateTransform || !capabilities.canPreviewTransform || @@ -134,10 +134,6 @@ export const TransformList: FC = ({ const filteredTransforms = clauses.length > 0 ? filterTransforms(transforms, clauses) : transforms; - if (transforms.length === 0 && transformNodes === 0) { - return null; - } - if (transforms.length === 0) { return ( = ({ const toolsRight = ( - + diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx index 8ad53c64c2f1e..a041466eb5434 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transforms_stats_bar.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import React, { FC } from 'react'; +import React, { type FC } from 'react'; -import { EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; +import { EuiButton, EuiCallOut, EuiLink, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -16,7 +16,7 @@ import { TRANSFORM_MODE, TRANSFORM_STATE } from '../../../../../../common/consta import { TransformListRow } from '../../../../common'; -import { useDocumentationLinks } from '../../../../hooks/use_documentation_links'; +import { useDocumentationLinks, useRefreshTransformList } from '../../../../hooks'; import { StatsBar, TransformStatsBarStats } from '../stats_bar'; @@ -109,6 +109,7 @@ export const TransformStatsBar: FC = ({ transformNodes, transformsList, }) => { + const refreshTransformList = useRefreshTransformList(); const { esNodeRoles } = useDocumentationLinks(); const transformStats: TransformStatsBarStats = createTranformStats( @@ -118,10 +119,8 @@ export const TransformStatsBar: FC = ({ return ( <> - {transformNodes === 0 && ( <> - = ({ }} />

+ refreshTransformList()} size="s"> + +
+ )} + ); }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.test.tsx index d620a60e7a861..34b69e45f087a 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_actions.test.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import React, { type FC } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { renderHook } from '@testing-library/react-hooks'; jest.mock('../../../../../shared_imports'); @@ -14,8 +16,13 @@ import { useActions } from './use_actions'; describe('Transform: Transform List Actions', () => { test('useActions()', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useActions({ forceDisable: false, transformNodes: 1 }) + const queryClient = new QueryClient(); + const wrapper: FC = ({ children }) => ( + {children} + ); + const { result, waitForNextUpdate } = renderHook( + () => useActions({ forceDisable: false, transformNodes: 1 }), + { wrapper } ); await waitForNextUpdate(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx index 521bd745e8692..87f550e433bc2 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.test.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import React, { type FC } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { renderHook } from '@testing-library/react-hooks'; import { useColumns } from './use_columns'; @@ -14,7 +16,13 @@ jest.mock('../../../../app_dependencies'); describe('Transform: Job List Columns', () => { test('useColumns()', async () => { - const { result, waitForNextUpdate } = renderHook(() => useColumns([], () => {}, 1, [])); + const queryClient = new QueryClient(); + const wrapper: FC = ({ children }) => ( + {children} + ); + const { result, waitForNextUpdate } = renderHook(() => useColumns([], () => {}, 1, []), { + wrapper, + }); await waitForNextUpdate(); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx index db77b3e306da2..2ae8edf30a1de 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_columns.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useContext } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { @@ -24,7 +24,7 @@ import { EuiIcon, } from '@elastic/eui'; -import { AuthorizationContext } from '../../../../lib/authorization'; +import { useTransformCapabilities } from '../../../../hooks'; import { needsReauthorization } from '../../../../common/reauthorization_utils'; import { isLatestTransform, @@ -52,7 +52,7 @@ export const useColumns = ( transformNodes: number, transformSelection: TransformListRow[] ) => { - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const { canStartStopTransform } = useTransformCapabilities(); const { actions, modals } = useActions({ forceDisable: transformSelection.length > 0, diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.ts deleted file mode 100644 index c1f4c3d4f7d5c..0000000000000 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_refresh_interval.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 React, { useEffect } from 'react'; - -import { DEFAULT_REFRESH_INTERVAL_MS } from '../../../../../../common/constants'; - -import { useRefreshTransformList } from '../../../../common'; - -export const useRefreshInterval = ( - setBlockRefresh: React.Dispatch> -) => { - const { refresh } = useRefreshTransformList(); - useEffect(() => { - const interval = setInterval(refresh, DEFAULT_REFRESH_INTERVAL_MS); - - // useEffect cleanup - return () => { - clearInterval(interval); - }; - // custom comparison - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // [] as comparator makes sure this only runs once -}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx index 3e4cee609c75b..3782bc9e9dfb3 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.test.tsx @@ -5,17 +5,25 @@ * 2.0. */ -import { shallow } from 'enzyme'; import React from 'react'; +import { render } from '@testing-library/react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { TransformManagementSection } from './transform_management_section'; jest.mock('../../../shared_imports'); +jest.mock('../../services/navigation'); + +const queryClient = new QueryClient(); describe('Transform: ', () => { test('Minimal initialization', () => { - const wrapper = shallow(); + const { container } = render( + + + + ); - expect(wrapper).toMatchSnapshot(); + expect(container.textContent).toContain('Missing permission'); }); }); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx index 093930aeb1b7f..8cfb7ebb5240c 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/transform_management_section.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { FC, useContext, useEffect, useMemo, useState } from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; +import React, { type FC, useEffect, useMemo, useState } from 'react'; + import { EuiButton, EuiButtonEmpty, @@ -16,19 +16,26 @@ import { EuiSkeletonText, EuiSpacer, } from '@elastic/eui'; + import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; + import { needsReauthorization } from '../../common/reauthorization_utils'; +import { TRANSFORM_STATE } from '../../../../common/constants'; + import { - APP_GET_TRANSFORM_CLUSTER_PRIVILEGES, - TRANSFORM_STATE, -} from '../../../../common/constants'; -import { TransformListRow, useRefreshTransformList } from '../../common'; -import { useDocumentationLinks } from '../../hooks/use_documentation_links'; -import { useDeleteTransforms, useGetTransforms } from '../../hooks'; + useDocumentationLinks, + useDeleteTransforms, + useTransformCapabilities, + useGetTransforms, + useGetTransformNodes, +} from '../../hooks'; import { RedirectToCreateTransform } from '../../common/navigation'; -import { AuthorizationContext, PrivilegesWrapper } from '../../lib/authorization'; -import { BREADCRUMB_SECTION, breadcrumbService, docTitleService } from '../../services/navigation'; -import { useRefreshInterval } from './components/transform_list/use_refresh_interval'; +import { CapabilitiesWrapper } from '../../components/capabilities_wrapper'; +import { ToastNotificationText } from '../../components/toast_notification_text'; +import { breadcrumbService, docTitleService, BREADCRUMB_SECTION } from '../../services/navigation'; + import { SearchSelection } from './components/search_selection'; import { TransformList } from './components/transform_list'; import { TransformStatsBar } from './components/transform_list/transforms_stats_bar'; @@ -38,39 +45,52 @@ import { TransformAlertFlyoutWrapper, } from '../../../alerting/transform_alerting_flyout'; +const ErrorMessageCallout: FC<{ + text: JSX.Element; + errorMessage: IHttpFetchError | null; +}> = ({ text, errorMessage }) => { + return ( + <> + + + {text}{' '} + {errorMessage !== null && ( + + )} + + } + color="danger" + iconType="error" + /> + + ); +}; + export const TransformManagement: FC = () => { const { esTransform } = useDocumentationLinks(); - const [transformsLoading, setTransformsLoading] = useState(false); - const [isInitialized, setIsInitialized] = useState(false); - const [blockRefresh, setBlockRefresh] = useState(false); - const [transforms, setTransforms] = useState([]); - const [transformNodes, setTransformNodes] = useState(0); - const [errorMessage, setErrorMessage] = useState(undefined); - const [transformIdsWithoutConfig, setTransformIdsWithoutConfig] = useState< - string[] | undefined - >(); - const deleteTransforms = useDeleteTransforms(); - const getTransforms = useGetTransforms( - setTransforms, - setTransformNodes, - setErrorMessage, - setTransformIdsWithoutConfig, - setIsInitialized, - blockRefresh - ); + const { + isInitialLoading: transformNodesInitialLoading, + error: transformNodesErrorMessage, + data: transformNodesData = 0, + } = useGetTransformNodes(); + const transformNodes = transformNodesErrorMessage === null ? transformNodesData : 0; - // Subscribe to the refresh observable to trigger reloading the transform list. - useRefreshTransformList({ - isLoading: setTransformsLoading, - onRefresh: () => getTransforms(true), - }); - // Call useRefreshInterval() after the subscription above is set up. - useRefreshInterval(setBlockRefresh); + const { + isInitialLoading: transformsInitialLoading, + isLoading: transformsLoading, + error: transformsErrorMessage, + data: { transforms, transformIdsWithoutConfig }, + } = useGetTransforms({ enabled: !transformNodesInitialLoading && transformNodes > 0 }); - const { canStartStopTransform } = useContext(AuthorizationContext).capabilities; + const isInitialLoading = transformNodesInitialLoading || transformsInitialLoading; + + const { canStartStopTransform } = useTransformCapabilities(); const unauthorizedTransformsWarning = useMemo(() => { const unauthorizedCnt = transforms.filter((t) => needsReauthorization(t)).length; @@ -162,93 +182,101 @@ export const TransformManagement: FC = () => { paddingSize={'none'} /> - - - {typeof errorMessage !== 'undefined' && ( - - - - } - body={ -

-

{JSON.stringify(errorMessage)}
-

- } - /> - )} - - {!isInitialized && } - {isInitialized && ( + {isInitialLoading && ( + <> + + + + )} + {!isInitialLoading && ( <> {unauthorizedTransformsWarning} + {transformNodesErrorMessage !== null && ( + + } + errorMessage={transformNodesErrorMessage} + /> + )} + {transformsErrorMessage !== null && ( + + } + errorMessage={transformsErrorMessage} + /> + )} + + - {typeof errorMessage === 'undefined' && ( - - {transformIdsWithoutConfig ? ( - <> - -

- -

- { - await deleteTransforms( - // If transform task doesn't have any corresponding config - // we won't know what the destination index or data view would be - // and should be force deleted - { - transformsInfo: transformIdsWithoutConfig.map((id) => ({ - id, - state: TRANSFORM_STATE.FAILED, - })), - deleteDestIndex: false, - deleteDestDataView: false, - forceDelete: true, - } - ); + + {transformIdsWithoutConfig ? ( + <> + +

+ - - - - - - ) : null} + /> +

+ + deleteTransforms( + // If transform task doesn't have any corresponding config + // we won't know what the destination index or data view would be + // and should be force deleted + { + transformsInfo: transformIdsWithoutConfig.map((id) => ({ + id, + state: TRANSFORM_STATE.FAILED, + })), + deleteDestIndex: false, + deleteDestDataView: false, + forceDelete: true, + } + ) + } + > + + +
+ + + ) : null} + {(transformNodes > 0 || transforms.length > 0) && ( - -
- )} + )} + +
)}
@@ -274,8 +302,8 @@ export const TransformManagementSection: FC = () => { }, []); return ( - + - + ); }; diff --git a/x-pack/plugins/transform/public/app/services/es_index_service.ts b/x-pack/plugins/transform/public/app/services/es_index_service.ts deleted file mode 100644 index d8d058b731a74..0000000000000 --- a/x-pack/plugins/transform/public/app/services/es_index_service.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { HttpSetup } from '@kbn/core/public'; -import type { DataViewsContract } from '@kbn/data-views-plugin/public'; -import { addInternalBasePath } from '../../../common/constants'; - -export class IndexService { - async canDeleteIndex(http: HttpSetup) { - const privilege = await http.get<{ hasAllPrivileges: boolean }>( - addInternalBasePath(`privileges`), - { version: '1' } - ); - if (!privilege) { - return false; - } - return privilege.hasAllPrivileges; - } - - async dataViewExists(dataViewsContract: DataViewsContract, indexName: string) { - return (await dataViewsContract.find(indexName)).some(({ title }) => title === indexName); - } -} - -export const indexService = new IndexService(); diff --git a/x-pack/plugins/transform/common/privilege/has_privilege_factory.test.ts b/x-pack/plugins/transform/server/capabilities.test.ts similarity index 94% rename from x-pack/plugins/transform/common/privilege/has_privilege_factory.test.ts rename to x-pack/plugins/transform/server/capabilities.test.ts index e9fa6cd7bc6d7..5cf194d6e84e3 100644 --- a/x-pack/plugins/transform/common/privilege/has_privilege_factory.test.ts +++ b/x-pack/plugins/transform/server/capabilities.test.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { extractMissingPrivileges, getPrivilegesAndCapabilities } from './has_privilege_factory'; +import { type TransformCapabilities } from '../common/types/capabilities'; + +import { extractMissingPrivileges, getPrivilegesAndCapabilities } from './capabilities'; describe('has_privilege_factory', () => { const fullClusterPrivileges = { @@ -65,9 +67,10 @@ describe('has_privilege_factory', () => { describe('getPrivilegesAndCapabilities', () => { it('returns full capabilities if provided both monitor and admin cluster privileges', () => { - const fullCapabilities = { + const fullCapabilities: TransformCapabilities = { canCreateTransform: true, canCreateTransformAlerts: true, + canDeleteIndex: true, canDeleteTransform: true, canGetTransform: true, canPreviewTransform: true, @@ -91,9 +94,10 @@ describe('has_privilege_factory', () => { }); }); it('returns view only capabilities if provided only monitor cluster privileges', () => { - const viewOnlyCapabilities = { + const viewOnlyCapabilities: TransformCapabilities = { canCreateTransform: false, canCreateTransformAlerts: false, + canDeleteIndex: false, canDeleteTransform: false, canGetTransform: true, canPreviewTransform: false, @@ -119,9 +123,10 @@ describe('has_privilege_factory', () => { }); }); it('returns no capabilities and all the missing privileges if no cluster privileges', () => { - const noCapabilities = { + const noCapabilities: TransformCapabilities = { canCreateTransform: false, canCreateTransformAlerts: false, + canDeleteIndex: false, canDeleteTransform: false, canGetTransform: false, canPreviewTransform: false, diff --git a/x-pack/plugins/transform/server/capabilities.ts b/x-pack/plugins/transform/server/capabilities.ts index 73889a0808359..5fd542d428a70 100644 --- a/x-pack/plugins/transform/server/capabilities.ts +++ b/x-pack/plugins/transform/server/capabilities.ts @@ -7,22 +7,123 @@ import type { CoreSetup } from '@kbn/core-lifecycle-server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; +import { isPopulatedObject } from '@kbn/ml-is-populated-object'; + import { - getPrivilegesAndCapabilities, - INITIAL_CAPABILITIES, -} from '../common/privilege/has_privilege_factory'; -import { APP_CLUSTER_PRIVILEGES } from '../common/constants'; + getInitialTransformCapabilities, + type Privilege, + type Privileges, + type PrivilegesAndCapabilities, +} from '../common/types/capabilities'; +import { APP_CLUSTER_PRIVILEGES, APP_INDEX_PRIVILEGES } from '../common/constants'; + import type { PluginStartDependencies } from './types'; export const TRANSFORM_PLUGIN_ID = 'transform' as const; +function isPrivileges(arg: unknown): arg is Privileges { + return ( + isPopulatedObject(arg, ['hasAllPrivileges', 'missingPrivileges']) && + typeof arg.hasAllPrivileges === 'boolean' && + typeof arg.missingPrivileges === 'object' && + arg.missingPrivileges !== null + ); +} + +export const hasPrivilegeFactory = + (privileges: Privileges | undefined | null) => (privilege: Privilege) => { + const [section, requiredPrivilege] = privilege; + if (isPrivileges(privileges) && !privileges.missingPrivileges[section]) { + // if the section does not exist in our missingPrivileges, everything is OK + return true; + } + if (isPrivileges(privileges) && privileges.missingPrivileges[section]!.length === 0) { + return true; + } + if (requiredPrivilege === '*') { + // If length > 0 and we require them all... KO + return false; + } + // If we require _some_ privilege, we make sure that the one + // we require is *not* in the missingPrivilege array + return ( + isPrivileges(privileges) && + !privileges.missingPrivileges[section]!.includes(requiredPrivilege) + ); + }; + +export const extractMissingPrivileges = ( + privilegesObject: { [key: string]: boolean } = {} +): string[] => + Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { + if (!privilegesObject[privilegeName]) { + privileges.push(privilegeName); + } + return privileges; + }, []); + +export const getPrivilegesAndCapabilities = ( + clusterPrivileges: Record, + hasOneIndexWithAllPrivileges: boolean, + hasAllPrivileges: boolean +): PrivilegesAndCapabilities => { + const privilegesResult: Privileges = { + hasAllPrivileges: true, + missingPrivileges: { + cluster: [], + index: [], + }, + }; + + // Find missing cluster privileges and set overall app privileges + privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(clusterPrivileges); + privilegesResult.hasAllPrivileges = hasAllPrivileges; + + if (!hasOneIndexWithAllPrivileges) { + privilegesResult.missingPrivileges.index = [...APP_INDEX_PRIVILEGES]; + } + + const hasPrivilege = hasPrivilegeFactory(privilegesResult); + + const capabilities = getInitialTransformCapabilities(); + + capabilities.canGetTransform = + hasPrivilege(['cluster', 'cluster:monitor/transform/get']) && + hasPrivilege(['cluster', 'cluster:monitor/transform/stats/get']); + + capabilities.canCreateTransform = hasPrivilege(['cluster', 'cluster:admin/transform/put']); + + capabilities.canDeleteTransform = hasPrivilege(['cluster', 'cluster:admin/transform/delete']); + + capabilities.canResetTransform = hasPrivilege(['cluster', 'cluster:admin/transform/reset']); + + capabilities.canPreviewTransform = hasPrivilege(['cluster', 'cluster:admin/transform/preview']); + + capabilities.canStartStopTransform = + hasPrivilege(['cluster', 'cluster:admin/transform/start']) && + hasPrivilege(['cluster', 'cluster:admin/transform/start_task']) && + hasPrivilege(['cluster', 'cluster:admin/transform/stop']); + + capabilities.canCreateTransformAlerts = capabilities.canCreateTransform; + + capabilities.canUseTransformAlerts = capabilities.canGetTransform; + + capabilities.canScheduleNowTransform = capabilities.canStartStopTransform; + + capabilities.canReauthorizeTransform = capabilities.canStartStopTransform; + + capabilities.canDeleteIndex = hasAllPrivileges; + + return { privileges: privilegesResult, capabilities }; +}; + export const setupCapabilities = ( core: Pick, 'capabilities' | 'getStartServices'>, securitySetup?: SecurityPluginSetup ) => { core.capabilities.registerProvider(() => { return { - transform: INITIAL_CAPABILITIES, + transform: getInitialTransformCapabilities(), }; }); @@ -38,10 +139,7 @@ export const setupCapabilities = ( // If security is not enabled or not available, transform should have full permission if (!isSecurityPluginEnabled || !securityStart) { return { - transform: Object.keys(INITIAL_CAPABILITIES).reduce>((acc, p) => { - acc[p] = true; - return acc; - }, {}), + transform: getInitialTransformCapabilities(true), }; } @@ -71,6 +169,8 @@ export const setupCapabilities = ( hasAllRequested ).capabilities; - return { transform: transformCapabilities }; + return { + transform: transformCapabilities as Record>, + }; }); }; diff --git a/x-pack/plugins/transform/server/routes/api/privileges.ts b/x-pack/plugins/transform/server/routes/api/privileges.ts deleted file mode 100644 index 0b93c8e503fc6..0000000000000 --- a/x-pack/plugins/transform/server/routes/api/privileges.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { IKibanaResponse, IScopedClusterClient } from '@kbn/core/server'; -import type { SecurityHasPrivilegesResponse } from '@elastic/elasticsearch/lib/api/types'; -import { - getPrivilegesAndCapabilities, - type PrivilegesAndCapabilities, -} from '../../../common/privilege/has_privilege_factory'; -import { - addInternalBasePath, - APP_CLUSTER_PRIVILEGES, - APP_INDEX_PRIVILEGES, -} from '../../../common/constants'; - -import type { RouteDependencies } from '../../types'; - -export function registerPrivilegesRoute({ router, license }: RouteDependencies) { - router.versioned - .get({ - path: addInternalBasePath('privileges'), - access: 'internal', - }) - .addVersion( - { - version: '1', - validate: false, - }, - license.guardApiRoute( - async (ctx, req, res): Promise> => { - if (license.getStatus().isSecurityEnabled === false) { - // If security isn't enabled, let the user use app. - return res.ok({ - body: getPrivilegesAndCapabilities({}, true, true), - }); - } - - const esClient: IScopedClusterClient = (await ctx.core).elasticsearch.client; - - const esClusterPrivilegesReq: Promise = - esClient.asCurrentUser.security.hasPrivileges({ - body: { - cluster: APP_CLUSTER_PRIVILEGES, - }, - }); - const [esClusterPrivileges, userPrivileges] = await Promise.all([ - // Get cluster privileges - esClusterPrivilegesReq, - // // Get all index privileges the user has - esClient.asCurrentUser.security.getUserPrivileges(), - ]); - - const { has_all_requested: hasAllPrivileges, cluster } = esClusterPrivileges; - const { indices } = userPrivileges; - - // Check if they have all the required index privileges for at least one index - const hasOneIndexWithAllPrivileges = - indices.find(({ privileges }: { privileges: string[] }) => { - if (privileges.includes('all')) { - return true; - } - - const indexHasAllPrivileges = APP_INDEX_PRIVILEGES.every((privilege) => - privileges.includes(privilege) - ); - - return indexHasAllPrivileges; - }) !== undefined; - - return res.ok({ - body: getPrivilegesAndCapabilities( - cluster, - hasOneIndexWithAllPrivileges, - hasAllPrivileges - ), - }); - } - ) - ); -} diff --git a/x-pack/plugins/transform/server/routes/index.ts b/x-pack/plugins/transform/server/routes/index.ts index 0a8539c7683de..aec4417f2a421 100644 --- a/x-pack/plugins/transform/server/routes/index.ts +++ b/x-pack/plugins/transform/server/routes/index.ts @@ -8,11 +8,9 @@ import { RouteDependencies } from '../types'; import { registerFieldHistogramsRoutes } from './api/field_histograms'; -import { registerPrivilegesRoute } from './api/privileges'; import { registerTransformsRoutes } from './api/transforms'; export function registerRoutes(dependencies: RouteDependencies) { registerFieldHistogramsRoutes(dependencies); - registerPrivilegesRoute(dependencies); registerTransformsRoutes(dependencies); } diff --git a/x-pack/plugins/transform/tsconfig.json b/x-pack/plugins/transform/tsconfig.json index 9c9ef2299c60d..2d0cdf45c554d 100644 --- a/x-pack/plugins/transform/tsconfig.json +++ b/x-pack/plugins/transform/tsconfig.json @@ -67,7 +67,8 @@ "@kbn/saved-search-plugin", "@kbn/unified-field-list", "@kbn/ebt-tools", - "@kbn/content-management-plugin" + "@kbn/content-management-plugin", + "@kbn/react-kibana-mount" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 34706e7cb9ba7..c272f855f41db 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -2155,7 +2155,7 @@ "discover.advancedSettings.disableDocumentExplorerDescription": "Désactivez cette option pour utiliser le nouveau {documentExplorerDocs} au lieu de la vue classique. l'explorateur de documents offre un meilleur tri des données, des colonnes redimensionnables et une vue en plein écran.", "discover.advancedSettings.discover.showFieldStatisticsDescription": "Activez le {fieldStatisticsDocs} pour afficher des détails tels que les valeurs minimale et maximale d'un champ numérique ou une carte d'un champ géographique. Cette fonctionnalité est en version bêta et susceptible d'être modifiée.", "discover.advancedSettings.discover.showMultifieldsDescription": "Détermine si les {multiFields} doivent s'afficher dans la fenêtre de document étendue. Dans la plupart des cas, les champs multiples sont les mêmes que les champs d'origine. Cette option est uniquement disponible lorsque le paramètre ''searchFieldsFromSource'' est désactivé.", - "discover.advancedSettings.enableSQLDescription": "{technicalPreviewLabel} Cette fonctionnalité en préversion technique est à un stade hautement expérimental ; ne pas s'y fier pour les recherches enregistrées, ni pour les visualisations ou les tableaux de bord en production. Ce paramètre active SQL comme langage de requête à base de texte dans Discover et Lens. Si vous avez des commentaires sur cette expérience, contactez-nous via {link}", + "discover.advancedSettings.enableESQLDescription": "{technicalPreviewLabel} Cette fonctionnalité en préversion technique est à un stade hautement expérimental ; ne pas s'y fier pour les recherches enregistrées, ni pour les visualisations ou les tableaux de bord en production. Ce paramètre active SQL comme langage de requête à base de texte dans Discover et Lens. Si vous avez des commentaires sur cette expérience, contactez-nous via {link}", "discover.context.contextOfTitle": "Documents relatifs à #{anchorId}", "discover.context.newerDocumentsWarning": "Seuls {docCount} documents plus récents que le document ancré ont été trouvés.", "discover.context.olderDocumentsWarning": "Seuls {docCount} documents plus anciens que le document ancré ont été trouvés.", @@ -2178,11 +2178,6 @@ "discover.dscTour.stepAddFields.description": "Cliquez sur {plusIcon} pour ajouter les champs qui vous intéressent.", "discover.dscTour.stepExpand.description": "Cliquez sur {expandIcon} pour afficher, comparer et filtrer les documents.", "discover.errorCalloutFormattedTitle": "{title} : {errorMessage}", - "discover.grid.copyClipboardButtonTitle": "Copier la valeur de {column}", - "discover.grid.copyColumnValuesToClipboard.toastTitle": "Valeurs de la colonne \"{column}\" copiées dans le presse-papiers", - "discover.grid.filterForAria": "Filtrer sur cette {value}", - "discover.grid.filterOutAria": "Exclure cette {value}", - "discover.gridSampleSize.limitDescription": "Les résultats de recherche sont limités à {sampleSize} documents Ajoutez d'autres termes pour affiner votre recherche.", "discover.howToSeeOtherMatchingDocumentsDescription": "Voici les {sampleSize} premiers documents correspondant à votre recherche. Veuillez affiner cette dernière pour en voir davantage.", "discover.noMatchRoute.bannerText": "L'application Discover ne reconnaît pas cet itinéraire : {route}", "discover.noResults.kqlExamples.kqlDescription": "En savoir plus sur {kqlLink}", @@ -2192,9 +2187,6 @@ "discover.pageTitleWithSavedSearch": "Discover –{savedSearchTitle}", "discover.savedSearchAliasMatchRedirect.objectNoun": "Recherche {savedSearch}", "discover.savedSearchURLConflictCallout.objectNoun": "Recherche {savedSearch}", - "discover.searchGenerationWithDescription": "Tableau généré par la recherche {searchTitle}", - "discover.searchGenerationWithDescriptionGrid": "Tableau généré par la recherche {searchTitle} ({searchDescription})", - "discover.selectedDocumentsNumber": "{nr} documents sélectionnés", "discover.showingDefaultDataViewWarningDescription": "Affichage de la vue de données par défaut : \"{loadedDataViewTitle}\" ({loadedDataViewId})", "discover.showingSavedDataViewWarningDescription": "Affichage de la vue de données enregistrée : \"{ownDataViewTitle}\" ({ownDataViewId})", "discover.singleDocRoute.errorMessage": "Aucune vue de données correspondante pour l'ID {dataViewId}", @@ -2220,8 +2212,8 @@ "discover.advancedSettings.docTableHideTimeColumnText": "Permet de masquer la colonne ''Time'' dans Discover et dans toutes les recherches enregistrées des tableaux de bord.", "discover.advancedSettings.docTableHideTimeColumnTitle": "Masquer la colonne ''Time''", "discover.advancedSettings.documentExplorerLinkText": "Explorateur de documents", - "discover.advancedSettings.enableSQL.discussLinkText": "discuss.elastic.co/c/elastic-stack/kibana", - "discover.advancedSettings.enableSQLTitle": "Activer SQL", + "discover.advancedSettings.enableESQL.discussLinkText": "discuss.elastic.co/c/elastic-stack/kibana", + "discover.advancedSettings.enableESQLTitle": "Activer SQL", "discover.advancedSettings.fieldsPopularLimitText": "Les N champs les plus populaires à afficher", "discover.advancedSettings.fieldsPopularLimitTitle": "Limite de champs populaires", "discover.advancedSettings.maxDocFieldsDisplayedText": "Le nombre maximal de champs renvoyés dans le résumé du document", @@ -2247,7 +2239,6 @@ "discover.backToTopLinkText": "Revenir en haut de la page.", "discover.badge.readOnly.text": "Lecture seule", "discover.badge.readOnly.tooltip": "Impossible d’enregistrer les recherches", - "discover.clearSelection": "Effacer la sélection", "discover.confirmDataViewSave.cancel": "Annuler", "discover.confirmDataViewSave.message": "L'action que vous avez choisie requiert une vue de données enregistrée.", "discover.confirmDataViewSave.saveAndContinue": "Enregistrer et continuer", @@ -2268,8 +2259,6 @@ "discover.context.unableToLoadAnchorDocumentDescription": "Impossible de charger le document ancré", "discover.context.unableToLoadDocumentDescription": "Impossible de charger les documents", "discover.contextViewRoute.errorTitle": "Une erreur s'est produite", - "discover.controlColumnHeader": "Colonne de commande", - "discover.copyToClipboardJSON": "Copier les documents dans le presse-papiers (JSON)", "discover.discoverBreadcrumbTitle": "Discover", "discover.discoverDefaultSearchSessionName": "Discover", "discover.discoverDescription": "Explorez vos données de manière interactive en interrogeant et en filtrant des documents bruts.", @@ -2368,29 +2357,15 @@ "discover.fieldChooser.discoverField.removeFieldTooltip": "Supprimer le champ du tableau", "unifiedDocViewer.fieldChooser.discoverField.value": "Valeur", "discover.goToDiscoverButtonText": "Aller à Discover", - "discover.grid.closePopover": "Fermer la fenêtre contextuelle", - "discover.grid.copyCellValueButton": "Copier la valeur", - "discover.grid.copyColumnNameToClipboard.toastTitle": "Copié dans le presse-papiers", - "discover.grid.copyColumnNameToClipBoardButton": "Copier le nom", - "discover.grid.copyColumnValuesToClipBoardButton": "Copier la colonne", - "discover.grid.copyEscapedValueWithFormulasToClipboardWarningText": "Les valeurs peuvent contenir des formules avec échappement.", - "discover.grid.copyFailedErrorText": "Impossible de copier dans le presse-papiers avec ce navigateur", - "discover.grid.copyValueToClipboard.toastTitle": "Copié dans le presse-papiers", - "discover.grid.documentHeader": "Document", - "discover.grid.editFieldButton": "Modifier le champ de la vue de données", - "discover.grid.filterFor": "Filtrer sur", - "discover.grid.filterOut": "Exclure", "discover.grid.flyout.documentNavigation": "Navigation dans le document", "discover.grid.flyout.toastColumnAdded": "La colonne \"{columnName}\" a été ajoutée.", "discover.grid.flyout.toastColumnRemoved": "La colonne \"{columnName}\" a été supprimée.", - "discover.grid.selectDoc": "Sélectionner le document \"{rowNumber}\"", "discover.grid.tableRow.detailHeading": "Document développé", "discover.grid.tableRow.textBasedDetailHeading": "Ligne développée", "discover.grid.tableRow.viewSingleDocumentLinkTextSimple": "Document unique", "discover.grid.tableRow.viewSurroundingDocumentsHover": "Inspectez des documents qui ont été créés avant et après ce document. Seuls les filtres épinglés restent actifs dans la vue Documents relatifs.", "discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple": "Documents relatifs", "discover.grid.tableRow.viewText": "Afficher :", - "discover.grid.viewDoc": "Afficher/Masquer les détails de la boîte de dialogue", "discover.helpMenu.appName": "Découverte", "discover.inspectorRequestDataTitleDocuments": "Documents", "discover.inspectorRequestDescriptionDocument": "Cette requête interroge Elasticsearch afin de récupérer les documents.", @@ -2400,7 +2375,6 @@ "unifiedDocViewer.json.copyToClipboardLabel": "Copier dans le presse-papiers", "discover.loadingDocuments": "Chargement des documents", "unifiedDocViewer.loadingJSON": "Chargement de JSON", - "discover.loadingResults": "Chargement des résultats", "discover.localMenu.alertsDescription": "Alertes", "discover.localMenu.fallbackReportTitle": "Recherche Discover sans titre", "discover.localMenu.inspectTitle": "Inspecter", @@ -2443,23 +2417,18 @@ "discover.noResults.suggestion.syntaxPopoverExampleHeader": "Exemple", "discover.noResults.suggestion.tryText": "Voici quelques solutions à essayer :", "discover.noResults.suggestion.viewAllMatchesButtonText": "Afficher toutes les correspondances", - "discover.noResultsFound": "Résultat introuvable", "discover.notifications.invalidTimeRangeText": "La plage temporelle spécifiée n'est pas valide (de : \"{from}\" à \"{to}\").", "discover.notifications.invalidTimeRangeTitle": "Plage temporelle non valide", "discover.notifications.notSavedSearchTitle": "La recherche \"{savedSearchTitle}\" n'a pas été enregistrée.", "discover.notifications.savedSearchTitle": "La recherche \"{savedSearchTitle}\" a été enregistrée.", "discover.pageTitleWithoutSavedSearch": "Discover - Recherche non encore enregistrée", "discover.reloadSavedSearchButton": "Réinitialiser la recherche", - "discover.removeColumnLabel": "Supprimer la colonne", "discover.rootBreadcrumb": "Découverte", "discover.sampleData.viewLinkLabel": "Découverte", "discover.savedSearch.savedObjectName": "Recherche enregistrée", "discover.savedSearchEmbeddable.action.viewSavedSearch.displayName": "Ouvrir dans Discover", "discover.searchingTitle": "Recherche", - "discover.selectColumnHeader": "Sélectionner la colonne", "discover.serverLocatorExtension.titleFromLocatorUnknown": "Recherche inconnue", - "discover.showAllDocuments": "Afficher tous les documents", - "discover.showSelectedDocumentsOnly": "Afficher uniquement les documents sélectionnés", "discover.singleDocRoute.errorTitle": "Une erreur s'est produite", "discover.skipToBottomButtonLabel": "Atteindre la fin du tableau", "unifiedDocViewer.sourceViewer.errorMessage": "Impossible de récupérer les données pour le moment. Actualisez l'onglet et réessayez.", @@ -2481,6 +2450,25 @@ "discover.viewAlert.searchSourceErrorTitle": "Erreur lors de la récupération de la source de recherche", "discover.viewModes.document.label": "Documents", "discover.viewModes.fieldStatistics.label": "Statistiques de champ", + "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} – Ce champ représente l'heure à laquelle les événements se sont produits.", + "unifiedDataTable.searchGenerationWithDescription": "Tableau généré par la recherche {searchTitle}", + "unifiedDataTable.searchGenerationWithDescriptionGrid": "Tableau généré par la recherche {searchTitle} ({searchDescription})", + "unifiedDataTable.selectedDocumentsNumber": "{nr} documents sélectionnés", + "unifiedDataTable.clearSelection": "Effacer la sélection", + "unifiedDataTable.controlColumnHeader": "Colonne de commande", + "unifiedDataTable.copyToClipboardJSON": "Copier les documents dans le presse-papiers (JSON)", + "unifiedDataTable.tableHeader.timeFieldIconTooltip": "Ce champ représente l'heure à laquelle les événements se sont produits.", + "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "Copier le nom", + "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "Copier la colonne", + "unifiedDataTable.grid.documentHeader": "Document", + "unifiedDataTable.grid.editFieldButton": "Modifier le champ de la vue de données", + "unifiedDataTable.grid.selectDoc": "Sélectionner le document \"{rowNumber}\"", + "unifiedDataTable.loadingResults": "Chargement des résultats", + "unifiedDataTable.noResultsFound": "Résultat introuvable", + "unifiedDataTable.removeColumnLabel": "Supprimer la colonne", + "unifiedDataTable.selectColumnHeader": "Sélectionner la colonne", + "unifiedDataTable.showAllDocuments": "Afficher tous les documents", + "unifiedDataTable.showSelectedDocumentsOnly": "Afficher uniquement les documents sélectionnés", "domDragDrop.announce.cancelled": "Mouvement annulé. {label} revenu à sa position initiale", "domDragDrop.announce.cancelledItem": "Mouvement annulé. {label} revenu au groupe {groupLabel} à la position {position}", "domDragDrop.announce.dropped.combineCompatible": "{label} combiné dans le groupe {groupLabel} en {dropLabel} dans le groupe {dropGroupLabel} à la position {dropPosition} dans le calque {dropLayerNumber}", @@ -5925,9 +5913,6 @@ "unifiedSearch.query.queryBar.indexPattern.findFilterSet": "Trouver une requête", "unifiedSearch.query.queryBar.indexPattern.manageFieldButton": "Gérer cette vue de données", "unifiedSearch.query.queryBar.indexPattern.temporaryDataviewLabel": "Temporaire", - "unifiedSearch.query.queryBar.indexPattern.textBasedLangSwitchWarning": "Un changement de vue de données supprime la requête SQL en cours. Sauvegardez cette recherche pour ne pas perdre de travail.", - "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesLabel": "Langages de requête à base de texte", - "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalBody": "Un changement de vue de données supprime la requête SQL en cours. Sauvegardez cette recherche pour ne pas perdre de travail.", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalCloseButton": "Basculer sans sauvegarder", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalDismissButton": "Ne plus afficher cet avertissement", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalSaveButton": "Sauvegarder et basculer", @@ -27640,8 +27625,6 @@ "xpack.observability.slo.sloEdit.sliType.customKql.goodQuery.tooltip": "Cette requête KQL doit renvoyer un sous-ensemble d'événements considérés comme \"bons\" ou \"réussis\" aux fins du calcul du SLO. La requête doit filtrer les événements en fonction de certains critères pertinents, tels que les codes de statut, les messages d'erreur ou d'autres champs pertinents.", "xpack.observability.slo.sloEdit.sliType.customKql.goodQueryPlaceholder": "Définir les bons événements", "xpack.observability.slo.sloEdit.sliType.customKql.queryFilter": "Filtre de requête", - "xpack.observability.slo.sloEdit.sliType.customKql.timestampField.label": "Champ d'horodatage", - "xpack.observability.slo.sloEdit.sliType.customKql.timestampField.placeholder": "Sélectionner un champ d'horodatage", "xpack.observability.slo.sloEdit.sliType.customKql.totalQuery": "Total de la requête", "xpack.observability.slo.sloEdit.sliType.customKql.totalQuery.tooltip": "Cette requête KQL doit renvoyer tous les événements pertinents pour le calcul du SLO, y compris les bons et les mauvais événements.", "xpack.observability.slo.sloEdit.sliType.customKql.totalQueryPlaceholder": "Définir le total d'événements", @@ -27655,8 +27638,6 @@ "xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder": "Sélectionner un champ d’indicateur", "xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter": "Filtre de requête", "xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel": "Somme de", - "xpack.observability.slo.sloEdit.sliType.customMetric.timestampField.label": "Champ d'horodatage", - "xpack.observability.slo.sloEdit.sliType.customMetric.timestampField.placeholder": "Sélectionner un champ d'horodatage", "xpack.observability.slo.sloEdit.tags.label": "Balises", "xpack.observability.slo.sloEdit.tags.placeholder": "Ajouter des balises", "xpack.observability.slo.sloEdit.targetSlo.label": "Cible/SLO (%)", @@ -34620,10 +34601,6 @@ "xpack.serverlessSearch.apiKey.roleDescriptorsLinkLabel": "Découvrir comment structurer les descripteurs de rôles", "xpack.serverlessSearch.apiKey.setup.description": "Les détails de la configuration de base pour créer votre clé d’API.", "xpack.serverlessSearch.apiKey.setup.title": "Configuration", - "xpack.serverlessSearch.apiKey.stepOneDescription": "Identifiant unique pour l’authentification et l’autorisation. ", - "xpack.serverlessSearch.apiKey.stepOneTitle": "Générer et stocker vos clés d’API", - "xpack.serverlessSearch.apiKey.stepTwoDescription": "Identifiant unique pour un projet spécifique. ", - "xpack.serverlessSearch.apiKey.stepTwoTitle": "Stocker votre identifiant unique du cloud", "xpack.serverlessSearch.apiKey.title": "Stocker votre clé d’API et votre identifiant du cloud", "xpack.serverlessSearch.apiKey.userFieldHelpText": "Identifiant de l’utilisateur créant la clé d’API.", "xpack.serverlessSearch.apiKey.userFieldLabel": "Utilisateur", @@ -37692,26 +37669,19 @@ "xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage": "La/les {count, plural, one {Transformer} many {Transformations} other {Transformations}} {transformsString} {count, plural, one {est} many {sont} other {sont}} saine(s).", "xpack.transform.alertTypes.transformHealth.notStartedMessage": "La/les {count, plural, one {Transformer} many {Transformer} other {Transformer}} {transformsString} {count, plural, one {est} many {sont} other {ne sont pas démarrées}}.", "xpack.transform.alertTypes.transformHealth.notStartedRecoveryMessage": "La/les {count, plural, one {Transformer} many {Transformer} other {Transformer}} {transformsString} {count, plural, one {est} many {sont} other {sont}} lancée(s).", - "xpack.transform.app.deniedPrivilegeDescription": "Pour utiliser cette section des transformations, vous devez avoir {privilegesCount, plural, one {ce privilège de cluster} many {ces privilèges de cluster} other {ces privilèges de cluster}} : {missingPrivileges}.", "xpack.transform.capability.pleaseContactAdministratorTooltip": "{message} Veuillez contacter votre administrateur.", "xpack.transform.clone.noDataViewErrorPromptText": "Impossible de cloner la transformation {transformId}. Il n'existe aucune vue de données pour {dataViewTitle}.", "xpack.transform.danglingTasksError": "{count} {count, plural, one {transformation n'a pas de} many {transformations n'ont pas de} other {transformations n'ont pas de}} détails de configuration : [{transformIds}] {count, plural, one {Elle ne peut pas être récupérée et doit être supprimée} many {Elles ne peuvent pas être récupérées et doivent être supprimées} other {Elles ne peuvent pas être récupérées et doivent être supprimées}}.", "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage": "Une erreur est survenue lors de la suppression de la vue de données {destinationIndex}", - "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage": "Requête de suppression de la vue de données {destinationIndex} reconnue.", "xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage": "Une erreur s'est produite lors de la suppression de l'index de destination {destinationIndex}", - "xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage": "Requête de suppression de l'index de destination {destinationIndex} reconnue.", "xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage": "Une erreur s'est produite lors de la vérification de l'existence de la vue de données {dataView} : {error}", "xpack.transform.edit.noDataViewErrorPromptText": "Impossible d'obtenir la vue de données pour la transformation {transformId}. Il n'existe aucune vue de données pour {dataViewTitle}.", "xpack.transform.forceDeleteTransformMessage": "Supprimer {count} {count, plural, one {transformation} many {transformations} other {transformations}}", "xpack.transform.managedTransformsWarningCallout": "{count, plural, one {Cette transformation} many {Au moins l'une de ces transformations} other {Au moins l'une de ces transformations}} est préconfigurée par Elastic. Le fait de {action} {count, plural, one {la} many {les} other {les}} avec une heure de fin spécifique peut avoir un impact sur d'autres éléments du produit.", "xpack.transform.multiTransformActionsMenu.transformsCount": "Sélection effectuée de {count} {count, plural, one {transformation} many {transformations} other {transformations}}", "xpack.transform.stepCreateForm.createDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} :", - "xpack.transform.stepCreateForm.createDataViewSuccessMessage": "La vue de données Kibana {dataViewName} a bien été créée.", "xpack.transform.stepCreateForm.createTransformErrorMessage": "Une erreur s'est produite lors de la création de la transformation {transformId} :", - "xpack.transform.stepCreateForm.createTransformSuccessMessage": "La requête pour créer la transformation {transformId} a été reconnue.", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Une erreur est survenue lors de la création de la vue de données Kibana {dataViewName} : La vue de données existe déjà.", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "Une erreur s'est produite lors du démarrage de la transformation {transformId} :", - "xpack.transform.stepCreateForm.startTransformSuccessMessage": "La requête pour démarrer la transformation {transformId} a été reconnue.", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "Requête non valide : {queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "Par exemple, {example}", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "Par exemple, {example}", @@ -37723,41 +37693,30 @@ "xpack.transform.stepDetailsForm.retentionPolicyMaxAgePlaceholderText": "max_age, par exemple {exampleValue}", "xpack.transform.transformForm.sizeNotationPlaceholder": "Exemples : {example1}, {example2}, {example3}, {example4}", "xpack.transform.transformList.alertingRules.tooltipContent": "La transformation a {rulesCount} {rulesCount, plural, one { règle} many { règles} other { règles}} d'alerte associée(s)", - "xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage": "Suppression réussie de {count} {count, plural, one {vue} many {vues} other {vues}} de données de destination.", - "xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage": "Suppression réussie de {count} {count, plural, one {index} many {index système non migrés} other {index}} de destination.", "xpack.transform.transformList.bulkDeleteModalTitle": "Supprimer {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", - "xpack.transform.transformList.bulkDeleteTransformSuccessMessage": "Suppression réussie de {count} {count, plural, one {transformation} many {transformations} other {transformations}}.", "xpack.transform.transformList.bulkReauthorizeModalTitle": "Réautoriser {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", "xpack.transform.transformList.bulkResetModalTitle": "Réinitialiser {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", - "xpack.transform.transformList.bulkResetTransformSuccessMessage": "Réinitialisation effectuée avec succès de {count} {count, plural, one {transformation} many {transformations} other {transformations}}.", "xpack.transform.transformList.bulkStartModalTitle": "Démarrer {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", "xpack.transform.transformList.bulkStopModalTitle": "Arrêter {count} {count, plural, one {transformation} many {transformations} other {transformations}} ?", "xpack.transform.transformList.cannotRestartCompleteBatchTransformToolTip": "{transformId} est une transformation par lots terminée et ne peut pas être redémarrée.", "xpack.transform.transformList.cannotScheduleNowCompleteBatchTransformToolTip": "{transformId} est une transformation par lots terminée qui ne peut pas être planifiée pour traiter les données instantanément.", "xpack.transform.transformList.deleteModalTitle": "Supprimer {transformId} ?", "xpack.transform.transformList.deleteTransformErrorMessage": "Une erreur s'est produite lors de la suppression de la transformation {transformId}", - "xpack.transform.transformList.deleteTransformSuccessMessage": "La requête pour supprimer la transformation {transformId} a été reconnue.", "xpack.transform.transformList.editFlyoutFormPlaceholderText": "Par défaut : {defaultValue}", "xpack.transform.transformList.editFlyoutTitle": "Modifier {transformId}", - "xpack.transform.transformList.editTransformSuccessMessage": "Transformation {transformId} mise à jour.", "xpack.transform.transformList.reauthorizeModalTitle": "Réautoriser {transformId} ?", "xpack.transform.transformList.reauthorizeTransformErrorMessage": "Une erreur s'est produite lors de la réautorisation de la transformation {transformId}", - "xpack.transform.transformList.reauthorizeTransformSuccessMessage": "La requête pour réautoriser la transformation {transformId} a été reconnue.", "xpack.transform.transformList.resetModalTitle": "Réinitialiser {transformId} ?", "xpack.transform.transformList.resetTransformErrorMessage": "Une erreur s'est produite lors de la réinitialisation de la transformation {transformId}", - "xpack.transform.transformList.resetTransformSuccessMessage": "La requête pour réinitialiser la transformation {transformId} a été reconnue.", "xpack.transform.transformList.rowCollapse": "Masquer les détails pour {transformId}", "xpack.transform.transformList.rowExpand": "Afficher les détails pour {transformId}", "xpack.transform.transformList.scheduleNowTransformErrorMessage": "Une erreur s'est produite lors de la planification de la transformation {transformId} pour traiter les données instantanément.", - "xpack.transform.transformList.scheduleNowTransformSuccessMessage": "La demande de planification de transformation {transformId} pour traiter les données immédiatement a été reconnue.", "xpack.transform.transformList.startedTransformToolTip": "{transformId} a déjà démarré.", "xpack.transform.transformList.startModalTitle": "Démarrer {transformId} ?", "xpack.transform.transformList.startTransformErrorMessage": "Une erreur s'est produite lors du démarrage de la transformation {transformId}", - "xpack.transform.transformList.startTransformSuccessMessage": "La requête pour démarrer la transformation {transformId} a été reconnue.", "xpack.transform.transformList.stopModalTitle": "Arrêter {transformId} ?", "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} est déjà arrêtée.", "xpack.transform.transformList.stopTransformErrorMessage": "Une erreur s'est produite lors de l'arrêt de la transformation du cadre de données {transformId}", - "xpack.transform.transformList.stopTransformSuccessMessage": "La requête pour arrêter la transformation du cadre de données {transformId} a été reconnue.", "xpack.transform.transformList.unauthorizedTransformsCallout.insufficientPermissionsMsg": "{unauthorizedCnt, plural, one {Une transformation a été créée avec des autorisations insuffisantes.} many {# transformations ont été créées avec des autorisations insuffisantes.} other {# transformations ont été créées avec des autorisations insuffisantes.}}", "xpack.transform.transformList.unauthorizedTransformsCallout.reauthorizeMsg": "Réautorisez pour démarrer {unauthorizedCnt, plural, one {la transformation} many {# transformations} other {# transformations}}.", "xpack.transform.transformNodes.noTransformNodesCallOutBody": "Vous ne pourrez ni créer ni exécuter de transformations. {learnMoreLink}", @@ -37803,9 +37762,6 @@ "xpack.transform.alertTypes.transformHealth.notStartedCheckName": "La transformation n'a pas démarré", "xpack.transform.alertTypes.transformHealth.testsConfigTransforms.errorMessage": "Au moins une vérification d'intégrité doit être sélectionnée", "xpack.transform.alertTypes.transformHealth.testsSelection.enableTestLabel": "Activer", - "xpack.transform.app.checkingPrivilegesDescription": "Vérification des privilèges…", - "xpack.transform.app.checkingPrivilegesErrorMessage": "Erreur lors de la récupération des privilèges utilisateur depuis le serveur", - "xpack.transform.app.deniedPrivilegeTitle": "Vous ne disposez pas de privilèges de cluster", "xpack.transform.appName": "Transformations", "xpack.transform.appTitle": "Transformations", "xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip": "Vous ne disposez pas d'autorisation pour créer des règles d'alerte de transformation.", @@ -37851,7 +37807,6 @@ "xpack.transform.licenseCheckErrorMessage": "La vérification de la licence a échoué", "xpack.transform.list.emptyPromptButtonText": "Créez votre première transformation", "xpack.transform.list.emptyPromptTitle": "Aucune transformation n'a été trouvée", - "xpack.transform.list.errorPromptTitle": "Une erreur s'est produite lors de l'obtention de la liste de transformations", "xpack.transform.mode": "Mode", "xpack.transform.modeFilter": "Mode", "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "Toutes les autres requêtes ont été annulées.", @@ -38083,7 +38038,6 @@ "xpack.transform.transformList.editFlyoutUpdateButtonText": "Mettre à jour", "xpack.transform.transformList.editManagedTransformsDescription": "modification", "xpack.transform.transformList.editTransformGenericErrorMessage": "Une erreur s'est produite lors de l'appel du point de terminaison de l'API pour mettre à jour les transformations.", - "xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "Une erreur s'est produite lors de la vérification de la possibilité pour un utilisateur de supprimer l'index de destination", "xpack.transform.transformList.managedBadgeLabel": "Géré", "xpack.transform.transformList.managedBadgeTooltip": "Cette transformation est préconfigurée et gérée par Elastic. Les autres éléments du produit peuvent dépendre de ce comportement.", "xpack.transform.transformList.needsReauthorizationBadge.contactAdminTooltip": "Contactez votre administrateur pour demander les autorisations requises.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 3ccfa58b6e070..20cb00541f78c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2170,7 +2170,7 @@ "discover.advancedSettings.disableDocumentExplorerDescription": "クラシックビューではなく、{documentExplorerDocs}を使用するには、このオプションをオフにします。ドキュメントエクスプローラーでは、データの並べ替え、列のサイズ変更、全画面表示といった優れた機能を使用できます。", "discover.advancedSettings.discover.showFieldStatisticsDescription": "{fieldStatisticsDocs}を有効にすると、数値フィールドの最大/最小値やジオフィールドの地図といった詳細が表示されます。この機能はベータ段階で、変更される可能性があります。", "discover.advancedSettings.discover.showMultifieldsDescription": "拡張ドキュメントビューに{multiFields}が表示されるかどうかを制御します。ほとんどの場合、マルチフィールドは元のフィールドと同じです。「searchFieldsFromSource」がオフのときにのみこのオプションを使用できます。", - "discover.advancedSettings.enableSQLDescription": "{technicalPreviewLabel}このパッチプレビュー機能は実験段階です。本番の保存された検索、可視化、またはダッシュボードでは、この機能を信頼しないでください。この設定により、DiscoverとLensでテキストベースのクエリ言語としてSQLを使用できます。このエクスペリエンスに関するフィードバックがございましたら、{link}からお問い合わせください", + "discover.advancedSettings.enableESQLDescription": "{technicalPreviewLabel}このパッチプレビュー機能は実験段階です。本番の保存された検索、可視化、またはダッシュボードでは、この機能を信頼しないでください。この設定により、DiscoverとLensでテキストベースのクエリ言語としてSQLを使用できます。このエクスペリエンスに関するフィードバックがございましたら、{link}からお問い合わせください", "discover.context.contextOfTitle": "#{anchorId}の周りのドキュメント", "discover.context.newerDocumentsWarning": "アンカーよりも新しいドキュメントは{docCount}件しか見つかりませんでした。", "discover.context.olderDocumentsWarning": "アンカーよりも古いドキュメントは{docCount}件しか見つかりませんでした。", @@ -2193,11 +2193,6 @@ "discover.dscTour.stepAddFields.description": "{plusIcon}をクリックして、関心があるフィールドを追加します。", "discover.dscTour.stepExpand.description": "{expandIcon}をクリックすると、ドキュメントを表示、比較、フィルタリングできます。", "discover.errorCalloutFormattedTitle": "{title}: {errorMessage}", - "discover.grid.copyClipboardButtonTitle": "{column}の値をコピー", - "discover.grid.copyColumnValuesToClipboard.toastTitle": "\"{column}\"列の値がクリップボードにコピーされました", - "discover.grid.filterForAria": "この{value}でフィルターを適用", - "discover.grid.filterOutAria": "この{value}を除外", - "discover.gridSampleSize.limitDescription": "検索結果は{sampleSize}ドキュメントに制限されています。検索を絞り込むには、その他の検索用語を追加してください。", "discover.howToSeeOtherMatchingDocumentsDescription": "これらは検索条件に一致した初めの{sampleSize}件のドキュメントです。他の結果を表示するには検索条件を絞ってください。", "discover.noMatchRoute.bannerText": "Discoverアプリケーションはこのルートを認識できません:{route}", "discover.noResults.kqlExamples.kqlDescription": "{kqlLink}の詳細", @@ -2207,9 +2202,6 @@ "discover.pageTitleWithSavedSearch": "Discover - {savedSearchTitle}", "discover.savedSearchAliasMatchRedirect.objectNoun": "{savedSearch}検索", "discover.savedSearchURLConflictCallout.objectNoun": "{savedSearch}検索", - "discover.searchGenerationWithDescription": "検索{searchTitle}で生成されたテーブル", - "discover.searchGenerationWithDescriptionGrid": "検索{searchTitle}で生成されたテーブル({searchDescription})", - "discover.selectedDocumentsNumber": "{nr}個のドキュメントが選択されました", "discover.showingDefaultDataViewWarningDescription": "デフォルトのデータビューを表示しています:\"{loadedDataViewTitle}\"({loadedDataViewId})", "discover.showingSavedDataViewWarningDescription": "保存されたデータビューを表示しています:\"{ownDataViewTitle}\"({ownDataViewId})", "discover.singleDocRoute.errorMessage": "ID {dataViewId}の一致するデータビューが見つかりません", @@ -2235,8 +2227,8 @@ "discover.advancedSettings.docTableHideTimeColumnText": "Discover と、ダッシュボードのすべての保存された検索で、「時刻」列を非表示にします。", "discover.advancedSettings.docTableHideTimeColumnTitle": "「時刻」列を非表示", "discover.advancedSettings.documentExplorerLinkText": "ドキュメントエクスプローラー", - "discover.advancedSettings.enableSQL.discussLinkText": "discuss.elastic.co/c/elastic-stack/kibana", - "discover.advancedSettings.enableSQLTitle": "SQLを有効にする", + "discover.advancedSettings.enableESQL.discussLinkText": "discuss.elastic.co/c/elastic-stack/kibana", + "discover.advancedSettings.enableESQLTitle": "SQLを有効にする", "discover.advancedSettings.fieldsPopularLimitText": "最も頻繁に使用されるフィールドのトップNを表示します", "discover.advancedSettings.fieldsPopularLimitTitle": "頻繁に使用されるフィールドの制限", "discover.advancedSettings.maxDocFieldsDisplayedText": "ドキュメント概要でレンダリングされるフィールドの最大数", @@ -2262,7 +2254,6 @@ "discover.backToTopLinkText": "最上部へ戻る。", "discover.badge.readOnly.text": "読み取り専用", "discover.badge.readOnly.tooltip": "検索を保存できません", - "discover.clearSelection": "選択した項目をクリア", "discover.confirmDataViewSave.cancel": "キャンセル", "discover.confirmDataViewSave.message": "選択したアクションでは、保存されたデータビューが必要です。", "discover.confirmDataViewSave.saveAndContinue": "保存して続行", @@ -2283,8 +2274,6 @@ "discover.context.unableToLoadAnchorDocumentDescription": "アンカードキュメントを読み込めません", "discover.context.unableToLoadDocumentDescription": "ドキュメントを読み込めません", "discover.contextViewRoute.errorTitle": "エラーが発生しました", - "discover.controlColumnHeader": "列の制御", - "discover.copyToClipboardJSON": "ドキュメントをクリップボードにコピー(JSON)", "discover.discoverBreadcrumbTitle": "Discover", "discover.discoverDefaultSearchSessionName": "Discover", "discover.discoverDescription": "ドキュメントにクエリをかけたりフィルターを適用することで、データをインタラクティブに閲覧できます。", @@ -2383,29 +2372,15 @@ "discover.fieldChooser.discoverField.removeFieldTooltip": "フィールドを表から削除", "unifiedDocViewer.fieldChooser.discoverField.value": "値", "discover.goToDiscoverButtonText": "Discoverに移動", - "discover.grid.closePopover": "ポップオーバーを閉じる", - "discover.grid.copyCellValueButton": "値をコピー", - "discover.grid.copyColumnNameToClipboard.toastTitle": "クリップボードにコピーされました", - "discover.grid.copyColumnNameToClipBoardButton": "名前をコピー", - "discover.grid.copyColumnValuesToClipBoardButton": "列をコピー", - "discover.grid.copyEscapedValueWithFormulasToClipboardWarningText": "値にはエスケープされた式を含めることができます。", - "discover.grid.copyFailedErrorText": "このブラウザーではクリップボードにコピーできません", - "discover.grid.copyValueToClipboard.toastTitle": "クリップボードにコピーされました", - "discover.grid.documentHeader": "ドキュメント", - "discover.grid.editFieldButton": "データビューフィールドを編集", - "discover.grid.filterFor": "フィルター", - "discover.grid.filterOut": "除外", "discover.grid.flyout.documentNavigation": "ドキュメントナビゲーション", "discover.grid.flyout.toastColumnAdded": "列'{columnName}'が追加されました", "discover.grid.flyout.toastColumnRemoved": "列'{columnName}'が削除されました", - "discover.grid.selectDoc": "ドキュメント'{rowNumber}'を選択", "discover.grid.tableRow.detailHeading": "拡張ドキュメント", "discover.grid.tableRow.textBasedDetailHeading": "展開された行", "discover.grid.tableRow.viewSingleDocumentLinkTextSimple": "1つのドキュメント", "discover.grid.tableRow.viewSurroundingDocumentsHover": "このドキュメントの前後に出現したドキュメントを検査します。周りのドキュメントビューでは、固定されたフィルターのみがアクティブのままです。", "discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple": "周りのドキュメント", "discover.grid.tableRow.viewText": "表示:", - "discover.grid.viewDoc": "詳細ダイアログを切り替え", "discover.helpMenu.appName": "Discover", "discover.inspectorRequestDataTitleDocuments": "ドキュメント", "discover.inspectorRequestDescriptionDocument": "このリクエストはElasticsearchにクエリをかけ、ドキュメントを取得します。", @@ -2415,7 +2390,6 @@ "unifiedDocViewer.json.copyToClipboardLabel": "クリップボードにコピー", "discover.loadingDocuments": "ドキュメントを読み込み中", "unifiedDocViewer.loadingJSON": "JSONを読み込んでいます", - "discover.loadingResults": "結果を読み込み中", "discover.localMenu.alertsDescription": "アラート", "discover.localMenu.fallbackReportTitle": "無題のDiscover検索", "discover.localMenu.inspectTitle": "検査", @@ -2458,23 +2432,18 @@ "discover.noResults.suggestion.syntaxPopoverExampleHeader": "例", "discover.noResults.suggestion.tryText": "次の方法を試してください:", "discover.noResults.suggestion.viewAllMatchesButtonText": "すべての一致を表示", - "discover.noResultsFound": "結果が見つかりませんでした", "discover.notifications.invalidTimeRangeText": "指定された時間範囲が無効です。(開始:'{from}'、終了:'{to}')", "discover.notifications.invalidTimeRangeTitle": "無効な時間範囲", "discover.notifications.notSavedSearchTitle": "検索「{savedSearchTitle}」は保存されませんでした。", "discover.notifications.savedSearchTitle": "検索「{savedSearchTitle}」が保存されました。", "discover.pageTitleWithoutSavedSearch": "Discover - 検索は保存されていません", "discover.reloadSavedSearchButton": "検索をリセット", - "discover.removeColumnLabel": "列を削除", "discover.rootBreadcrumb": "Discover", "discover.sampleData.viewLinkLabel": "Discover", "discover.savedSearch.savedObjectName": "保存検索", "discover.savedSearchEmbeddable.action.viewSavedSearch.displayName": "Discoverで開く", "discover.searchingTitle": "検索中", - "discover.selectColumnHeader": "列を選択", "discover.serverLocatorExtension.titleFromLocatorUnknown": "不明な検索", - "discover.showAllDocuments": "すべてのドキュメントを表示", - "discover.showSelectedDocumentsOnly": "選択したドキュメントのみを表示", "discover.singleDocRoute.errorTitle": "エラーが発生しました", "discover.skipToBottomButtonLabel": "テーブルの最後に移動", "unifiedDocViewer.sourceViewer.errorMessage": "現在データを取得できませんでした。タブを更新して、再試行してください。", @@ -2496,6 +2465,25 @@ "discover.viewAlert.searchSourceErrorTitle": "検索ソースの取得エラー", "discover.viewModes.document.label": "ドキュメント", "discover.viewModes.fieldStatistics.label": "フィールド統計情報", + "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} - このフィールドはイベントの発生時刻を表します。", + "unifiedDataTable.searchGenerationWithDescription": "検索{searchTitle}で生成されたテーブル", + "unifiedDataTable.searchGenerationWithDescriptionGrid": "検索{searchTitle}で生成されたテーブル({searchDescription})", + "unifiedDataTable.selectedDocumentsNumber": "{nr}個のドキュメントが選択されました", + "unifiedDataTable.clearSelection": "選択した項目をクリア", + "unifiedDataTable.controlColumnHeader": "列の制御", + "unifiedDataTable.copyToClipboardJSON": "ドキュメントをクリップボードにコピー(JSON)", + "unifiedDataTable.tableHeader.timeFieldIconTooltip": "このフィールドはイベントの発生時刻を表します。", + "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "名前をコピー", + "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "列をコピー", + "unifiedDataTable.grid.documentHeader": "ドキュメント", + "unifiedDataTable.grid.editFieldButton": "データビューフィールドを編集", + "unifiedDataTable.grid.selectDoc": "ドキュメント'{rowNumber}'を選択", + "unifiedDataTable.loadingResults": "結果を読み込み中", + "unifiedDataTable.noResultsFound": "結果が見つかりませんでした", + "unifiedDataTable.removeColumnLabel": "列を削除", + "unifiedDataTable.selectColumnHeader": "列を選択", + "unifiedDataTable.showAllDocuments": "すべてのドキュメントを表示", + "unifiedDataTable.showSelectedDocumentsOnly": "選択したドキュメントのみを表示", "domDragDrop.announce.cancelled": "移動がキャンセルされました。{label}は初期位置に戻りました", "domDragDrop.announce.cancelledItem": "移動がキャンセルされました。{label}は位置{position}の{groupLabel}グループに戻りました", "domDragDrop.announce.dropped.combineCompatible": "レイヤー{dropLayerNumber}の位置{dropPosition}でグループ{dropGroupLabel}の{dropLabel}にグループ{groupLabel}の{label}を結合しました。", @@ -5941,9 +5929,6 @@ "unifiedSearch.query.queryBar.indexPattern.findFilterSet": "クエリを検索", "unifiedSearch.query.queryBar.indexPattern.manageFieldButton": "このデータビューを管理", "unifiedSearch.query.queryBar.indexPattern.temporaryDataviewLabel": "一時", - "unifiedSearch.query.queryBar.indexPattern.textBasedLangSwitchWarning": "データビューを切り替えると、現在のSQLクエリが削除されます。この検索を保存すると、作業内容が失われないことが保証されます。", - "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesLabel": "テキストベースのクエリ言語", - "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalBody": "データビューを切り替えると、現在のSQLクエリが削除されます。この検索を保存すると、作業内容が失われないことが保証されます。", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalCloseButton": "保存せずに切り替え", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalDismissButton": "次回以降この警告を表示しない", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalSaveButton": "保存して切り替え", @@ -27640,8 +27625,6 @@ "xpack.observability.slo.sloEdit.sliType.customKql.goodQuery.tooltip": "このKQLクエリは、SLOを計算する目的で、「良好」または「成功」と見なされるイベントのサブセットを返します。このクエリは、ステータスコード、エラー、メッセージ、または他の関連するフィールドなどの一部の関連する条件に基づいて、イベントをフィルタリングします。", "xpack.observability.slo.sloEdit.sliType.customKql.goodQueryPlaceholder": "良いイベントを定義", "xpack.observability.slo.sloEdit.sliType.customKql.queryFilter": "クエリのフィルター", - "xpack.observability.slo.sloEdit.sliType.customKql.timestampField.label": "タイムスタンプフィールド", - "xpack.observability.slo.sloEdit.sliType.customKql.timestampField.placeholder": "タイムスタンプフィールドを選択", "xpack.observability.slo.sloEdit.sliType.customKql.totalQuery": "合計クエリ", "xpack.observability.slo.sloEdit.sliType.customKql.totalQuery.tooltip": "このKQLクエリは、良好なイベントと問題があるイベントの両方を含む、SLO計算に関連するすべてのイベントを返します。", "xpack.observability.slo.sloEdit.sliType.customKql.totalQueryPlaceholder": "合計イベントを定義", @@ -27655,8 +27638,6 @@ "xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder": "メトリックフィールドを選択", "xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter": "クエリのフィルター", "xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel": "の合計", - "xpack.observability.slo.sloEdit.sliType.customMetric.timestampField.label": "タイムスタンプフィールド", - "xpack.observability.slo.sloEdit.sliType.customMetric.timestampField.placeholder": "タイムスタンプフィールドを選択", "xpack.observability.slo.sloEdit.tags.label": "タグ", "xpack.observability.slo.sloEdit.tags.placeholder": "タグを追加", "xpack.observability.slo.sloEdit.targetSlo.label": "目標 / SLO(%)", @@ -34619,10 +34600,6 @@ "xpack.serverlessSearch.apiKey.roleDescriptorsLinkLabel": "ロール記述子を構造化する方法をご覧ください", "xpack.serverlessSearch.apiKey.setup.description": "APIキーを作成するための基本構成詳細情報。", "xpack.serverlessSearch.apiKey.setup.title": "セットアップ", - "xpack.serverlessSearch.apiKey.stepOneDescription": "認証と認可のための一意の識別子。", - "xpack.serverlessSearch.apiKey.stepOneTitle": "APIキーを生成して保存", - "xpack.serverlessSearch.apiKey.stepTwoDescription": "特定のプロジェクトの一意の識別子。", - "xpack.serverlessSearch.apiKey.stepTwoTitle": "一意のCloud IDを保存", "xpack.serverlessSearch.apiKey.title": "APIキーとCloud IDを保存", "xpack.serverlessSearch.apiKey.userFieldHelpText": "APIキーを作成するユーザーのID。", "xpack.serverlessSearch.apiKey.userFieldLabel": "ユーザー", @@ -37691,26 +37668,19 @@ "xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage": "{count, plural, other {トランスフォーム}} {transformsString} {count, plural, other {あります}}は正常です。", "xpack.transform.alertTypes.transformHealth.notStartedMessage": "{count, plural, other {トランスフォーム}}\"{transformsString}\"{count, plural, other {あります}}開始されていません。", "xpack.transform.alertTypes.transformHealth.notStartedRecoveryMessage": "{count, plural, other {トランスフォーム}}\"{transformsString}\"{count, plural, other {あります}}開始しました。", - "xpack.transform.app.deniedPrivilegeDescription": "変換のこのセクションを使用するには、{privilegesCount, plural, other {これらのクラスター権限}}が必要です:{missingPrivileges}", "xpack.transform.capability.pleaseContactAdministratorTooltip": "{message} 管理者にお問い合わせください。", "xpack.transform.clone.noDataViewErrorPromptText": "トランスフォーム{transformId}を複製できません。{dataViewTitle}のデータビューは存在しません。", "xpack.transform.danglingTasksError": "{count}個の{count, plural, other {変換}}に構成の詳細がありません:[{transformIds}]。{count, plural, other {それら}}回復できないため、削除してください。", "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage": "データビュー{destinationIndex}の削除中にエラーが発生しました", - "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage": "データビュー {destinationIndex} の削除リクエストが受け付けられました。", "xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage": "ディスティネーションインデックス{destinationIndex}の削除中にエラーが発生しました", - "xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage": "ディスティネーションインデックス{destinationIndex}を削除する要求が確認されました。", "xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage": "データビュー{dataView}が存在するかどうかを確認するときにエラーが発生しました:{error}", "xpack.transform.edit.noDataViewErrorPromptText": "変換{transformId}のデータビューを取得できません。{dataViewTitle}のデータビューは存在しません。", "xpack.transform.forceDeleteTransformMessage": "{count}{count, plural, other {変換}}の削除", "xpack.transform.managedTransformsWarningCallout": "{count, plural, other {これらの変換のうちの少なくとも1個の変換}}はElasticによってあらかじめ構成されています。{count, plural, other {それらを}}{action}すると、製品の他の部分に影響する可能性があります。", "xpack.transform.multiTransformActionsMenu.transformsCount": "{count}個の{count, plural, other {変換}}を選択済み", "xpack.transform.stepCreateForm.createDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:", - "xpack.transform.stepCreateForm.createDataViewSuccessMessage": "Kibanaデータビュー{dataViewName}が正常に作成されました。", "xpack.transform.stepCreateForm.createTransformErrorMessage": "変換 {transformId} の取得中にエラーが発生しました。", - "xpack.transform.stepCreateForm.createTransformSuccessMessage": "変換 {transformId} の作成リクエストが受け付けられました。", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "Kibanaデータビュー{dataViewName}の作成中にエラーが発生しました:データビューはすでに存在します。", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "変換 {transformId} の開始中にエラーが発生しました。", - "xpack.transform.stepCreateForm.startTransformSuccessMessage": "変換 {transformId} の開始リクエストが受け付けられました。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "無効なクエリ:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例: {example}.", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "例: {example}.", @@ -37722,41 +37692,30 @@ "xpack.transform.stepDetailsForm.retentionPolicyMaxAgePlaceholderText": "max_age 例:{exampleValue}", "xpack.transform.transformForm.sizeNotationPlaceholder": "例:{example1}, {example2}, {example3}, {example4}", "xpack.transform.transformList.alertingRules.tooltipContent": "変換には{rulesCount}個の関連付けられたアラート{rulesCount, plural, other { ルール}}があります", - "xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage": "{count}個のディスティネーションデータ{count, plural, other {ビュー}}が正常に削除されました。", - "xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage": "{count}個のディスティネーション{count, plural, other {インデックス}}が正常に削除されました。", "xpack.transform.transformList.bulkDeleteModalTitle": "{count}{count, plural, other {変換}}を削除しますか?", - "xpack.transform.transformList.bulkDeleteTransformSuccessMessage": "{count}個の{count, plural, other {トランスフォーム}}が正常に削除されました。", "xpack.transform.transformList.bulkReauthorizeModalTitle": "{count} {count, plural, other {トランスフォーム}}をもう一度認可しますか?", "xpack.transform.transformList.bulkResetModalTitle": "{count}個の{count, plural, other {変換}}をリセットしますか?", - "xpack.transform.transformList.bulkResetTransformSuccessMessage": "{count}個の{count, plural, other {変換}}が正常にリセットされました。", "xpack.transform.transformList.bulkStartModalTitle": "{count}個の{count, plural, other {変換}}を開始しますか?", "xpack.transform.transformList.bulkStopModalTitle": "{count}個のを{count, plural, other {変換}}停止しますか?", "xpack.transform.transformList.cannotRestartCompleteBatchTransformToolTip": "{transformId} は完了済みの一斉変換で、再度開始できません。", "xpack.transform.transformList.cannotScheduleNowCompleteBatchTransformToolTip": "{transformId}は完了済みのバッチ変換であるため、データの即時処理のスケジュールを設定できません。", "xpack.transform.transformList.deleteModalTitle": "{transformId}を削除しますか?", "xpack.transform.transformList.deleteTransformErrorMessage": "変換 {transformId} の削除中にエラーが発生しました", - "xpack.transform.transformList.deleteTransformSuccessMessage": "変換 {transformId} の削除リクエストが受け付けられました。", "xpack.transform.transformList.editFlyoutFormPlaceholderText": "デフォルト:{defaultValue}", "xpack.transform.transformList.editFlyoutTitle": "{transformId}の編集", - "xpack.transform.transformList.editTransformSuccessMessage": "変換{transformId}が更新されました。", "xpack.transform.transformList.reauthorizeModalTitle": "{transformId}をもう一度許可しますか?", "xpack.transform.transformList.reauthorizeTransformErrorMessage": "変換{transformId}の再認可中にエラーが発生しました", - "xpack.transform.transformList.reauthorizeTransformSuccessMessage": "変換{transformId}の再認可リクエストが受け付けられました。", "xpack.transform.transformList.resetModalTitle": "{transformId}をリセットしますか?", "xpack.transform.transformList.resetTransformErrorMessage": "変換{transformId}のリセット中にエラーが発生しました", - "xpack.transform.transformList.resetTransformSuccessMessage": "変換{transformId}のリセットリクエストが受け付けられました。", "xpack.transform.transformList.rowCollapse": "{transformId} の詳細を非表示", "xpack.transform.transformList.rowExpand": "{transformId} の詳細を表示", "xpack.transform.transformList.scheduleNowTransformErrorMessage": "変換{transformId}でデータの即時処理のスケジュールの設定中にエラーが発生しました。", - "xpack.transform.transformList.scheduleNowTransformSuccessMessage": "変換{transformId}でデータの即時処理のスケジュールを設定するリクエストが受け付けられました。", "xpack.transform.transformList.startedTransformToolTip": "{transformId} はすでに開始済みです。", "xpack.transform.transformList.startModalTitle": "{transformId}を開始しますか?", "xpack.transform.transformList.startTransformErrorMessage": "変換 {transformId} の開始中にエラーが発生しました", - "xpack.transform.transformList.startTransformSuccessMessage": "変換 {transformId} の開始リクエストが受け付けられました。", "xpack.transform.transformList.stopModalTitle": "{transformId}を終了しますか?", "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} はすでに停止済みです。", "xpack.transform.transformList.stopTransformErrorMessage": "データフレーム変換 {transformId} の停止中にエラーが発生しました", - "xpack.transform.transformList.stopTransformSuccessMessage": "データフレーム変換 {transformId} の停止リクエストが受け付けられました。", "xpack.transform.transformList.unauthorizedTransformsCallout.insufficientPermissionsMsg": "{unauthorizedCnt, plural, other {十分な権限がない状態で#個の変換が作成されました。}}", "xpack.transform.transformList.unauthorizedTransformsCallout.reauthorizeMsg": "もう一度認可して、{unauthorizedCnt, plural, other {#個の変換}}を開始してください。", "xpack.transform.transformNodes.noTransformNodesCallOutBody": "変換の作成または実行はできません。{learnMoreLink}。", @@ -37802,9 +37761,6 @@ "xpack.transform.alertTypes.transformHealth.notStartedCheckName": "トランスフォームが開始していません", "xpack.transform.alertTypes.transformHealth.testsConfigTransforms.errorMessage": "1つ以上の正常性チェックを選択する必要があります", "xpack.transform.alertTypes.transformHealth.testsSelection.enableTestLabel": "有効にする", - "xpack.transform.app.checkingPrivilegesDescription": "権限を確認中…", - "xpack.transform.app.checkingPrivilegesErrorMessage": "サーバーからユーザー特権を取得しているときにエラーが発生しました", - "xpack.transform.app.deniedPrivilegeTitle": "クラスター特権が足りません", "xpack.transform.appName": "トランスフォーム", "xpack.transform.appTitle": "トランスフォーム", "xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip": "トランスフォームアラートルールを作成するアクセス権がありません。", @@ -37850,7 +37806,6 @@ "xpack.transform.licenseCheckErrorMessage": "ライセンス確認失敗", "xpack.transform.list.emptyPromptButtonText": "初めてのトランスフォームを作成", "xpack.transform.list.emptyPromptTitle": "トランスフォームが見つかりません", - "xpack.transform.list.errorPromptTitle": "トランスフォームリストの取得中にエラーが発生しました", "xpack.transform.mode": "モード", "xpack.transform.modeFilter": "モード", "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "他のすべてのリクエストはキャンセルされました。", @@ -38082,7 +38037,6 @@ "xpack.transform.transformList.editFlyoutUpdateButtonText": "更新", "xpack.transform.transformList.editManagedTransformsDescription": "編集中", "xpack.transform.transformList.editTransformGenericErrorMessage": "トランスフォームを削除するためのAPIエンドポイントの呼び出し中にエラーが発生しました。", - "xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "ユーザーがディスティネーションインデックスを削除できるかどうかを確認するときにエラーが発生しました。", "xpack.transform.transformList.managedBadgeLabel": "管理中", "xpack.transform.transformList.managedBadgeTooltip": "このトランスフォームはElasticによってあらかじめ構成および管理されています。製品の他の部分はその動作に依存関係が存在している場合があります。", "xpack.transform.transformList.needsReauthorizationBadge.contactAdminTooltip": "必要な権限をリクエストするには、管理者に問い合わせてください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a6538965d28a6..fdc52c8db4fcc 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2170,7 +2170,7 @@ "discover.advancedSettings.disableDocumentExplorerDescription": "要使用新的 {documentExplorerDocs},而非经典视图,请关闭此选项。Document Explorer 提供了更合理的数据排序、可调整大小的列和全屏视图。", "discover.advancedSettings.discover.showFieldStatisticsDescription": "启用 {fieldStatisticsDocs} 以显示详细信息,如数字字段的最小和最大值,或地理字段的地图。此功能为公测版,可能会进行更改。", "discover.advancedSettings.discover.showMultifieldsDescription": "控制 {multiFields} 是否显示在展开的文档视图中。多数情况下,多字段与原始字段相同。此选项仅在 `searchFieldsFromSource` 关闭时可用。", - "discover.advancedSettings.enableSQLDescription": "{technicalPreviewLabel} 此技术预览功能为高度实验性功能 -- 请勿在生产已保存搜索、可视化或仪表板中依赖此功能。此设置在 Discover 和 Lens 中将 SQL 用作基于文本的查询语言。如果具有与此体验有关的反馈,请通过 {link} 联系我们", + "discover.advancedSettings.enableESQLDescription": "{technicalPreviewLabel} 此技术预览功能为高度实验性功能 -- 请勿在生产已保存搜索、可视化或仪表板中依赖此功能。此设置在 Discover 和 Lens 中将 SQL 用作基于文本的查询语言。如果具有与此体验有关的反馈,请通过 {link} 联系我们", "discover.context.contextOfTitle": "#{anchorId} 周围的文档", "discover.context.newerDocumentsWarning": "仅可以找到 {docCount} 个比定位标记新的文档。", "discover.context.olderDocumentsWarning": "仅可以找到 {docCount} 个比定位标记旧的文档。", @@ -2193,11 +2193,6 @@ "discover.dscTour.stepAddFields.description": "单击 {plusIcon} 以添加您感兴趣的字段。", "discover.dscTour.stepExpand.description": "单击 {expandIcon} 以查看、比较和筛选文档。", "discover.errorCalloutFormattedTitle": "{title}: {errorMessage}", - "discover.grid.copyClipboardButtonTitle": "复制 {column} 的值", - "discover.grid.copyColumnValuesToClipboard.toastTitle": "“{column}”列的值已复制到剪贴板", - "discover.grid.filterForAria": "筛留此 {value}", - "discover.grid.filterOutAria": "筛除此 {value}", - "discover.gridSampleSize.limitDescription": "搜索结果被限定为 {sampleSize} 个文档。添加更多搜索词以缩小搜索范围。", "discover.howToSeeOtherMatchingDocumentsDescription": "以下是匹配您的搜索的前 {sampleSize} 个文档,请优化您的搜索以查看其他文档。", "discover.noMatchRoute.bannerText": "Discover 应用程序无法识别此路由:{route}", "discover.noResults.kqlExamples.kqlDescription": "详细了解 {kqlLink}", @@ -2207,9 +2202,6 @@ "discover.pageTitleWithSavedSearch": "Discover - {savedSearchTitle}", "discover.savedSearchAliasMatchRedirect.objectNoun": "{savedSearch} 搜索", "discover.savedSearchURLConflictCallout.objectNoun": "{savedSearch} 搜索", - "discover.searchGenerationWithDescription": "搜索 {searchTitle} 生成的表", - "discover.searchGenerationWithDescriptionGrid": "搜索 {searchTitle} 生成的表({searchDescription})", - "discover.selectedDocumentsNumber": "{nr} 个文档已选择", "discover.showingDefaultDataViewWarningDescription": "正在显示默认数据视图:“{loadedDataViewTitle}”({loadedDataViewId})", "discover.showingSavedDataViewWarningDescription": "正在显示已保存数据视图:“{ownDataViewTitle}”({ownDataViewId})", "discover.singleDocRoute.errorMessage": "没有与 ID {dataViewId} 相匹配的数据视图", @@ -2235,8 +2227,8 @@ "discover.advancedSettings.docTableHideTimeColumnText": "在 Discover 中和仪表板上的所有已保存搜索中隐藏“时间”列。", "discover.advancedSettings.docTableHideTimeColumnTitle": "隐藏“时间”列", "discover.advancedSettings.documentExplorerLinkText": "Document Explorer", - "discover.advancedSettings.enableSQL.discussLinkText": "discuss.elastic.co/c/elastic-stack/kibana", - "discover.advancedSettings.enableSQLTitle": "启用 SQL", + "discover.advancedSettings.enableESQL.discussLinkText": "discuss.elastic.co/c/elastic-stack/kibana", + "discover.advancedSettings.enableESQLTitle": "启用 SQL", "discover.advancedSettings.fieldsPopularLimitText": "要显示的排名前 N 最常见字段", "discover.advancedSettings.fieldsPopularLimitTitle": "常见字段限制", "discover.advancedSettings.maxDocFieldsDisplayedText": "在文档摘要中渲染的最大字段数目", @@ -2262,7 +2254,6 @@ "discover.backToTopLinkText": "返回顶部。", "discover.badge.readOnly.text": "只读", "discover.badge.readOnly.tooltip": "无法保存搜索", - "discover.clearSelection": "清除所选内容", "discover.confirmDataViewSave.cancel": "取消", "discover.confirmDataViewSave.message": "您选择的操作需要已保存的数据视图。", "discover.confirmDataViewSave.saveAndContinue": "保存并继续", @@ -2283,8 +2274,6 @@ "discover.context.unableToLoadAnchorDocumentDescription": "无法加载该定位点文档", "discover.context.unableToLoadDocumentDescription": "无法加载文档", "discover.contextViewRoute.errorTitle": "发生错误", - "discover.controlColumnHeader": "控制列", - "discover.copyToClipboardJSON": "将文档复制到剪贴板 (JSON)", "discover.discoverBreadcrumbTitle": "Discover", "discover.discoverDefaultSearchSessionName": "发现", "discover.discoverDescription": "通过查询和筛选原始文档来以交互方式浏览您的数据。", @@ -2383,29 +2372,15 @@ "discover.fieldChooser.discoverField.removeFieldTooltip": "从表中移除字段", "unifiedDocViewer.fieldChooser.discoverField.value": "值", "discover.goToDiscoverButtonText": "前往 Discover", - "discover.grid.closePopover": "关闭弹出框", - "discover.grid.copyCellValueButton": "复制值", - "discover.grid.copyColumnNameToClipboard.toastTitle": "已复制到剪贴板", - "discover.grid.copyColumnNameToClipBoardButton": "复制名称", - "discover.grid.copyColumnValuesToClipBoardButton": "复制列", - "discover.grid.copyEscapedValueWithFormulasToClipboardWarningText": "值可能包含已转义的公式。", - "discover.grid.copyFailedErrorText": "无法在此浏览器中复制到剪贴板", - "discover.grid.copyValueToClipboard.toastTitle": "已复制到剪贴板", - "discover.grid.documentHeader": "文档", - "discover.grid.editFieldButton": "编辑数据视图字段", - "discover.grid.filterFor": "筛留", - "discover.grid.filterOut": "筛除", "discover.grid.flyout.documentNavigation": "文档导航", "discover.grid.flyout.toastColumnAdded": "已添加列“{columnName}”", "discover.grid.flyout.toastColumnRemoved": "已移除列“{columnName}”", - "discover.grid.selectDoc": "选择文档“{rowNumber}”", "discover.grid.tableRow.detailHeading": "已展开文档", "discover.grid.tableRow.textBasedDetailHeading": "已展开行", "discover.grid.tableRow.viewSingleDocumentLinkTextSimple": "单个文档", "discover.grid.tableRow.viewSurroundingDocumentsHover": "检查在此文档之前和之后出现的文档。在周围文档视图中,仅已固定筛选仍处于活动状态。", "discover.grid.tableRow.viewSurroundingDocumentsLinkTextSimple": "周围文档", "discover.grid.tableRow.viewText": "视图:", - "discover.grid.viewDoc": "切换具有详情的对话框", "discover.helpMenu.appName": "Discover", "discover.inspectorRequestDataTitleDocuments": "文档", "discover.inspectorRequestDescriptionDocument": "此请求将查询 Elasticsearch 以获取文档。", @@ -2415,7 +2390,6 @@ "unifiedDocViewer.json.copyToClipboardLabel": "复制到剪贴板", "discover.loadingDocuments": "正在加载文档", "unifiedDocViewer.loadingJSON": "正在加载 JSON", - "discover.loadingResults": "正在加载结果", "discover.localMenu.alertsDescription": "告警", "discover.localMenu.fallbackReportTitle": "未命名 Discover 搜索", "discover.localMenu.inspectTitle": "检查", @@ -2458,23 +2432,18 @@ "discover.noResults.suggestion.syntaxPopoverExampleHeader": "示例", "discover.noResults.suggestion.tryText": "这里是要尝试的一些内容:", "discover.noResults.suggestion.viewAllMatchesButtonText": "查看所有匹配项", - "discover.noResultsFound": "找不到结果", "discover.notifications.invalidTimeRangeText": "提供的时间范围无效。(自:“{from}”,至:“{to}”)", "discover.notifications.invalidTimeRangeTitle": "时间范围无效", "discover.notifications.notSavedSearchTitle": "搜索“{savedSearchTitle}”未保存。", "discover.notifications.savedSearchTitle": "搜索“{savedSearchTitle}”已保存", "discover.pageTitleWithoutSavedSearch": "Discover - 尚未保存搜索", "discover.reloadSavedSearchButton": "重置搜索", - "discover.removeColumnLabel": "移除列", "discover.rootBreadcrumb": "Discover", "discover.sampleData.viewLinkLabel": "Discover", "discover.savedSearch.savedObjectName": "已保存搜索", "discover.savedSearchEmbeddable.action.viewSavedSearch.displayName": "在 Discover 中打开", "discover.searchingTitle": "正在搜索", - "discover.selectColumnHeader": "选择列", "discover.serverLocatorExtension.titleFromLocatorUnknown": "未知搜索", - "discover.showAllDocuments": "显示所有文档", - "discover.showSelectedDocumentsOnly": "仅显示选定的文档", "discover.singleDocRoute.errorTitle": "发生错误", "discover.skipToBottomButtonLabel": "转到表尾", "unifiedDocViewer.sourceViewer.errorMessage": "当前无法获取数据。请刷新选项卡以重试。", @@ -2496,6 +2465,25 @@ "discover.viewAlert.searchSourceErrorTitle": "提取搜索源时出错", "discover.viewModes.document.label": "文档", "discover.viewModes.fieldStatistics.label": "字段统计信息", + "unifiedDataTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} - 此字段表示事件发生的时间。", + "unifiedDataTable.searchGenerationWithDescription": "搜索 {searchTitle} 生成的表", + "unifiedDataTable.searchGenerationWithDescriptionGrid": "搜索 {searchTitle} 生成的表({searchDescription})", + "unifiedDataTable.selectedDocumentsNumber": "{nr} 个文档已选择", + "unifiedDataTable.clearSelection": "清除所选内容", + "unifiedDataTable.controlColumnHeader": "控制列", + "unifiedDataTable.copyToClipboardJSON": "将文档复制到剪贴板 (JSON)", + "unifiedDataTable.tableHeader.timeFieldIconTooltip": "此字段表示事件发生的时间。", + "unifiedDataTable.grid.copyColumnNameToClipBoardButton": "复制名称", + "unifiedDataTable.grid.copyColumnValuesToClipBoardButton": "复制列", + "unifiedDataTable.grid.documentHeader": "文档", + "unifiedDataTable.grid.editFieldButton": "编辑数据视图字段", + "unifiedDataTable.grid.selectDoc": "选择文档“{rowNumber}”", + "unifiedDataTable.loadingResults": "正在加载结果", + "unifiedDataTable.noResultsFound": "找不到结果", + "unifiedDataTable.removeColumnLabel": "移除列", + "unifiedDataTable.selectColumnHeader": "选择列", + "unifiedDataTable.showAllDocuments": "显示所有文档", + "unifiedDataTable.showSelectedDocumentsOnly": "仅显示选定的文档", "domDragDrop.announce.cancelled": "移动已取消。{label} 已返回至其初始位置", "domDragDrop.announce.cancelledItem": "移动已取消。{label} 返回至 {groupLabel} 组中的位置 {position}", "domDragDrop.announce.dropped.combineCompatible": "已将组 {groupLabel} 中的 {label} 组合到图层 {dropLayerNumber} 的组 {dropGroupLabel} 中的位置 {dropPosition} 上的 {dropLabel}", @@ -5940,9 +5928,6 @@ "unifiedSearch.query.queryBar.indexPattern.findFilterSet": "查找查询", "unifiedSearch.query.queryBar.indexPattern.manageFieldButton": "管理此数据视图", "unifiedSearch.query.queryBar.indexPattern.temporaryDataviewLabel": "临时", - "unifiedSearch.query.queryBar.indexPattern.textBasedLangSwitchWarning": "切换数据视图会移除当前的 SQL 查询。保存此搜索以确保不会丢失工作。", - "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesLabel": "基于文本的查询语言", - "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalBody": "切换数据视图会移除当前的 SQL 查询。保存此搜索以确保不会丢失工作。", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalCloseButton": "切换而不保存", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalDismissButton": "不再显示此警告", "unifiedSearch.query.queryBar.indexPattern.textBasedLanguagesTransitionModalSaveButton": "保存并切换", @@ -27638,8 +27623,6 @@ "xpack.observability.slo.sloEdit.sliType.customKql.goodQuery.tooltip": "此 KQL 查询应返回用于计算 SLO 时被视为“良好”或“成功”的事件的子集。此查询应基于某些相关条件(如状态代码、错误消息或其他相关字段)筛选事件。", "xpack.observability.slo.sloEdit.sliType.customKql.goodQueryPlaceholder": "定义良好事件", "xpack.observability.slo.sloEdit.sliType.customKql.queryFilter": "查询筛选", - "xpack.observability.slo.sloEdit.sliType.customKql.timestampField.label": "时间戳字段", - "xpack.observability.slo.sloEdit.sliType.customKql.timestampField.placeholder": "选择时间戳字段", "xpack.observability.slo.sloEdit.sliType.customKql.totalQuery": "查询总数", "xpack.observability.slo.sloEdit.sliType.customKql.totalQuery.tooltip": "此 KQL 查询应返回与 SLO 计算相关的所有事件,包括良好和不良事件。", "xpack.observability.slo.sloEdit.sliType.customKql.totalQueryPlaceholder": "定义事件总数", @@ -27653,8 +27636,6 @@ "xpack.observability.slo.sloEdit.sliType.customMetric.metricField.placeholder": "选择指标字段", "xpack.observability.slo.sloEdit.sliType.customMetric.queryFilter": "查询筛选", "xpack.observability.slo.sloEdit.sliType.customMetric.sumLabel": "求和", - "xpack.observability.slo.sloEdit.sliType.customMetric.timestampField.label": "时间戳字段", - "xpack.observability.slo.sloEdit.sliType.customMetric.timestampField.placeholder": "选择时间戳字段", "xpack.observability.slo.sloEdit.tags.label": "标签", "xpack.observability.slo.sloEdit.tags.placeholder": "添加标签", "xpack.observability.slo.sloEdit.targetSlo.label": "目标/SLO (%)", @@ -34615,10 +34596,6 @@ "xpack.serverlessSearch.apiKey.roleDescriptorsLinkLabel": "了解如何构造角色描述符", "xpack.serverlessSearch.apiKey.setup.description": "用于创建 API 密钥的基本配置详情。", "xpack.serverlessSearch.apiKey.setup.title": "设置", - "xpack.serverlessSearch.apiKey.stepOneDescription": "用于身份验证和授权的唯一标识符。", - "xpack.serverlessSearch.apiKey.stepOneTitle": "生成并存储 API 密钥", - "xpack.serverlessSearch.apiKey.stepTwoDescription": "用于特定项目的唯一标识符。", - "xpack.serverlessSearch.apiKey.stepTwoTitle": "存储您的唯一云 ID", "xpack.serverlessSearch.apiKey.title": "存储您的 API 密钥和云 ID", "xpack.serverlessSearch.apiKey.userFieldHelpText": "创建 API 密钥的用户的 ID。", "xpack.serverlessSearch.apiKey.userFieldLabel": "用户", @@ -37685,26 +37662,19 @@ "xpack.transform.alertTypes.transformHealth.healthCheckRecoveryMessage": "{count, plural, other {转换}} {transformsString}{count, plural, other {有}}运行正常。", "xpack.transform.alertTypes.transformHealth.notStartedMessage": "{count, plural, other {转换}} {transformsString}{count, plural, other {有}}未启动。", "xpack.transform.alertTypes.transformHealth.notStartedRecoveryMessage": "{count, plural, other {转换}} {transformsString}{count, plural, other {有}}已启动。", - "xpack.transform.app.deniedPrivilegeDescription": "要使用“转换”部分,必须具有{privilegesCount, plural, other {以下集群权限}}:{missingPrivileges}。", "xpack.transform.capability.pleaseContactAdministratorTooltip": "{message}请联系您的管理员。", "xpack.transform.clone.noDataViewErrorPromptText": "无法克隆转换 {transformId}。对于 {dataViewTitle},不存在数据视图。", "xpack.transform.danglingTasksError": "{count} 个{count, plural, other {转换}}缺少配置详情:[{transformIds}] 无法将{count, plural, other {其}}恢复,应予以删除。", "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewErrorMessage": "删除数据视图 {destinationIndex} 时出错", - "xpack.transform.deleteTransform.deleteAnalyticsWithDataViewSuccessMessage": "删除数据视图 {destinationIndex} 的请求已确认。", "xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage": "删除目标索引 {destinationIndex} 时发生错误", - "xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage": "删除目标索引 {destinationIndex} 的请求已确认。", "xpack.transform.deleteTransform.errorWithCheckingIfDataViewExistsNotificationErrorMessage": "检查数据视图 {dataView} 是否存在时发生错误:{error}", "xpack.transform.edit.noDataViewErrorPromptText": "无法获取转换 {transformId} 的数据视图。对于 {dataViewTitle},不存在数据视图。", "xpack.transform.forceDeleteTransformMessage": "删除 {count} {count, plural, other {转换}}", "xpack.transform.managedTransformsWarningCallout": "{count, plural, other {至少一个此类转换}}由 Elastic 预配置;{action} {count, plural, other {这些转换}}可能会影响该产品的其他部分。", "xpack.transform.multiTransformActionsMenu.transformsCount": "已选定 {count} 个{count, plural, other {转换}}", "xpack.transform.stepCreateForm.createDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:", - "xpack.transform.stepCreateForm.createDataViewSuccessMessage": "已成功创建 Kibana 数据视图 {dataViewName}。", "xpack.transform.stepCreateForm.createTransformErrorMessage": "创建转换 {transformId} 时出错:", - "xpack.transform.stepCreateForm.createTransformSuccessMessage": "创建转换 {transformId} 的请求已确认。", "xpack.transform.stepCreateForm.duplicateDataViewErrorMessage": "创建 Kibana 数据视图 {dataViewName} 时发生错误:数据视图已存在。", - "xpack.transform.stepCreateForm.startTransformErrorMessage": "启动转换 {transformId} 时发生错误:", - "xpack.transform.stepCreateForm.startTransformSuccessMessage": "启动转换 {transformId} 的请求已确认。", "xpack.transform.stepDefineForm.invalidKuerySyntaxErrorMessageQueryBar": "无效查询:{queryErrorMessage}", "xpack.transform.stepDefineForm.queryPlaceholderKql": "例如,{example}", "xpack.transform.stepDefineForm.queryPlaceholderLucene": "例如,{example}", @@ -37716,41 +37686,30 @@ "xpack.transform.stepDetailsForm.retentionPolicyMaxAgePlaceholderText": "max_age,例如 {exampleValue}", "xpack.transform.transformForm.sizeNotationPlaceholder": "示例:{example1}、{example2}、{example3}、{example4}", "xpack.transform.transformList.alertingRules.tooltipContent": "转换具有 {rulesCount} 个关联的告警{rulesCount, plural, other { 规则}}", - "xpack.transform.transformList.bulkDeleteDestDataViewSuccessMessage": "已成功删除 {count} 个目标数据{count, plural, other {视图}}。", - "xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage": "已成功删除 {count} 个目标数据{count, plural, other {索引}}。", "xpack.transform.transformList.bulkDeleteModalTitle": "删除 {count} 个 {count, plural, other {转换}}?", - "xpack.transform.transformList.bulkDeleteTransformSuccessMessage": "已成功删除 {count} 个{count, plural, other {转换}}。", "xpack.transform.transformList.bulkReauthorizeModalTitle": "重新授权 {count} 个{count, plural, other {转换}}?", "xpack.transform.transformList.bulkResetModalTitle": "重置 {count} 个{count, plural, other {转换}}?", - "xpack.transform.transformList.bulkResetTransformSuccessMessage": "已成功重置 {count} 个{count, plural, other {转换}}。", "xpack.transform.transformList.bulkStartModalTitle": "启动 {count} 个{count, plural, other {转换}}?", "xpack.transform.transformList.bulkStopModalTitle": "停止 {count} 个{count, plural, other {转换}}?", "xpack.transform.transformList.cannotRestartCompleteBatchTransformToolTip": "{transformId} 为已完成批量转换,无法重新启动。", "xpack.transform.transformList.cannotScheduleNowCompleteBatchTransformToolTip": "{transformId} 为已完成的批量转换,无法安排其立即处理数据。", "xpack.transform.transformList.deleteModalTitle": "删除 {transformId}?", "xpack.transform.transformList.deleteTransformErrorMessage": "删除转换 {transformId} 时发生错误", - "xpack.transform.transformList.deleteTransformSuccessMessage": "删除转换 {transformId} 的请求已确认。", "xpack.transform.transformList.editFlyoutFormPlaceholderText": "默认值:{defaultValue}", "xpack.transform.transformList.editFlyoutTitle": "编辑 {transformId}", - "xpack.transform.transformList.editTransformSuccessMessage": "转换 {transformId} 已更新。", "xpack.transform.transformList.reauthorizeModalTitle": "重新授权 {transformId}?", "xpack.transform.transformList.reauthorizeTransformErrorMessage": "重新授权转换 {transformId} 时出错", - "xpack.transform.transformList.reauthorizeTransformSuccessMessage": "重新授权转换 {transformId} 的请求已确认。", "xpack.transform.transformList.resetModalTitle": "重置 {transformId}?", "xpack.transform.transformList.resetTransformErrorMessage": "重置转换 {transformId} 时出错", - "xpack.transform.transformList.resetTransformSuccessMessage": "重置转换 {transformId} 的请求已确认。", "xpack.transform.transformList.rowCollapse": "隐藏 {transformId} 的详情", "xpack.transform.transformList.rowExpand": "显示 {transformId} 的详情", "xpack.transform.transformList.scheduleNowTransformErrorMessage": "计划转换 {transformId} 以立即处理数据时出错。", - "xpack.transform.transformList.scheduleNowTransformSuccessMessage": "计划转换 {transformId} 以立即处理数据的请求已确认。", "xpack.transform.transformList.startedTransformToolTip": "{transformId} 已启动。", "xpack.transform.transformList.startModalTitle": "启动 {transformId}?", "xpack.transform.transformList.startTransformErrorMessage": "启动转换 {transformId} 时发生错误", - "xpack.transform.transformList.startTransformSuccessMessage": "启动转换 {transformId} 的请求已确认。", "xpack.transform.transformList.stopModalTitle": "停止 {transformId}?", "xpack.transform.transformList.stoppedTransformToolTip": "{transformId} 已停止。", "xpack.transform.transformList.stopTransformErrorMessage": "停止数据帧转换 {transformId} 时发生错误", - "xpack.transform.transformList.stopTransformSuccessMessage": "停止数据帧转换 {transformId} 的请求已确认。", "xpack.transform.transformList.unauthorizedTransformsCallout.insufficientPermissionsMsg": "{unauthorizedCnt, plural, other {已创建 # 个转换,但权限不足。}}", "xpack.transform.transformList.unauthorizedTransformsCallout.reauthorizeMsg": "重新授权以启动{unauthorizedCnt, plural, other {# 个转换}}。", "xpack.transform.transformNodes.noTransformNodesCallOutBody": "您将无法创建或运行转换。{learnMoreLink}", @@ -37796,9 +37755,6 @@ "xpack.transform.alertTypes.transformHealth.notStartedCheckName": "转换未启动", "xpack.transform.alertTypes.transformHealth.testsConfigTransforms.errorMessage": "必须至少选择一次运行状况检查", "xpack.transform.alertTypes.transformHealth.testsSelection.enableTestLabel": "启用", - "xpack.transform.app.checkingPrivilegesDescription": "正在检查权限……", - "xpack.transform.app.checkingPrivilegesErrorMessage": "从服务器获取用户权限时出错", - "xpack.transform.app.deniedPrivilegeTitle": "您缺少集群权限", "xpack.transform.appName": "转换", "xpack.transform.appTitle": "转换", "xpack.transform.capability.noPermission.canCreateTransformAlertsTooltip": "您无权创建转换告警规则。", @@ -37844,7 +37800,6 @@ "xpack.transform.licenseCheckErrorMessage": "许可证检查失败", "xpack.transform.list.emptyPromptButtonText": "创建您的首个转换", "xpack.transform.list.emptyPromptTitle": "找不到转换", - "xpack.transform.list.errorPromptTitle": "获取转换列表时发生错误", "xpack.transform.mode": "模式", "xpack.transform.modeFilter": "模式", "xpack.transform.models.transformService.allOtherRequestsCancelledDescription": "所有其他请求已取消。", @@ -38076,7 +38031,6 @@ "xpack.transform.transformList.editFlyoutUpdateButtonText": "更新", "xpack.transform.transformList.editManagedTransformsDescription": "正在编辑", "xpack.transform.transformList.editTransformGenericErrorMessage": "调用用于更新转换的 API 终端时发生错误。", - "xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage": "检查用户是否可以删除目标索引时发生错误", "xpack.transform.transformList.managedBadgeLabel": "托管", "xpack.transform.transformList.managedBadgeTooltip": "此转换由 Elastic 预配置和管理;该产品的其他部分可能依赖于其行为。", "xpack.transform.transformList.needsReauthorizationBadge.contactAdminTooltip": "请联系管理员请求所需权限。", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_data_grid.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_data_grid.tsx index 43199b924ba2d..08c9a45358f3e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_data_grid.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_data_grid.tsx @@ -66,6 +66,7 @@ export interface EventLogDataGrid { onFlyoutOpen?: (runLog: IExecutionLog) => void; setVisibleColumns: (visibleColumns: string[]) => void; setSortingColumns: (sortingColumns: EuiDataGridSorting['columns']) => void; + getRuleDetailsRoute?: (ruleId: string) => string; } export const numTriggeredActionsDisplay = i18n.translate( @@ -167,6 +168,7 @@ export const EventLogDataGrid = (props: EventLogDataGrid) => { onChangeItemsPerPage, onChangePage, onFlyoutOpen, + getRuleDetailsRoute, } = props; const { euiTheme } = useEuiTheme(); @@ -343,6 +345,7 @@ export const EventLogDataGrid = (props: EventLogDataGrid) => { ruleId={ruleId} spaceIds={spaceIds} useExecutionStatus={isRuleUsingExecutionStatus} + getRuleDetailsRoute={getRuleDetailsRoute} />
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_list_cell_renderer.tsx index f11c38a9dfe11..a35e963b6ce11 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/event_log/event_log_list_cell_renderer.tsx @@ -10,7 +10,7 @@ import moment from 'moment'; import { EuiLink } from '@elastic/eui'; import { RuleAlertingOutcome } from '@kbn/alerting-plugin/common'; import { useHistory } from 'react-router-dom'; -import { getRuleDetailsRoute } from '@kbn/rule-data-utils'; +import { getRuleDetailsRoute as internalGetRuleDetailsRoute } from '@kbn/rule-data-utils'; import { formatRuleAlertCount } from '../../../../../common/lib/format_rule_alert_count'; import { useKibana, useSpacesData } from '../../../../../common/lib/kibana'; import { EventLogListStatus } from './event_log_list_status'; @@ -36,6 +36,7 @@ interface EventLogListCellRendererProps { ruleId?: string; spaceIds?: string[]; useExecutionStatus?: boolean; + getRuleDetailsRoute?: (ruleId: string) => string; } export const EventLogListCellRenderer = (props: EventLogListCellRendererProps) => { @@ -47,6 +48,7 @@ export const EventLogListCellRenderer = (props: EventLogListCellRendererProps) = ruleId, spaceIds, useExecutionStatus = true, + getRuleDetailsRoute, } = props; const spacesData = useSpacesData(); const { http } = useKibana().services; @@ -66,7 +68,9 @@ export const EventLogListCellRenderer = (props: EventLogListCellRendererProps) = const ruleNamePathname = useMemo(() => { if (!ruleId) return ''; - const ruleRoute = getRuleDetailsRoute(ruleId); + const ruleRoute = getRuleDetailsRoute + ? getRuleDetailsRoute(ruleId) + : internalGetRuleDetailsRoute(ruleId); if (ruleOnDifferentSpace) { const [linkedSpaceId] = spaceIds ?? []; @@ -82,7 +86,7 @@ export const EventLogListCellRenderer = (props: EventLogListCellRendererProps) = return newPathname; } return ruleRoute; - }, [ruleId, ruleOnDifferentSpace, history, activeSpace, http, spaceIds]); + }, [ruleId, ruleOnDifferentSpace, history, activeSpace, http, spaceIds, getRuleDetailsRoute]); const onClickRuleName = useCallback(() => { if (!ruleId) return; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/global_rule_event_log_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/global_rule_event_log_list.tsx index bb939e3e26180..c7d7f442beab1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/global_rule_event_log_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/global_rule_event_log_list.tsx @@ -16,6 +16,7 @@ export interface GlobalRuleEventLogListProps { setHeaderActions?: RuleEventLogListCommonProps['setHeaderActions']; localStorageKey?: RuleEventLogListCommonProps['localStorageKey']; filteredRuleTypes?: RuleEventLogListCommonProps['filteredRuleTypes']; + getRuleDetailsRoute?: RuleEventLogListCommonProps['getRuleDetailsRoute']; } const GLOBAL_EVENT_LOG_LIST_STORAGE_KEY = @@ -31,7 +32,7 @@ const REFRESH_TOKEN = { }; export const GlobalRuleEventLogList = (props: GlobalRuleEventLogListProps) => { - const { setHeaderActions, localStorageKey, filteredRuleTypes } = props; + const { setHeaderActions, localStorageKey, filteredRuleTypes, getRuleDetailsRoute } = props; const { spaces } = useKibana().services; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -51,6 +52,7 @@ export const GlobalRuleEventLogList = (props: GlobalRuleEventLogListProps) => { localStorageKey={localStorageKey || GLOBAL_EVENT_LOG_LIST_STORAGE_KEY} filteredRuleTypes={filteredRuleTypes} setHeaderActions={setHeaderActions} + getRuleDetailsRoute={getRuleDetailsRoute} /> ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx index 32db0a686bff5..73eb9f2c5c536 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx @@ -95,6 +95,7 @@ export interface RuleEventLogListCommonProps { hasAllSpaceSwitch?: boolean; filteredRuleTypes?: string[]; setHeaderActions?: (components?: React.ReactNode[]) => void; + getRuleDetailsRoute?: (ruleId: string) => string; } export type RuleEventLogListTableProps = @@ -116,6 +117,7 @@ export const RuleEventLogListTable = ( hasAllSpaceSwitch = false, setHeaderActions, filteredRuleTypes, + getRuleDetailsRoute, } = props; const { uiSettings, notifications } = useKibana().services; @@ -629,6 +631,7 @@ export const RuleEventLogListTable = ( onFlyoutOpen={onFlyoutOpen} setVisibleColumns={setVisibleColumns} setSortingColumns={setSortingColumns} + getRuleDetailsRoute={getRuleDetailsRoute} /> ); @@ -668,7 +671,7 @@ export const RuleEventLogListTable = ( - + { return ( - ; + ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/get_rule_event_log_list.tsx b/x-pack/plugins/triggers_actions_ui/public/common/get_rule_event_log_list.tsx index 1d2e2cf580411..168f3b6d7ad38 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/get_rule_event_log_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/get_rule_event_log_list.tsx @@ -20,7 +20,7 @@ export const getRuleEventLogListLazy = { + // FLAKY: https://github.com/elastic/kibana/issues/140973 + describe.skip('telemetry', () => { const objectRemover = new ObjectRemover(supertest); const alwaysFiringRuleId: { [key: string]: string } = {}; diff --git a/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts b/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts index e34caa20fcdbc..179ac28a0c939 100644 --- a/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts +++ b/x-pack/test/api_integration/apis/synthetics/sync_global_params.ts @@ -23,6 +23,7 @@ import { comparePolicies, getTestSyntheticsPolicy } from './sample_data/test_pol export default function ({ getService }: FtrProviderContext) { // FLAKY: https://github.com/elastic/kibana/issues/162594 + // Failing: See https://github.com/elastic/kibana/issues/162594 describe.skip('SyncGlobalParams', function () { this.tags('skipCloud'); const supertestAPI = getService('supertest'); diff --git a/x-pack/test/api_integration/apis/transform/stop_transforms.ts b/x-pack/test/api_integration/apis/transform/stop_transforms.ts index 7811432e7417a..c982c6b45f1c9 100644 --- a/x-pack/test/api_integration/apis/transform/stop_transforms.ts +++ b/x-pack/test/api_integration/apis/transform/stop_transforms.ts @@ -9,7 +9,6 @@ import expect from '@kbn/expect'; import type { PutTransformsRequestSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; import type { StopTransformsRequestSchema } from '@kbn/transform-plugin/common/api_schemas/stop_transforms'; -import { isStopTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { TRANSFORM_STATE } from '@kbn/transform-plugin/common/constants'; @@ -76,7 +75,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); expect(body[transformId].success).to.eql(true); expect(typeof body[transformId].error).to.eql('undefined'); await transform.api.waitForTransformState(transformId, TRANSFORM_STATE.STOPPED); @@ -97,7 +95,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); expect(body[transformId].success).to.eql(false); expect(typeof body[transformId].error).to.eql('object'); @@ -121,7 +118,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); expect(body.invalid_transform_id.success).to.eql(false); expect(body.invalid_transform_id).to.have.property('error'); }); @@ -158,8 +154,6 @@ export default ({ getService }: FtrProviderContext) => { .send(reqBody); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); - await asyncForEach(reqBody, async ({ id: transformId }: { id: string }, idx: number) => { expect(body[transformId].success).to.eql(true); await transform.api.waitForTransformState(transformId, TRANSFORM_STATE.STOPPED); @@ -183,8 +177,6 @@ export default ({ getService }: FtrProviderContext) => { ]); transform.api.assertResponseStatusCode(200, status, body); - expect(isStopTransformsResponseSchema(body)).to.eql(true); - await asyncForEach(reqBody, async ({ id: transformId }: { id: string }, idx: number) => { expect(body[transformId].success).to.eql(true); await transform.api.waitForTransformState(transformId, TRANSFORM_STATE.STOPPED); diff --git a/x-pack/test/api_integration/apis/transform/transforms.ts b/x-pack/test/api_integration/apis/transform/transforms.ts index 4c3d1641d6d5f..2016876ba93a6 100644 --- a/x-pack/test/api_integration/apis/transform/transforms.ts +++ b/x-pack/test/api_integration/apis/transform/transforms.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import type { GetTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; -import { isGetTransformsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; import { USER } from '../../../functional/services/transform/security_common'; @@ -43,8 +42,6 @@ export default ({ getService }: FtrProviderContext) => { } function assertTransformsResponseBody(body: GetTransformsResponseSchema) { - expect(isGetTransformsResponseSchema(body)).to.eql(true); - expect(body.count).to.eql(expected.apiTransformTransforms.count); expect(body.transforms).to.have.length(expected.apiTransformTransforms.count); @@ -62,8 +59,6 @@ export default ({ getService }: FtrProviderContext) => { } function assertSingleTransformResponseBody(body: GetTransformsResponseSchema) { - expect(isGetTransformsResponseSchema(body)).to.eql(true); - expect(body.count).to.eql(expected.apiTransformTransformsTransformId.count); expect(body.transforms).to.have.length(expected.apiTransformTransformsTransformId.count); diff --git a/x-pack/test/api_integration/apis/transform/transforms_nodes.ts b/x-pack/test/api_integration/apis/transform/transforms_nodes.ts index bf3e91df69684..10f4413a8f85f 100644 --- a/x-pack/test/api_integration/apis/transform/transforms_nodes.ts +++ b/x-pack/test/api_integration/apis/transform/transforms_nodes.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import type { GetTransformNodesResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms'; -import { isGetTransformNodesResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; import { USER } from '../../../functional/services/transform/security_common'; @@ -25,8 +24,6 @@ export default ({ getService }: FtrProviderContext) => { }; function assertTransformsNodesResponseBody(body: GetTransformNodesResponseSchema) { - expect(isGetTransformNodesResponseSchema(body)).to.eql(true); - expect(body.count).to.not.be.lessThan(expected.apiTransformTransformsNodes.minCount); } diff --git a/x-pack/test/api_integration/apis/transform/transforms_stats.ts b/x-pack/test/api_integration/apis/transform/transforms_stats.ts index 41cdafd0c058f..aea5c049343e9 100644 --- a/x-pack/test/api_integration/apis/transform/transforms_stats.ts +++ b/x-pack/test/api_integration/apis/transform/transforms_stats.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import type { GetTransformsStatsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/transforms_stats'; -import { isGetTransformsStatsResponseSchema } from '@kbn/transform-plugin/common/api_schemas/type_guards'; import { TRANSFORM_STATE } from '@kbn/transform-plugin/common/constants'; import { getCommonRequestHeader } from '../../../functional/services/ml/common_api'; @@ -39,7 +38,6 @@ export default ({ getService }: FtrProviderContext) => { } function assertTransformsStatsResponseBody(body: GetTransformsStatsResponseSchema) { - expect(isGetTransformsStatsResponseSchema(body)).to.eql(true); expect(body.count).to.eql(expected.apiTransformTransforms.count); expect(body.transforms).to.have.length(expected.apiTransformTransforms.count); diff --git a/x-pack/test/apm_api_integration/tests/sourcemaps/sourcemaps.ts b/x-pack/test/apm_api_integration/tests/sourcemaps/sourcemaps.ts index 769041847bb3f..2b02096f57d39 100644 --- a/x-pack/test/apm_api_integration/tests/sourcemaps/sourcemaps.ts +++ b/x-pack/test/apm_api_integration/tests/sourcemaps/sourcemaps.ts @@ -27,16 +27,6 @@ const SAMPLE_SOURCEMAP = { mappings: 'A,AAAB;;ABCDE;', }; -const SAMPLE_ANDROID_MAP = `# compiler: R8 -# compiler_version: 3.2.47 -# min_api: 26 -# common_typos_disable -# {"id":"com.android.tools.r8.mapping","version":"2.0"} -# pg_map_id: 127b14c -# pg_map_hash: SHA-256 127b14c0be5dd1b55beee544a8d0e7c9414b432868ed8bc54ca5cc43cba12435 -a1.TableInfo$ForeignKey$$ExternalSyntheticOutline0 -> a1.e: -# {"id":"sourceFile","fileName":"R8$$SyntheticClass"}`; - export default function ApiTest({ getService }: FtrProviderContext) { const registry = getService('registry'); const apmApiClient = getService('apmApiClient'); @@ -109,28 +99,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { return response.body; } - async function uploadAndroidMap({ - serviceName, - serviceVersion, - androidMap, - }: { - serviceName: string; - serviceVersion: string; - androidMap: string; - }) { - const response = await apmApiClient.writeUser({ - endpoint: 'POST /api/apm/androidmaps 2023-10-31', - type: 'form-data', - params: { - body: { - service_name: serviceName, - service_version: serviceVersion, - map_file: androidMap, - }, - }, - }); - return response.body; - } async function runSourceMapMigration() { await apmApiClient.writeUser({ endpoint: 'POST /internal/apm/sourcemaps/migrate_fleet_artifacts', @@ -160,12 +128,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { await Promise.all([deleteAllFleetSourceMaps(), deleteAllApmSourceMaps()]); }); - async function getDecodedMapContent(encodedContent?: string): Promise { - if (encodedContent) { - return (await unzip(Buffer.from(encodedContent, 'base64'))).toString(); - } - } - async function getDecodedSourceMapContent( encodedContent?: string ): Promise { @@ -281,111 +243,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - let androidResp: APIReturnType<'POST /api/apm/androidmaps 2023-10-31'>; - describe('upload android map', () => { - after(async () => { - await apmApiClient.writeUser({ - endpoint: 'DELETE /api/apm/sourcemaps/{id} 2023-10-31', - params: { path: { id: androidResp.id } }, - }); - }); - - before(async () => { - androidResp = await uploadAndroidMap({ - serviceName: 'uploading-test', - serviceVersion: '1.0.0', - androidMap: SAMPLE_ANDROID_MAP, - }); - - await waitForSourceMapCount(1); - }); - - it('is uploaded as a fleet artifact', async () => { - const res = await es.search({ - index: '.fleet-artifacts', - size: 1, - query: { - bool: { - filter: [{ term: { type: 'sourcemap' } }, { term: { package_name: 'apm' } }], - }, - }, - }); - - // @ts-expect-error - expect(res.hits.hits[0]._source.identifier).to.be('uploading-test-1.0.0-android'); - }); - - it('is added to .apm-source-map index', async () => { - const res = await es.search({ - index: '.apm-source-map', - }); - - const source = res.hits.hits[0]._source; - const decodedSourceMap = await getDecodedMapContent(source?.content); - expect(decodedSourceMap).to.eql(SAMPLE_ANDROID_MAP); - expect(source?.content_sha256).to.be( - '702e07279b0fbed47fdbf5e71528dff845b4f07a16ca79cab0c1b06eb71be966' - ); - expect(source?.file.path).to.be('android'); - expect(source?.service.name).to.be('uploading-test'); - expect(source?.service.version).to.be('1.0.0'); - }); - - describe('when uploading a new android map with the same service.name and service.version', () => { - let resBefore: GetResponse; - let resAfter: GetResponse; - - before(async () => { - async function getSourceMapDocFromApmIndex() { - await es.indices.refresh({ index: '.apm-source-map' }); - return await es.get({ - index: '.apm-source-map', - id: 'uploading-test-1.0.0-android', - }); - } - - resBefore = await getSourceMapDocFromApmIndex(); - - await uploadAndroidMap({ - serviceName: 'uploading-test', - serviceVersion: '1.0.0', - androidMap: '# compiler: R8\n# ANOTHER MAP', - }); - - resAfter = await getSourceMapDocFromApmIndex(); - }); - - after(async () => { - await deleteAllApmSourceMaps(); - await deleteAllFleetSourceMaps(); - }); - - it('creates one document in the .apm-source-map index', async () => { - const res = await es.search({ index: '.apm-source-map', size: 0 }); - - // @ts-expect-error - expect(res.hits.total.value).to.be(1); - }); - - it('creates two documents in the .fleet-artifacts index', async () => { - const res = await listSourcemaps({ page: 1, perPage: 10 }); - expect(res.total).to.be(2); - }); - - it('updates the content', async () => { - const contentBefore = await getDecodedMapContent(resBefore._source?.content); - const contentAfter = await getDecodedMapContent(resAfter._source?.content); - - expect(contentBefore).to.be(SAMPLE_ANDROID_MAP); - expect(contentAfter).to.be('# compiler: R8\n# ANOTHER MAP'); - }); - - it('updates the content hash', async () => { - expect(resBefore._source?.content_sha256).to.not.be(resAfter._source?.content_sha256); - }); - }); - }); - describe('list source maps', async () => { before(async () => { const totalCount = 6; diff --git a/x-pack/test/functional/apps/dashboard/group2/_async_dashboard.ts b/x-pack/test/functional/apps/dashboard/group2/_async_dashboard.ts index 80354eda9eefd..bf76152a459c4 100644 --- a/x-pack/test/functional/apps/dashboard/group2/_async_dashboard.ts +++ b/x-pack/test/functional/apps/dashboard/group2/_async_dashboard.ts @@ -128,7 +128,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should launch sample flights data set dashboard', async () => { - await appMenu.clickLink('Dashboard'); + await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.loadSavedDashboard('[Flights] Global Flight Dashboard'); await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.timePicker.setCommonlyUsedTime('sample_data range'); @@ -144,7 +144,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); - await appMenu.clickLink('Dashboard'); + await appMenu.clickLink('Dashboard', { + category: 'recentlyViewed', + closeCollapsibleNav: true, + }); await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); log.debug('Checking charts rendered'); @@ -157,7 +160,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); - await appMenu.clickLink('Dashboard'); + await appMenu.clickLink('Dashboard', { + category: 'recentlyViewed', + closeCollapsibleNav: true, + }); await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); log.debug('Checking charts rendered'); @@ -170,7 +176,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const hitCount = parseInt(await PageObjects.discover.getHitCount(), 10); expect(hitCount).to.be.greaterThan(0); }); - await appMenu.clickLink('Dashboard'); + await appMenu.clickLink('Dashboard', { + category: 'recentlyViewed', + closeCollapsibleNav: true, + }); await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); log.debug('Checking charts rendered'); diff --git a/x-pack/test/functional/apps/dashboard/group2/dashboard_maps_by_value.ts b/x-pack/test/functional/apps/dashboard/group2/dashboard_maps_by_value.ts index d9a0062298eec..5503d1a08dc4e 100644 --- a/x-pack/test/functional/apps/dashboard/group2/dashboard_maps_by_value.ts +++ b/x-pack/test/functional/apps/dashboard/group2/dashboard_maps_by_value.ts @@ -60,7 +60,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); if (!saveToDashboard) { - await appsMenu.clickLink('Dashboard'); + await appsMenu.clickLink('Dashboard', { + category: 'kibana', + closeCollapsibleNav: true, + }); } } else { await PageObjects.maps.clickSaveAndReturnButton(); diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts index 75fa7feb02057..173869a85465f 100644 --- a/x-pack/test/functional/apps/discover/reporting.ts +++ b/x-pack/test/functional/apps/discover/reporting.ts @@ -29,6 +29,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }; const getReport = async () => { + // close any open notification toasts + await PageObjects.reporting.clearToastNotifications(); + await PageObjects.reporting.openCsvReportingPanel(); await PageObjects.reporting.clickGenerateReportButton(); diff --git a/x-pack/test/functional/apps/discover/saved_searches.ts b/x-pack/test/functional/apps/discover/saved_searches.ts index 76b380274f207..8b6f830a11406 100644 --- a/x-pack/test/functional/apps/discover/saved_searches.ts +++ b/x-pack/test/functional/apps/discover/saved_searches.ts @@ -45,7 +45,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.common.unsetTime(); }); - describe('Customize time range', () => { + // FLAKY: https://github.com/elastic/kibana/issues/104578 + describe.skip('Customize time range', () => { it('should be possible to customize time range for saved searches on dashboards', async () => { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.clickNewDashboard(); diff --git a/x-pack/test/functional/apps/discover/visualize_field.ts b/x-pack/test/functional/apps/discover/visualize_field.ts index 32cd9b5360da0..a61a2abba1870 100644 --- a/x-pack/test/functional/apps/discover/visualize_field.ts +++ b/x-pack/test/functional/apps/discover/visualize_field.ts @@ -33,7 +33,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const monacoEditor = getService('monacoEditor'); const defaultSettings = { - 'discover:enableSql': true, + 'discover:enableESQL': true, }; async function setDiscoverTimeRange() { @@ -144,15 +144,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('should visualize correctly text based language queries in Discover', async () => { - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await monacoEditor.setCodeEditorValue( - 'SELECT extension, AVG("bytes") as average FROM "logstash-*" GROUP BY extension' + 'from logstash-* | stats averageB = avg(bytes) by extension' ); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); expect(await testSubjects.exists('unifiedHistogramChart')).to.be(true); - expect(await testSubjects.exists('heatmapChart')).to.be(true); + expect(await testSubjects.exists('xyVisChart')).to.be(true); await PageObjects.discover.chooseLensChart('Donut'); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -161,10 +161,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('should allow changing dimensions', async () => { await elasticChart.setNewChartUiDebugFlag(true); - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await monacoEditor.setCodeEditorValue( - 'SELECT extension, AVG("bytes") as average FROM "logstash-*" GROUP BY extension' + 'from logstash-* | stats averageB = avg(bytes) by extension' ); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -186,11 +186,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { assertMatchesExpectedData(data!); }); - it('should visualize correctly text based language queries in Lenss', async () => { - await PageObjects.discover.selectTextBaseLang('SQL'); + it('should visualize correctly text based language queries in Lens', async () => { + await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await monacoEditor.setCodeEditorValue( - 'SELECT extension, AVG("bytes") as average FROM "logstash-*" GROUP BY extension' + 'from logstash-* | stats averageB = avg(bytes) by extension' ); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -201,15 +201,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await retry.waitFor('lens flyout', async () => { const dimensions = await testSubjects.findAll('lns-dimensionTrigger-textBased'); - return dimensions.length === 2 && (await dimensions[1].getVisibleText()) === 'average'; + return dimensions.length === 2 && (await dimensions[1].getVisibleText()) === 'averageB'; }); }); it('should visualize correctly text based language queries based on index patterns', async () => { - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await monacoEditor.setCodeEditorValue( - 'SELECT extension, AVG("bytes") as average FROM "logstash*" GROUP BY extension' + 'from logstash* | stats averageB = avg(bytes) by extension' ); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); @@ -220,15 +220,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await retry.waitFor('lens flyout', async () => { const dimensions = await testSubjects.findAll('lns-dimensionTrigger-textBased'); - return dimensions.length === 2 && (await dimensions[1].getVisibleText()) === 'average'; + return dimensions.length === 2 && (await dimensions[1].getVisibleText()) === 'averageB'; }); }); it('should save and edit chart in the dashboard on the fly', async () => { - await PageObjects.discover.selectTextBaseLang('SQL'); + await PageObjects.discover.selectTextBaseLang(); await PageObjects.header.waitUntilLoadingHasFinished(); await monacoEditor.setCodeEditorValue( - 'SELECT extension, AVG("bytes") as average FROM "logstash*" GROUP BY extension' + 'from logstash-* | stats averageB = avg(bytes) by extension' ); await testSubjects.click('querySubmitButton'); await PageObjects.header.waitUntilLoadingHasFinished(); diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 8ea0ad09a50f0..3d24a4d134c2a 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -56,8 +56,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/164164 - describe.skip('with metrics present', () => { + describe('with metrics present', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); await pageObjects.common.navigateToApp('infraOps'); diff --git a/x-pack/test/functional/apps/infra/node_details.ts b/x-pack/test/functional/apps/infra/node_details.ts index 576de71f0a55b..7ff494d4cb584 100644 --- a/x-pack/test/functional/apps/infra/node_details.ts +++ b/x-pack/test/functional/apps/infra/node_details.ts @@ -233,6 +233,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Processes Tab', () => { before(async () => { await pageObjects.assetDetails.clickProcessesTab(); + await pageObjects.header.waitUntilLoadingHasFinished(); }); it('should render processes tab and with Total Value summary', async () => { 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 34bcec45e7aa6..b4e8839ba89e2 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -43,7 +43,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide throw new Error(); } }); - return await testSubjects.find('waffleMap'); + return testSubjects.find('waffleMap'); }, async getWaffleMapTooltips() { @@ -84,7 +84,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide const color = await nodeValue.getAttribute('color'); return { name, value: parseFloat(value), color }; }); - return await Promise.all(promises); + return Promise.all(promises); }, async sortNodesBy(sort: string) { @@ -171,34 +171,31 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide return timelineSelectorsVisible.every((visible) => !visible); }, - async openInventorySwitcher() { - await testSubjects.click('openInventorySwitcher'); - return await testSubjects.find('goToHost1'); - }, - async toggleInventorySwitcher() { await testSubjects.click('openInventorySwitcher'); await testSubjects.find('goToHost'); await testSubjects.click('openInventorySwitcher'); - return await testSubjects.missingOrFail('goToHost'); + retry.tryForTime(2 * 1000, async () => { + return testSubjects.missingOrFail('goToHost'); + }); }, async goToHost() { await testSubjects.click('openInventorySwitcher'); await testSubjects.find('goToHost'); - return await testSubjects.click('goToHost'); + return testSubjects.click('goToHost'); }, async goToPods() { await testSubjects.click('openInventorySwitcher'); await testSubjects.find('goToHost'); - return await testSubjects.click('goToPods'); + return testSubjects.click('goToPods'); }, async goToDocker() { await testSubjects.click('openInventorySwitcher'); await testSubjects.find('goToHost'); - return await testSubjects.click('goToDocker'); + return testSubjects.click('goToDocker'); }, async goToSettings() { @@ -238,23 +235,23 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide }, async getSaveViewButton() { - return await testSubjects.find('openSaveViewModal'); + return testSubjects.find('openSaveViewModal'); }, async getLoadViewsButton() { - return await testSubjects.find('loadViews'); + return testSubjects.find('loadViews'); }, async openSaveViewsFlyout() { - return await testSubjects.click('loadViews'); + return testSubjects.click('loadViews'); }, async closeSavedViewFlyout() { - return await testSubjects.click('cancelSavedViewModal'); + return testSubjects.click('cancelSavedViewModal'); }, async openCreateSaveViewModal() { - return await testSubjects.click('openSaveViewModal'); + return testSubjects.click('openSaveViewModal'); }, async openEnterViewNameAndSave() { @@ -263,23 +260,23 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide }, async getNoMetricsIndicesPrompt() { - return await testSubjects.find('noDataPage'); + return testSubjects.find('noDataPage'); }, async getNoMetricsDataPrompt() { - return await testSubjects.find('noMetricsDataPrompt'); + return testSubjects.find('noMetricsDataPrompt'); }, async getNoRemoteClusterPrompt() { - return await testSubjects.find('infraHostsNoRemoteCluster'); + return testSubjects.find('infraHostsNoRemoteCluster'); }, async getInfraMissingMetricsIndicesCallout() { - return await testSubjects.find('infraIndicesPanelSettingsWarningCallout'); + return testSubjects.find('infraIndicesPanelSettingsWarningCallout'); }, async getInfraMissingRemoteClusterIndicesCallout() { - return await testSubjects.find('infraIndicesPanelSettingsDangerCallout'); + return testSubjects.find('infraIndicesPanelSettingsDangerCallout'); }, async openSourceConfigurationFlyout() { @@ -436,7 +433,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide }, async clickDismissKubernetesTourButton() { - return await testSubjects.click('infra-kubernetesTour-dismiss'); + return testSubjects.click('infra-kubernetesTour-dismiss'); }, }; } diff --git a/x-pack/test/functional/services/observability/alerts/common.ts b/x-pack/test/functional/services/observability/alerts/common.ts index 5986de63a2d74..57403ef8c3ab3 100644 --- a/x-pack/test/functional/services/observability/alerts/common.ts +++ b/x-pack/test/functional/services/observability/alerts/common.ts @@ -57,6 +57,15 @@ export function ObservabilityAlertsCommonProvider({ ); }; + const navigateToRulesLogsPage = async () => { + return await pageObjects.common.navigateToUrlWithBrowserHistory( + 'observability', + '/alerts/rules/logs', + '', + { ensureCurrentUrl: false } + ); + }; + const navigateToAlertDetails = async (alertId: string) => { return await pageObjects.common.navigateToUrlWithBrowserHistory( 'observability', @@ -338,6 +347,7 @@ export function ObservabilityAlertsCommonProvider({ getAlertsFlyoutViewRuleDetailsLinkOrFail, getRuleStatValue, navigateToRulesPage, + navigateToRulesLogsPage, navigateToRuleDetailsByRuleId, navigateToAlertDetails, }; diff --git a/x-pack/test/functional/services/observability/alerts/rules_page.ts b/x-pack/test/functional/services/observability/alerts/rules_page.ts index ff8e21c943725..226d257ed918b 100644 --- a/x-pack/test/functional/services/observability/alerts/rules_page.ts +++ b/x-pack/test/functional/services/observability/alerts/rules_page.ts @@ -8,6 +8,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); + const find = getService('find'); const getManageRulesPageHref = async () => { const manageRulesPageButton = await testSubjects.find('manageRulesPageButton'); @@ -23,10 +24,18 @@ export function ObservabilityAlertsRulesProvider({ getService }: FtrProviderCont const clickDisableFromDropDownMenu = async () => testSubjects.click('statusDropdownDisabledItem'); + const clickLogsTab = async () => testSubjects.click('ruleLogsTab'); + + const clickOnRuleInEventLogs = async () => { + await find.clickByButtonText('metric-threshold'); + }; + return { getManageRulesPageHref, clickCreateRuleButton, clickRuleStatusDropDownMenu, clickDisableFromDropDownMenu, + clickLogsTab, + clickOnRuleInEventLogs, }; } diff --git a/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts b/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts index 42c4a0bd6d1c3..7f8711fba0ab1 100644 --- a/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts +++ b/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts @@ -163,6 +163,17 @@ export default ({ getService }: FtrProviderContext) => { return true; }); }); + + it('should navigate to the details page when clicking on a rule in event logs tab', async () => { + await observability.alerts.rulesPage.clickLogsTab(); + await observability.alerts.rulesPage.clickOnRuleInEventLogs(); + await testSubjects.existOrFail('ruleDetails'); + }); + + it('shows the rule event log when navigating by URL', async () => { + await observability.alerts.common.navigateToRulesLogsPage(); + await testSubjects.existOrFail('ruleEventLogListTable'); + }); }); describe('User permissions', () => { diff --git a/x-pack/test/scalability/apis/api.status.json b/x-pack/test/scalability/apis/api.status.json new file mode 100644 index 0000000000000..396d9d0645fc3 --- /dev/null +++ b/x-pack/test/scalability/apis/api.status.json @@ -0,0 +1,48 @@ +{ + "journeyName": "POST /api/status", + "scalabilitySetup": { + "responseTimeThreshold": { + "threshold1": 1000, + "threshold2": 3000, + "threshold3": 5000 + }, + "warmup": [ + { + "action": "constantUsersPerSec", + "userCount": 10, + "duration": "30s" + } + ], + "test": [ + { + "action": "rampUsersPerSec", + "minUsersCount": 10, + "maxUsersCount": 700, + "duration": "138s" + } + ], + "maxDuration": "6m" + }, + "testData": { + "esArchives": [], + "kbnArchives": [] + }, + "streams": [ + { + "requests": [ + { + "http": { + "method": "GET", + "path": "/api/status", + "headers": { + "Cookie": "", + "Accept-Encoding": "gzip, deflate, br", + "Content-Type": "application/json; charset=utf-8" + }, + "statusCode": 200 + } + } + ] + } + ] +} diff --git a/x-pack/test/scalability/apis/api.status.no_auth.json b/x-pack/test/scalability/apis/api.status.no_auth.json new file mode 100644 index 0000000000000..2fe293f072a25 --- /dev/null +++ b/x-pack/test/scalability/apis/api.status.no_auth.json @@ -0,0 +1,47 @@ +{ + "journeyName": "POST /api/status", + "scalabilitySetup": { + "responseTimeThreshold": { + "threshold1": 1000, + "threshold2": 3000, + "threshold3": 5000 + }, + "warmup": [ + { + "action": "constantUsersPerSec", + "userCount": 10, + "duration": "30s" + } + ], + "test": [ + { + "action": "rampUsersPerSec", + "minUsersCount": 10, + "maxUsersCount": 1210, + "duration": "80s" + } + ], + "maxDuration": "4m" + }, + "testData": { + "esArchives": [], + "kbnArchives": [] + }, + "streams": [ + { + "requests": [ + { + "http": { + "method": "GET", + "path": "/api/status", + "headers": { + "Accept-Encoding": "gzip", + "Content-Type": "application/json; charset=utf-8" + }, + "statusCode": 200 + } + } + ] + } + ] +} diff --git a/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts b/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts index ddbd07ef0c10e..9dc632931d301 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts @@ -35,7 +35,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'x-pack/test/functional/fixtures/kbn_archiver/discover/default' ); await kibanaServer.uiSettings.replace({ - 'discover:enableSql': true, + 'discover:enableESQL': true, }); await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setDefaultAbsoluteRange(); @@ -131,6 +131,19 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(searchesCountBeforeRestore).to.be(searchesCountAfterRestore); // no new searches started during restore }); + + it('should should clean the search session when navigating to ESQL mode, and reinitialize when navigating back', async () => { + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setDefaultAbsoluteRange(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await searchSessions.exists()).to.be(true); + await PageObjects.discover.selectTextBaseLang(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await searchSessions.missingOrFail(); + await browser.goBack(); + await PageObjects.header.waitUntilLoadingHasFinished(); + expect(await searchSessions.exists()).to.be(true); + }); }); async function getSearchSessionId(): Promise { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts index 2d543bcfd35fc..f5aaef1b4e841 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/related_integrations/related_integrations.cy.ts @@ -189,7 +189,9 @@ describe('Related integrations', { tags: ['@ess', '@brokenInServerless'] }, () = }); }); - describe('rule details', () => { + // Flaky in serverless tests + // @brokenInServerless tag is not working so a skip was needed + describe.skip('rule details', { tags: ['@brokenInServerless'] }, () => { beforeEach(() => { visitFirstInstalledPrebuiltRuleDetailsPage(); }); @@ -221,14 +223,29 @@ describe('Related integrations', { tags: ['@ess', '@brokenInServerless'] }, () = openTable(); filterBy(RELATED_INTEGRATION_FIELD); - RULE_RELATED_INTEGRATIONS.forEach((integration) => { - cy.contains( - FIELD(RELATED_INTEGRATION_FIELD), - `{"package":"${integration.package}"${ - integration.integration ? `,"integration":"${integration.integration}"` : '' - },"version":"${integration.version}"}` - ); - }); + cy.get(FIELD(RELATED_INTEGRATION_FIELD)) + .invoke('text') + .then((stringValue) => { + // Integrations are displayed in the flyout as a string with a format like so: + // '{"package":"aws","version":"1.17.0","integration":"unknown"}{"package":"mock","version":"1.1.0"}{"package":"system","version":"1.17.0"}' + // We need to parse it to an array of valid objects before we can compare it to the expected value + // Otherwise, the test might fail because of the order of the properties in the objects in the string + const jsonStringArray = stringValue.split('}{'); + + const validJsonStringArray = createValidJsonStringArray(jsonStringArray); + + const parsedIntegrations = validJsonStringArray.map((jsonString) => + JSON.parse(jsonString) + ); + + RULE_RELATED_INTEGRATIONS.forEach((integration) => { + expect(parsedIntegrations).to.deep.include({ + package: integration.package, + version: integration.version, + ...(integration.integration ? { integration: integration.integration } : {}), + }); + }); + }); }); }); }); @@ -407,3 +424,14 @@ const AWS_PACKAGE_POLICY: PackagePolicyWithoutAgentPolicyId = { }, }, }; + +const createValidJsonStringArray = (jsonStringArray: string[]) => + jsonStringArray.map((jsonString, index) => { + if (index === 0) { + return `${jsonString}}`; + } else if (index === jsonStringArray.length - 1) { + return `{${jsonString}`; + } else { + return `{${jsonString}}`; + } + }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts index 447f399c24a20..b95741083a065 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/bulk_actions/bulk_duplicate_rules.cy.ts @@ -52,83 +52,88 @@ const EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item'; const NON_EXPIRED_EXCEPTION_ITEM_NAME = 'Sample exception item with future expiration'; -describe('Detection rules, bulk duplicate', { tags: ['@ess', '@serverless'] }, () => { - before(() => { - cleanKibana(); - }); - - beforeEach(() => { - login(); - // Make sure persisted rules table state is cleared - resetRulesTableState(); - deleteAlertsAndRules(); - cy.task('esArchiverResetKibana'); - createRule( - getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false }) - ).then((response) => { - createRuleExceptionItem(response.body.id, [ - { - description: 'Exception item for rule default exception list', - entries: [ - { - field: 'user.name', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - name: EXPIRED_EXCEPTION_ITEM_NAME, - type: 'simple', - expire_time: expiredDate, - }, - { - description: 'Exception item for rule default exception list', - entries: [ - { - field: 'user.name', - operator: 'included', - type: 'match', - value: 'some value', - }, - ], - name: NON_EXPIRED_EXCEPTION_ITEM_NAME, - type: 'simple', - expire_time: futureDate, - }, - ]); +// Flaky on serverless +describe( + 'Detection rules, bulk duplicate', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + before(() => { + cleanKibana(); }); - visitSecurityDetectionRulesPage(); - disableAutoRefresh(); - }); - - it('Duplicates rules', () => { - selectAllRules(); - duplicateSelectedRulesWithoutExceptions(); - expectManagementTableRules([`${RULE_NAME} [Duplicate]`]); - }); + beforeEach(() => { + login(); + // Make sure persisted rules table state is cleared + resetRulesTableState(); + deleteAlertsAndRules(); + cy.task('esArchiverResetKibana'); + createRule( + getNewRule({ name: RULE_NAME, ...defaultRuleData, rule_id: '1', enabled: false }) + ).then((response) => { + createRuleExceptionItem(response.body.id, [ + { + description: 'Exception item for rule default exception list', + entries: [ + { + field: 'user.name', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + name: EXPIRED_EXCEPTION_ITEM_NAME, + type: 'simple', + expire_time: expiredDate, + }, + { + description: 'Exception item for rule default exception list', + entries: [ + { + field: 'user.name', + operator: 'included', + type: 'match', + value: 'some value', + }, + ], + name: NON_EXPIRED_EXCEPTION_ITEM_NAME, + type: 'simple', + expire_time: futureDate, + }, + ]); + }); + + visitSecurityDetectionRulesPage(); + disableAutoRefresh(); + }); - describe('With exceptions', () => { - it('Duplicates rules with expired exceptions', () => { + it('Duplicates rules', () => { selectAllRules(); - duplicateSelectedRulesWithExceptions(); + duplicateSelectedRulesWithoutExceptions(); expectManagementTableRules([`${RULE_NAME} [Duplicate]`]); - goToTheRuleDetailsOf(`${RULE_NAME} [Duplicate]`); - goToExceptionsTab(); - assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]); - viewExpiredExceptionItems(); - assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [EXPIRED_EXCEPTION_ITEM_NAME]); }); - it('Duplicates rules with exceptions, excluding expired exceptions', () => { - selectAllRules(); - duplicateSelectedRulesWithNonExpiredExceptions(); - expectManagementTableRules([`${RULE_NAME} [Duplicate]`]); - goToTheRuleDetailsOf(`${RULE_NAME} [Duplicate]`); - goToExceptionsTab(); - assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]); - viewExpiredExceptionItems(); - assertNumberOfExceptionItemsExists(0); + describe('With exceptions', () => { + it('Duplicates rules with expired exceptions', () => { + selectAllRules(); + duplicateSelectedRulesWithExceptions(); + expectManagementTableRules([`${RULE_NAME} [Duplicate]`]); + goToTheRuleDetailsOf(`${RULE_NAME} [Duplicate]`); + goToExceptionsTab(); + assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]); + viewExpiredExceptionItems(); + assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [EXPIRED_EXCEPTION_ITEM_NAME]); + }); + + it('Duplicates rules with exceptions, excluding expired exceptions', () => { + selectAllRules(); + duplicateSelectedRulesWithNonExpiredExceptions(); + expectManagementTableRules([`${RULE_NAME} [Duplicate]`]); + goToTheRuleDetailsOf(`${RULE_NAME} [Duplicate]`); + goToExceptionsTab(); + assertExceptionItemsExists(EXCEPTION_CARD_ITEM_NAME, [NON_EXPIRED_EXCEPTION_ITEM_NAME]); + viewExpiredExceptionItems(); + assertNumberOfExceptionItemsExists(0); + }); }); - }); -}); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts index 3771d4a5858ac..6f5dc717c8607 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rule_actions/snoozing/rule_snoozing.cy.ts @@ -47,7 +47,8 @@ import { TOOLTIP } from '../../../../../screens/common'; const RULES_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_rules.ndjson'; -describe('rule snoozing', { tags: ['@ess', '@serverless'] }, () => { +// Flaky in serverless tests +describe('rule snoozing', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts index eaa67b859b6c0..97ccd8494e3dd 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_filtering.cy.ts @@ -28,7 +28,8 @@ import { import { disableAutoRefresh } from '../../../../tasks/alerts_detection_rules'; import { getNewRule } from '../../../../objects/rule'; -describe('Rules table: filtering', { tags: ['@ess', '@serverless'] }, () => { +// Flaky in serverless tests +describe('Rules table: filtering', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); }); @@ -41,8 +42,10 @@ describe('Rules table: filtering', { tags: ['@ess', '@serverless'] }, () => { cy.task('esArchiverResetKibana'); }); - describe('Last response filter', () => { - it('Filters rules by last response', function () { + describe.skip('Last response filter', () => { + // Flaky in serverless tests + // @brokenInServerless tag is not working so a skip was needed + it('Filters rules by last response', { tags: ['@brokenInServerless'] }, function () { deleteIndex('test_index'); createIndex('test_index', { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts index d4465760ee97f..d2fbd5433f872 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_links.cy.ts @@ -12,7 +12,8 @@ import { cleanKibana, deleteAlertsAndRules } from '../../../../tasks/common'; import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { DETECTIONS_RULE_MANAGEMENT_URL } from '../../../../urls/navigation'; -describe('Rules table: links', { tags: ['@ess', '@serverless'] }, () => { +// Flaky in serverless tests +describe('Rules table: links', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts index 7bf4d9e6eef24..675fa704f5430 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/rules_table/rules_table_persistent_state.cy.ts @@ -110,167 +110,172 @@ describe('Rules table: persistent state', { tags: ['@ess', '@serverless'] }, () resetRulesTableState(); }); - describe('while on a happy path', () => { - it('activates management tab by default', () => { - visit(SECURITY_DETECTIONS_RULES_URL); + // Flaky on serverless + describe( + 'while on a happy path', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + it('activates management tab by default', () => { + visit(SECURITY_DETECTIONS_RULES_URL); - expectRulesManagementTab(); - }); - - it('leads to displaying a rule according to the specified filters', () => { - visitRulesTableWithState({ - searchTerm: 'rule', - tags: ['tag-b'], - source: 'custom', - enabled: false, - field: 'name', - order: 'asc', - perPage: 5, - page: 2, - }); - - expectManagementTableRules(['rule 6']); - }); - - it('loads from the url', () => { - visitRulesTableWithState({ - searchTerm: 'rule', - tags: ['tag-b'], - source: 'custom', - enabled: false, - field: 'name', - order: 'asc', - perPage: 5, - page: 2, + expectRulesManagementTab(); }); - expectRulesManagementTab(); - expectFilterSearchTerm('rule'); - expectFilterByTags(['tag-b']); - expectFilterByCustomRules(); - expectFilterByDisabledRules(); - expectTableSorting('Rule', 'asc'); - expectRowsPerPage(5); - expectTablePage(2); - }); + it('leads to displaying a rule according to the specified filters', () => { + visitRulesTableWithState({ + searchTerm: 'rule', + tags: ['tag-b'], + source: 'custom', + enabled: false, + field: 'name', + order: 'asc', + perPage: 5, + page: 2, + }); - it('loads from the session storage', () => { - setStorageState({ - searchTerm: 'test', - tags: ['tag-a'], - source: 'prebuilt', - enabled: true, - field: 'severity', - order: 'desc', - perPage: 10, + expectManagementTableRules(['rule 6']); }); - visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); - - expectRulesManagementTab(); - expectFilterSearchTerm('test'); - expectFilterByTags(['tag-a']); - expectFilterByPrebuiltRules(); - expectFilterByEnabledRules(); - expectTableSorting('Severity', 'desc'); - }); - - it('prefers url state over storage state', () => { - setStorageState({ - searchTerm: 'test', - tags: ['tag-c'], - source: 'prebuilt', - enabled: true, - field: 'severity', - order: 'desc', - perPage: 10, - }); + it('loads from the url', () => { + visitRulesTableWithState({ + searchTerm: 'rule', + tags: ['tag-b'], + source: 'custom', + enabled: false, + field: 'name', + order: 'asc', + perPage: 5, + page: 2, + }); - visitRulesTableWithState({ - searchTerm: 'rule', - tags: ['tag-b'], - source: 'custom', - enabled: false, - field: 'name', - order: 'asc', - perPage: 5, - page: 2, + expectRulesManagementTab(); + expectFilterSearchTerm('rule'); + expectFilterByTags(['tag-b']); + expectFilterByCustomRules(); + expectFilterByDisabledRules(); + expectTableSorting('Rule', 'asc'); + expectRowsPerPage(5); + expectTablePage(2); }); - expectRulesManagementTab(); - expectRulesTableState(); - expectTablePage(2); - }); + it('loads from the session storage', () => { + setStorageState({ + searchTerm: 'test', + tags: ['tag-a'], + source: 'prebuilt', + enabled: true, + field: 'severity', + order: 'desc', + perPage: 10, + }); - describe('and on the rules management tab', () => { - beforeEach(() => { - login(); visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); + + expectRulesManagementTab(); + expectFilterSearchTerm('test'); + expectFilterByTags(['tag-a']); + expectFilterByPrebuiltRules(); + expectFilterByEnabledRules(); + expectTableSorting('Severity', 'desc'); }); - it('persists after reloading the page', () => { - changeRulesTableState(); - goToTablePage(2); + it('prefers url state over storage state', () => { + setStorageState({ + searchTerm: 'test', + tags: ['tag-c'], + source: 'prebuilt', + enabled: true, + field: 'severity', + order: 'desc', + perPage: 10, + }); - cy.reload(); + visitRulesTableWithState({ + searchTerm: 'rule', + tags: ['tag-b'], + source: 'custom', + enabled: false, + field: 'name', + order: 'asc', + perPage: 5, + page: 2, + }); expectRulesManagementTab(); expectRulesTableState(); expectTablePage(2); }); - it('persists after navigating back from a rule details page', () => { - changeRulesTableState(); - goToTablePage(2); + describe('and on the rules management tab', () => { + beforeEach(() => { + login(); + visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); + }); - goToRuleDetails(); - cy.go('back'); + it('persists after reloading the page', () => { + changeRulesTableState(); + goToTablePage(2); - expectRulesManagementTab(); - expectRulesTableState(); - expectTablePage(2); - }); + cy.reload(); - it('persists after navigating to another page inside Security Solution', () => { - changeRulesTableState(); - goToTablePage(2); + expectRulesManagementTab(); + expectRulesTableState(); + expectTablePage(2); + }); - visit(DASHBOARDS_URL); - visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); + it('persists after navigating back from a rule details page', () => { + changeRulesTableState(); + goToTablePage(2); - expectRulesManagementTab(); - expectRulesTableState(); - expectTablePage(1); - }); + goToRuleDetails(); + cy.go('back'); - it('persists after navigating to another page outside Security Solution', () => { - changeRulesTableState(); - goToTablePage(2); + expectRulesManagementTab(); + expectRulesTableState(); + expectTablePage(2); + }); - visit(KIBANA_HOME); - visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); + it('persists after navigating to another page inside Security Solution', () => { + changeRulesTableState(); + goToTablePage(2); - expectRulesManagementTab(); - expectRulesTableState(); - expectTablePage(1); - }); - }); + visit(DASHBOARDS_URL); + visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); - describe('and on the rules monitoring tab', () => { - beforeEach(() => { - login(); - visit(SECURITY_DETECTIONS_RULES_MONITORING_URL); + expectRulesManagementTab(); + expectRulesTableState(); + expectTablePage(1); + }); + + it('persists after navigating to another page outside Security Solution', () => { + changeRulesTableState(); + goToTablePage(2); + + visit(KIBANA_HOME); + visit(SECURITY_DETECTIONS_RULES_MANAGEMENT_URL); + + expectRulesManagementTab(); + expectRulesTableState(); + expectTablePage(1); + }); }); - it('persists the selected tab', () => { - changeRulesTableState(); + describe('and on the rules monitoring tab', () => { + beforeEach(() => { + login(); + visit(SECURITY_DETECTIONS_RULES_MONITORING_URL); + }); - cy.reload(); + it('persists the selected tab', () => { + changeRulesTableState(); - expectRulesMonitoringTab(); + cy.reload(); + + expectRulesMonitoringTab(); + }); }); - }); - }); + } + ); describe('upon state format upgrade', async () => { beforeEach(() => { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts index 3aa68a9f8029a..ad104df5789ca 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/value_lists/value_lists.cy.ts @@ -50,7 +50,8 @@ describe('value lists', () => { closeValueListsModal(); }); - describe('create list types', () => { + // Flaky in serverless tests + describe('create list types', { tags: ['@brokenInServerless'] }, () => { beforeEach(() => { openValueListsModal(); }); @@ -108,7 +109,8 @@ describe('value lists', () => { }); }); - describe('delete list types', () => { + // Flaky in serverless tests + describe('delete list types', { tags: ['@brokenInServerless'] }, () => { it('deletes a "keyword" list from an uploaded file', () => { importValueList(TEXT_LIST_FILE_NAME, 'keyword'); openValueListsModal(); @@ -154,7 +156,8 @@ describe('value lists', () => { }); }); - describe('export list types', () => { + // Flaky in serverless tests + describe('export list types', { tags: ['@brokenInServerless'] }, () => { it('exports a "keyword" list from an uploaded file', () => { cy.intercept('POST', `/api/lists/items/_export?list_id=${TEXT_LIST_FILE_NAME}`).as( 'exportList' diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts index e45484e5fb834..b1e2c81b4c420 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/entry/use_value_list.cy.ts @@ -50,83 +50,88 @@ const goToRulesAndOpenValueListModal = () => { openValueListsModal(); }; -describe('Use Value list in exception entry', { tags: ['@ess', '@serverless'] }, () => { - before(() => { - cleanKibana(); - login(); - cy.task('esArchiverLoad', { archiveName: 'exceptions' }); - createRule({ - ...getNewRule(), - query: 'user.name:*', - index: ['exceptions*'], - exceptions_list: [], - rule_id: '2', - }); - visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); - }); - beforeEach(() => { - createListsIndex(); - }); - - afterEach(() => { - cy.task('esArchiverUnload', 'exceptions'); - }); - - it('Should use value list in exception entry, and validate deleting value list prompt', () => { - const ITEM_NAME = 'Exception item with value list'; - const ITEM_FIELD = 'agent.name'; - - goToRulesAndOpenValueListModal(); - - // Add new value list of type keyword - const listName = 'value_list.txt'; - selectValueListType('keyword'); - selectValueListsFile(listName); - uploadValueList(); - - cy.get(VALUE_LISTS_TABLE) - .find(VALUE_LISTS_ROW) - .should(($row) => { - expect($row.text()).to.contain(listName); - expect($row.text()).to.contain('Keywords'); +// Flaky on serverless +describe( + 'Use Value list in exception entry', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + before(() => { + cleanKibana(); + login(); + cy.task('esArchiverLoad', { archiveName: 'exceptions' }); + createRule({ + ...getNewRule(), + query: 'user.name:*', + index: ['exceptions*'], + exceptions_list: [], + rule_id: '2', }); - closeValueListsModal(); - goToRuleDetails(); - goToExceptionsTab(); + visitWithoutDateRange(DETECTIONS_RULE_MANAGEMENT_URL); + }); + beforeEach(() => { + createListsIndex(); + }); + + afterEach(() => { + cy.task('esArchiverUnload', 'exceptions'); + }); - // open add exception modal - openExceptionFlyoutFromEmptyViewerPrompt(); + it('Should use value list in exception entry, and validate deleting value list prompt', () => { + const ITEM_NAME = 'Exception item with value list'; + const ITEM_FIELD = 'agent.name'; - // add exception item name - addExceptionFlyoutItemName(ITEM_NAME); + goToRulesAndOpenValueListModal(); - addExceptionEntryFieldValue(ITEM_FIELD, 0); - addExceptionEntryOperatorValue('is in list', 0); + // Add new value list of type keyword + const listName = 'value_list.txt'; + selectValueListType('keyword'); + selectValueListsFile(listName); + uploadValueList(); - addExceptionEntryFieldMatchIncludedValue('value_list.txt', 0); + cy.get(VALUE_LISTS_TABLE) + .find(VALUE_LISTS_ROW) + .should(($row) => { + expect($row.text()).to.contain(listName); + expect($row.text()).to.contain('Keywords'); + }); + closeValueListsModal(); + goToRuleDetails(); + goToExceptionsTab(); - // The Close all alerts that match attributes in this exception option is disabled - cy.get(CLOSE_ALERTS_CHECKBOX).should('exist'); - cy.get(CLOSE_ALERTS_CHECKBOX).should('have.attr', 'disabled'); + // open add exception modal + openExceptionFlyoutFromEmptyViewerPrompt(); - // Create exception - submitNewExceptionItem(); + // add exception item name + addExceptionFlyoutItemName(ITEM_NAME); - // displays existing exception items - cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); - cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); - cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); - cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should( - 'have.text', - ` ${ITEM_FIELD}included in value_list.txt` - ); + addExceptionEntryFieldValue(ITEM_FIELD, 0); + addExceptionEntryOperatorValue('is in list', 0); - // Go back to value list to delete the existing one - goToRulesAndOpenValueListModal(); + addExceptionEntryFieldMatchIncludedValue('value_list.txt', 0); - deleteValueListsFile(listName); + // The Close all alerts that match attributes in this exception option is disabled + cy.get(CLOSE_ALERTS_CHECKBOX).should('exist'); + cy.get(CLOSE_ALERTS_CHECKBOX).should('have.attr', 'disabled'); - // Toast should be shown because of exception reference - cy.get(EXCEPTIONS_TABLE_MODAL).should('exist'); - }); -}); + // Create exception + submitNewExceptionItem(); + + // displays existing exception items + cy.get(EXCEPTION_ITEM_VIEWER_CONTAINER).should('have.length', 1); + cy.get(NO_EXCEPTIONS_EXIST_PROMPT).should('not.exist'); + cy.get(EXCEPTION_CARD_ITEM_NAME).should('have.text', ITEM_NAME); + cy.get(EXCEPTION_CARD_ITEM_CONDITIONS).should( + 'have.text', + ` ${ITEM_FIELD}included in value_list.txt` + ); + + // Go back to value list to delete the existing one + goToRulesAndOpenValueListModal(); + + deleteValueListsFile(listName); + + // Toast should be shown because of exception reference + cy.get(EXCEPTIONS_TABLE_MODAL).should('exist'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts index 881c21472d7ef..b296ff05e3b5b 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/duplicate_lists.cy.ts @@ -40,7 +40,8 @@ const getExceptionList2 = () => ({ list_id: 'exception_list_2', }); -describe('Duplicate List', { tags: ['@ess', '@serverless'] }, () => { +// Flaky in serverless tests +describe('Duplicate List', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { beforeEach(() => { cy.task('esArchiverResetKibana'); login(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts index ac9c0be83b5c1..ac10e916d762f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/shared_exception_list_page/import_lists.cy.ts @@ -20,7 +20,8 @@ import { import { login, visitWithoutDateRange } from '../../../../tasks/login'; import { EXCEPTIONS_URL } from '../../../../urls/navigation'; -describe('Import Lists', { tags: ['@ess', '@serverless'] }, () => { +// Flaky in serverless +describe('Import Lists', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { const LIST_TO_IMPORT_FILENAME = 'cypress/fixtures/7_16_exception_list.ndjson'; before(() => { cy.task('esArchiverResetKibana'); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts index fcb33ff4de239..5b8ba030ade12 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/dashboards/upgrade_risk_score.cy.ts @@ -38,7 +38,8 @@ import { ENTITY_ANALYTICS_URL } from '../../../urls/navigation'; const spaceId = 'default'; -describe('Upgrade risk scores', { tags: ['@ess', '@serverless'] }, () => { +// Flaky on serverless +describe('Upgrade risk scores', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); login(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts index c3add90e6531f..0caaefd1c5e69 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/data_providers.cy.ts @@ -29,61 +29,66 @@ import { getTimeline } from '../../../objects/timeline'; import { HOSTS_URL } from '../../../urls/navigation'; import { cleanKibana, scrollToBottom } from '../../../tasks/common'; -describe('timeline data providers', { tags: ['@ess', '@serverless'] }, () => { - before(() => { - cleanKibana(); - }); +// Failing in serverless +describe( + 'timeline data providers', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + before(() => { + cleanKibana(); + }); - beforeEach(() => { - login(); - visit(HOSTS_URL); - waitForAllHostsToBeLoaded(); - scrollToBottom(); - createNewTimeline(); - addNameAndDescriptionToTimeline(getTimeline()); - populateTimeline(); - }); + beforeEach(() => { + login(); + visit(HOSTS_URL); + waitForAllHostsToBeLoaded(); + scrollToBottom(); + createNewTimeline(); + addNameAndDescriptionToTimeline(getTimeline()); + populateTimeline(); + }); - it('displays the data provider action menu when Enter is pressed', () => { - addDataProvider({ field: 'host.name', operator: 'exists' }); + it('displays the data provider action menu when Enter is pressed', () => { + addDataProvider({ field: 'host.name', operator: 'exists' }); - cy.get(TIMELINE_DATA_PROVIDERS_ACTION_MENU).should('not.exist'); - cy.get(`${TIMELINE_FLYOUT_HEADER} ${TIMELINE_DROPPED_DATA_PROVIDERS}`).focus(); - cy.get(`${TIMELINE_FLYOUT_HEADER} ${TIMELINE_DROPPED_DATA_PROVIDERS}`) - .first() - .parent() - .type('{enter}'); + cy.get(TIMELINE_DATA_PROVIDERS_ACTION_MENU).should('not.exist'); + cy.get(`${TIMELINE_FLYOUT_HEADER} ${TIMELINE_DROPPED_DATA_PROVIDERS}`).focus(); + cy.get(`${TIMELINE_FLYOUT_HEADER} ${TIMELINE_DROPPED_DATA_PROVIDERS}`) + .first() + .parent() + .type('{enter}'); + + cy.get(TIMELINE_DATA_PROVIDERS_ACTION_MENU).should('exist'); + }); - cy.get(TIMELINE_DATA_PROVIDERS_ACTION_MENU).should('exist'); - }); + it.skip( + 'persists timeline when data provider is updated by dragging a field from data grid', + { tags: ['@brokenInServerless'] }, + () => { + updateDataProviderbyDraggingField('host.name', 0); + waitForTimelineChanges(); + cy.reload(); + cy.get(`${GET_TIMELINE_GRID_CELL('host.name')}`) + .first() + .then((hostname) => { + cy.get(TIMELINE_DATA_PROVIDERS_CONTAINER).contains(`host.name: "${hostname.text()}"`); + }); + } + ); - it.skip( - 'persists timeline when data provider is updated by dragging a field from data grid', - { tags: ['@brokenInServerless'] }, - () => { - updateDataProviderbyDraggingField('host.name', 0); + it('persists timeline when a field is added by hover action "Add To Timeline" in data provider ', () => { + addDataProvider({ field: 'host.name', operator: 'exists' }); + waitForTimelineChanges(); + updateDataProviderByFieldHoverAction('host.name', 0); waitForTimelineChanges(); cy.reload(); cy.get(`${GET_TIMELINE_GRID_CELL('host.name')}`) .first() .then((hostname) => { - cy.get(TIMELINE_DATA_PROVIDERS_CONTAINER).contains(`host.name: "${hostname.text()}"`); - }); - } - ); - - it('persists timeline when a field is added by hover action "Add To Timeline" in data provider ', () => { - addDataProvider({ field: 'host.name', operator: 'exists' }); - waitForTimelineChanges(); - updateDataProviderByFieldHoverAction('host.name', 0); - waitForTimelineChanges(); - cy.reload(); - cy.get(`${GET_TIMELINE_GRID_CELL('host.name')}`) - .first() - .then((hostname) => { - cy.get(TIMELINE_DATA_PROVIDERS_CONTAINER).should((dataProviderContainer) => { - expect(dataProviderContainer).to.contain(`host.name: "${hostname.text()}"`); + cy.get(TIMELINE_DATA_PROVIDERS_CONTAINER).should((dataProviderContainer) => { + expect(dataProviderContainer).to.contain(`host.name: "${hostname.text()}"`); + }); }); - }); - }); -}); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts index 4806098a37d1c..09e0885a8542d 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/fields_browser.cy.ts @@ -49,7 +49,8 @@ const defaultHeaders = [ { id: 'user.name' }, ]; -describe('Fields Browser', { tags: ['@ess', '@serverless'] }, () => { +// Flaky in serverless tests +describe('Fields Browser', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts index a8ab36c7bd837..0fa319ec40021 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/pagination.cy.ts @@ -22,8 +22,9 @@ import { populateTimeline } from '../../../tasks/timeline'; import { HOSTS_URL } from '../../../urls/navigation'; +// Flaky on serverless const defaultPageSize = 25; -describe('Pagination', { tags: ['@ess', '@serverless'] }, () => { +describe('Pagination', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { before(() => { cleanKibana(); cy.task('esArchiverLoad', { archiveName: 'timeline' }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts index 5cdb4462839c2..c2ca620a40554 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/toggle_column.cy.ts @@ -19,30 +19,34 @@ import { import { HOSTS_URL } from '../../../urls/navigation'; -describe('toggle column in timeline', { tags: ['@ess', '@serverless'] }, () => { - before(() => { - cleanKibana(); - cy.intercept('POST', '/api/timeline/_export?file_name=timelines_export.ndjson').as('export'); - }); - - beforeEach(() => { - login(); - visit(HOSTS_URL); - openTimelineUsingToggle(); - populateTimeline(); - }); - - it('removes the @timestamp field from the timeline when the user un-checks the toggle', () => { - expandFirstTimelineEventDetails(); - clickTimestampToggleField(); - - cy.get(TIMESTAMP_HEADER_FIELD).should('not.exist'); - }); - - it('adds the _id field to the timeline when the user checks the field', () => { - expandFirstTimelineEventDetails(); - clickIdToggleField(); - - cy.get(ID_HEADER_FIELD).should('exist'); - }); -}); +describe( + 'toggle column in timeline', + { tags: ['@ess', '@serverless', '@brokenInServerless'] }, + () => { + before(() => { + cleanKibana(); + cy.intercept('POST', '/api/timeline/_export?file_name=timelines_export.ndjson').as('export'); + }); + + beforeEach(() => { + login(); + visit(HOSTS_URL); + openTimelineUsingToggle(); + populateTimeline(); + }); + + it('removes the @timestamp field from the timeline when the user un-checks the toggle', () => { + expandFirstTimelineEventDetails(); + clickTimestampToggleField(); + + cy.get(TIMESTAMP_HEADER_FIELD).should('not.exist'); + }); + + it('adds the _id field to the timeline when the user checks the field', () => { + expandFirstTimelineEventDetails(); + clickIdToggleField(); + + cy.get(ID_HEADER_FIELD).should('exist'); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/discover.ts b/x-pack/test/security_solution_cypress/cypress/screens/discover.ts index 577246e5f6568..72f0801fde778 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/discover.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/discover.ts @@ -45,7 +45,7 @@ export const DISCOVER_FIELDS_LOADING = getDataTestSubjectSelector( export const DISCOVER_DATA_GRID_UPDATING = getDataTestSubjectSelector('discoverDataGridUpdating'); -export const DISCOVER_DATA_GRID_LOADING = getDataTestSubjectSelector('discoverDataGridLoading'); +export const UNIFIED_DATA_TABLE_LOADING = getDataTestSubjectSelector('unifiedDataTableLoading'); export const DISCOVER_NO_RESULTS = getDataTestSubjectSelector('discoverNoResults'); @@ -54,7 +54,7 @@ export const DISCOVER_TABLE = getDataTestSubjectSelector('docTable'); export const GET_DISCOVER_DATA_GRID_CELL = (columnId: string, rowIndex: number) => { return `${DISCOVER_TABLE} ${getDataTestSubjectSelector( 'dataGridRowCell' - )}[data-gridcell-column-id="${columnId}"][data-gridcell-row-index="${rowIndex}"] .dscDiscoverGrid__cellValue`; + )}[data-gridcell-column-id="${columnId}"][data-gridcell-row-index="${rowIndex}"] .unifiedDataTable__cellValue`; }; export const GET_DISCOVER_DATA_GRID_CELL_HEADER = (columnId: string) => diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts index 9240c93428fab..5a0f0fdf93ec1 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/responder.ts @@ -81,8 +81,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); }; - // Failing: See https://github.com/elastic/kibana/issues/139260 - describe.skip('Response Actions Responder', function () { + describe('Response Actions Responder', function () { let indexedData: IndexedHostsAndAlertsResponse; let endpointAgentId: string; @@ -183,6 +182,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Show event/alert details for the first one in the list await pageObjects.timeline.showEventDetails(); + // TODO: The index already exists error toast should not show up + // close and dismiss it if it does + if (await testSubjects.exists('globalToastList')) { + await testSubjects.click('toastCloseButton'); + } // Click responder from the take action button await testSubjects.click('take-action-dropdown-btn'); await testSubjects.clickWhenNotDisabled('endpointResponseActions-action-item'); diff --git a/x-pack/test_serverless/README.md b/x-pack/test_serverless/README.md index 84b1aaab676d6..6d7c6e350b9b2 100644 --- a/x-pack/test_serverless/README.md +++ b/x-pack/test_serverless/README.md @@ -5,6 +5,9 @@ The tests and helper methods (services, page objects) defined here in `serverless`, `serverless_observability`, `serverless_search` and `serverless_security` plugins. + For how to set up Docker for serverless ES images, please refer to + [packages/kbn-es/README](https://github.com/elastic/kibana/blob/main/packages/kbn-es/README.mdx). + ## Serverless testing structure and conventions ### Overview @@ -133,3 +136,21 @@ node scripts/functional_tests_server.js --config test_serverless/api_integration node scripts/functional_test_runner.js --config test_serverless/api_integration/test_suites/search/config.ts ``` + +## Run tests on MKI +There is no need to start servers locally, you just need to create MKI project and copy urls for Elasticsearch and Kibana. Make sure to update urls with username/password and port 443 for Elasticsearch. FTR has no control over MKI and can't update your projects so make sure your `config.ts` does not specify any custom arguments for Kibana or Elasticsearch. Otherwise, it will be ignored. You can run the tests from the `x-pack` directory: +``` +TEST_CLOUD=1 TEST_ES_URL="https://elastic:PASSWORD@ES_HOSTNAME:443" TEST_KIBANA_URL="https://elastic:PASSWORD@KIBANA_HOSTNAME" node scripts/functional_test_runner --config test_serverless/api_integration/test_suites/search/config.ts --exclude-tag=skipMKI +``` + +## Skipping tests for MKI run +The tests that are listed in the the regular `config.ts` generally should work in both Kibana CI and MKI. However some tests might not work properly against MKI projects by design. +Tag the tests with `skipMKI` to be excluded for MKI run. It works only for the `describe` block: +``` +describe("my test suite", async function() { + this.tags(['skipMKI']); + ... +}); +``` + +If you are running tests from your local against MKI projects, make sure to add `--exclude-tag=skipMKI` to your FTR command. diff --git a/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts b/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts index f9700dfaff70a..cc165c517f6cf 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/index_management/indices.ts @@ -17,7 +17,8 @@ export default function ({ getService }: FtrProviderContext) { const es = getService('es'); const log = getService('log'); - describe('Indices', function () { + // FLAKY: https://github.com/elastic/kibana/issues/165565 + describe.skip('Indices', function () { const indexName = `index-${Math.random()}`; before(async () => { diff --git a/x-pack/test_serverless/api_integration/test_suites/common/rollups.ts b/x-pack/test_serverless/api_integration/test_suites/common/rollups.ts index 47dd58f242759..c1ec42564e481 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/rollups.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/rollups.ts @@ -16,7 +16,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - describe('rollup data views - fields for wildcard', function () { + // Failing: See https://github.com/elastic/kibana/issues/165476 + describe.skip('rollup data views - fields for wildcard', function () { before(async () => { await esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index'); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts b/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts index f3969e07eea7e..7cc4089814c77 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/scripted_fields.ts @@ -13,7 +13,8 @@ export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - describe('scripted fields disabled', function () { + // FLAKY: https://github.com/elastic/kibana/issues/165511 + describe.skip('scripted fields disabled', function () { before(async () => { await esArchiver.load('test/api_integration/fixtures/es_archiver/index_patterns/basic_index'); }); diff --git a/x-pack/test_serverless/api_integration/test_suites/common/security/user_profiles.ts b/x-pack/test_serverless/api_integration/test_suites/common/security/user_profiles.ts index 83ef0c4335679..64650c5f47548 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/security/user_profiles.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/security/user_profiles.ts @@ -16,7 +16,8 @@ export default function ({ getService }: FtrProviderContext) { describe('security/user_profiles', function () { describe('route access', () => { - describe('internal', () => { + // FLAKY: https://github.com/elastic/kibana/issues/165391 + describe.skip('internal', () => { // When we run tests on MKI, SAML realm is configured differently, and we cannot handcraft SAML responses to // log in as SAML users. this.tags(['skipMKI']); diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts b/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts index 5e3ab0cd27057..a840abb55f3a7 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/data_view_field_editor_example/index.ts @@ -17,7 +17,8 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid const retry = getService('retry'); const kibanaServer = getService('kibanaServer'); - describe('data view field editor example', function () { + // FLAKY: https://github.com/elastic/kibana/issues/165384 + describe.skip('data view field editor example', function () { before(async () => { // TODO: emptyKibanaIndex fails in Serverless with // "index_not_found_exception: no such index [.kibana_ingest]", diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/discover_customization_examples/customizations.ts b/x-pack/test_serverless/functional/test_suites/common/examples/discover_customization_examples/customizations.ts index 7b97c1256ce6d..cb0c5cc9c36ba 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/discover_customization_examples/customizations.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/discover_customization_examples/customizations.ts @@ -20,7 +20,9 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { const dataGrid = getService('dataGrid'); const defaultSettings = { defaultIndex: 'logstash-*' }; - describe('Customizations', () => { + // Flaky in serverless tests (before hook) + // Failing: See https://github.com/elastic/kibana/issues/165396 + describe.skip('Customizations', () => { before(async () => { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/field_formats/index.ts b/x-pack/test_serverless/functional/test_suites/common/examples/field_formats/index.ts index 8bd85620e9857..ee14ac9060c40 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/field_formats/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/field_formats/index.ts @@ -12,7 +12,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects(['common']); - describe('Field formats example', function () { + // Flaky in serverless tests + describe.skip('Field formats example', function () { before(async () => { await PageObjects.common.navigateToApp('fieldFormatsExample'); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/partial_results/index.ts b/x-pack/test_serverless/functional/test_suites/common/examples/partial_results/index.ts index fa0036812672d..e93f275a0269d 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/partial_results/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/partial_results/index.ts @@ -12,7 +12,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const PageObjects = getPageObjects(['common']); - describe('Partial Results Example', function () { + // FLAKY: https://github.com/elastic/kibana/issues/165563 + describe.skip('Partial Results Example', function () { before(async () => { await PageObjects.common.navigateToApp('partialResultsExample'); diff --git a/x-pack/test_serverless/functional/test_suites/common/home_page.ts b/x-pack/test_serverless/functional/test_suites/common/home_page.ts index c1b3dad37d292..9660b21d6e7d2 100644 --- a/x-pack/test_serverless/functional/test_suites/common/home_page.ts +++ b/x-pack/test_serverless/functional/test_suites/common/home_page.ts @@ -11,7 +11,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { const svlCommonPage = getPageObject('svlCommonPage'); const svlCommonNavigation = getService('svlCommonNavigation'); - describe('home page', function () { + // Failing: See https://github.com/elastic/kibana/issues/165386 + describe.skip('home page', function () { it('has project header', async () => { await svlCommonNavigation.navigateToKibanaHome(); await svlCommonPage.assertProjectHeaderExists(); diff --git a/x-pack/test_serverless/functional/test_suites/common/index.ts b/x-pack/test_serverless/functional/test_suites/common/index.ts index 08e816c9bdfda..597a1b6f84963 100644 --- a/x-pack/test_serverless/functional/test_suites/common/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/index.ts @@ -13,6 +13,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./management')); // platform security + loadTestFile(require.resolve('./security/api_keys')); loadTestFile(require.resolve('./security/navigation/avatar_menu')); // Management diff --git a/x-pack/test_serverless/functional/test_suites/common/management.ts b/x-pack/test_serverless/functional/test_suites/common/management.ts index fe2561854c49a..7ea23c7be4bb5 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management.ts @@ -11,7 +11,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { const commonPage = getPageObject('common'); const testSubjects = getService('testSubjects'); - describe('Management', function () { + // Flaky in serverless tests + describe.skip('Management', function () { describe('Disabled UIs', () => { const DISABLED_PLUGINS = [ { diff --git a/x-pack/test_serverless/functional/test_suites/common/security/api_keys.ts b/x-pack/test_serverless/functional/test_suites/common/security/api_keys.ts index ab650c4c43a25..32c12c9b713b4 100644 --- a/x-pack/test_serverless/functional/test_suites/common/security/api_keys.ts +++ b/x-pack/test_serverless/functional/test_suites/common/security/api_keys.ts @@ -8,7 +8,6 @@ import expect from '@kbn/expect'; import { Client } from '@elastic/elasticsearch'; import { ToolingLog } from '@kbn/tooling-log'; -import type { estypes } from '@elastic/elasticsearch'; import { FtrProviderContext } from '../../../ftr_provider_context'; async function clearAllApiKeys(esClient: Client, logger: ToolingLog) { @@ -25,433 +24,39 @@ async function clearAllApiKeys(esClient: Client, logger: ToolingLog) { } export default ({ getPageObjects, getService }: FtrProviderContext) => { - const es = getService('es'); const pageObjects = getPageObjects(['common', 'apiKeys']); - const log = getService('log'); - const security = getService('security'); - const testSubjects = getService('testSubjects'); - const find = getService('find'); const browser = getService('browser'); - const retry = getService('retry'); - - const testRoles: Record = { - viewer: { - cluster: ['all'], - indices: [ - { - names: ['*'], - privileges: ['all'], - allow_restricted_indices: false, - }, - { - names: ['*'], - privileges: ['monitor', 'read', 'view_index_metadata', 'read_cross_cluster'], - allow_restricted_indices: true, - }, - ], - run_as: ['*'], - }, - }; - - const otherUser: estypes.SecurityPutUserRequest = { - username: 'other_user', - password: 'changeme', - roles: ['superuser'], - }; - - async function ensureApiKeysExist(apiKeysNames: string[]) { - await retry.try(async () => { - for (const apiKeyName of apiKeysNames) { - log.debug(`Checking if API key ("${apiKeyName}") exists.`); - await pageObjects.apiKeys.ensureApiKeyExists(apiKeyName); - log.debug(`API key ("${apiKeyName}") exists.`); - } - }); - } + const es = getService('es'); + const log = getService('log'); - describe('Home page', function () { - before(async () => { + // FLAKY: https://github.com/elastic/kibana/issues/165553 + describe.skip('API keys', () => { + after(async () => { await clearAllApiKeys(es, log); - await security.testUser.setRoles(['kibana_admin']); - await es.security.putUser(otherUser); + }); + it('should create and delete API keys correctly', async () => { await pageObjects.common.navigateToUrl('management', 'security/api_keys', { shouldUseHashForSubUrl: false, }); - }); - - after(async () => { - await es.security.deleteUser({ username: otherUser.username }); - await security.testUser.restoreDefaults(); - }); - - // https://www.elastic.co/guide/en/kibana/7.6/api-keys.html#api-keys-security-privileges - it('Hides management link if user is not authorized', async () => { - await testSubjects.missingOrFail('apiKeys'); - }); - - it('Loads the app', async () => { - await security.testUser.setRoles(['test_api_keys']); - log.debug('Checking for Create API key call to action'); - await find.existsByLinkText('Create API key'); - }); - - describe('creates API key', function () { - before(async () => { - await security.testUser.setRoles(['kibana_admin', 'test_api_keys']); - await pageObjects.common.navigateToUrl('management', 'security/api_keys', { - shouldUseHashForSubUrl: false, - }); - - // Delete any API keys created outside of these tests - await pageObjects.apiKeys.bulkDeleteApiKeys(); - }); - - afterEach(async () => { - await pageObjects.apiKeys.deleteAllApiKeyOneByOne(); - }); - - after(async () => { - await clearAllApiKeys(es, log); - }); - - it('when submitting form, close dialog and displays new api key', async () => { - const apiKeyName = 'Happy API Key'; - await pageObjects.apiKeys.clickOnPromptCreateApiKey(); - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys/create'); - expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('Create API key'); - - await pageObjects.apiKeys.setApiKeyName(apiKeyName); - await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); - const newApiKeyCreation = await pageObjects.apiKeys.getNewApiKeyCreation(); - - expect(await browser.getCurrentUrl()).to.not.contain( - 'app/management/security/api_keys/flyout' - ); - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - expect(await pageObjects.apiKeys.isApiKeyModalExists()).to.be(false); - expect(newApiKeyCreation).to.be(`Created API key '${apiKeyName}'`); - }); - - it('with optional expiration, redirects back and displays base64', async () => { - const apiKeyName = 'Happy expiration API key'; - await pageObjects.apiKeys.clickOnPromptCreateApiKey(); - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys/create'); - - await pageObjects.apiKeys.setApiKeyName(apiKeyName); - await pageObjects.apiKeys.toggleCustomExpiration(); - await pageObjects.apiKeys.setApiKeyCustomExpiration('12'); - await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); - const newApiKeyCreation = await pageObjects.apiKeys.getNewApiKeyCreation(); - - expect(await browser.getCurrentUrl()).to.not.contain( - 'app/management/security/api_keys/create' - ); - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - expect(await pageObjects.apiKeys.isApiKeyModalExists()).to.be(false); - expect(newApiKeyCreation).to.be(`Created API key '${apiKeyName}'`); - }); - }); - - describe('Update API key', function () { - before(async () => { - await security.testUser.setRoles(['kibana_admin', 'test_api_keys']); - await pageObjects.common.navigateToUrl('management', 'security/api_keys', { - shouldUseHashForSubUrl: false, - }); - - // Delete any API keys created outside these tests - await pageObjects.apiKeys.bulkDeleteApiKeys(); - }); - - afterEach(async () => { - await pageObjects.apiKeys.deleteAllApiKeyOneByOne(); - }); - - after(async () => { - await clearAllApiKeys(es, log); - }); - - it('should create a new API key, click the name of the new row, fill out and submit form, and display success message', async () => { - // Create a key to updated - const apiKeyName = 'Happy API Key to Update'; - - await es.security.grantApiKey({ - api_key: { - name: apiKeyName, - expiration: '1d', - }, - grant_type: 'password', - run_as: 'elastic', - username: 'elastic', - password: 'changeme', - }); - - await browser.refresh(); - - log.debug('API key created, moving on to update'); - - // Update newly created API Key - await pageObjects.apiKeys.clickExistingApiKeyToOpenFlyout(apiKeyName); - - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - - await pageObjects.apiKeys.waitForSubmitButtonOnApiKeyFlyoutEnabled(); - - expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('Update API key'); - - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); - - // Status should be displayed - const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); - expect(await apiKeyStatus).to.be('Expires in a day'); - - // Verify metadata is editable - const apiKeyMetadataSwitch = await pageObjects.apiKeys.getMetadataSwitch(); - expect(await apiKeyMetadataSwitch.isEnabled()).to.be(true); - - // Verify restrict privileges is editable - const apiKeyRestrictPrivilegesSwitch = - await pageObjects.apiKeys.getRestrictPrivilegesSwitch(); - expect(await apiKeyRestrictPrivilegesSwitch.isEnabled()).to.be(true); - - // Toggle restrict privileges so the code editor shows up - await apiKeyRestrictPrivilegesSwitch.click(); - - // Toggle metadata switch so the code editor shows up - await apiKeyMetadataSwitch.click(); - - // Check default value of metadata and set value - const restrictPrivilegesCodeEditorValue = - await pageObjects.apiKeys.getCodeEditorValueByIndex(0); - expect(restrictPrivilegesCodeEditorValue).to.be('{}'); - - // Check default value of metadata and set value - const metadataCodeEditorValue = await pageObjects.apiKeys.getCodeEditorValueByIndex(1); - expect(metadataCodeEditorValue).to.be('{}'); - - await pageObjects.apiKeys.setCodeEditorValueByIndex(0, JSON.stringify(testRoles)); - - await pageObjects.apiKeys.setCodeEditorValueByIndex(1, '{"name":"metadataTest"}'); - - // Submit values to update API key - await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); - - // Get success message - const updatedApiKeyToastText = await pageObjects.apiKeys.getApiKeyUpdateSuccessToast(); - expect(updatedApiKeyToastText).to.be(`Updated API key '${apiKeyName}'`); - - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - expect(await pageObjects.apiKeys.isApiKeyModalExists()).to.be(false); - }); - }); - - describe('Readonly API key', function () { - before(async () => { - await security.role.create('read_security_role', { - elasticsearch: { - cluster: ['read_security'], - }, - kibana: [ - { - feature: { - infrastructure: ['read'], - }, - spaces: ['*'], - }, - ], - }); - - await security.testUser.setRoles(['kibana_admin', 'test_api_keys']); - await pageObjects.common.navigateToUrl('management', 'security/api_keys', { - shouldUseHashForSubUrl: false, - }); - - // Delete any API keys created outside these tests - await pageObjects.apiKeys.bulkDeleteApiKeys(); - }); - - afterEach(async () => { - await pageObjects.apiKeys.deleteAllApiKeyOneByOne(); - }); - - after(async () => { - await clearAllApiKeys(es, log); - }); - - // Serverless tests run as elastic (superuser) so unable to test `read_security` permissions - it.skip('should see readonly form elements', async () => { - // Create a key to updated - const apiKeyName = 'Happy API Key to View'; - - await es.security.grantApiKey({ - api_key: { - name: apiKeyName, - expiration: '1d', - metadata: { name: 'metadatatest' }, - role_descriptors: { ...testRoles }, - }, - grant_type: 'password', - run_as: 'elastic', - username: 'elastic', - password: 'changeme', - }); - - await browser.refresh(); - - log.debug('API key created, moving on to view'); - - // Set testUsers roles to have the `read_security` cluster privilege - await security.testUser.setRoles(['read_security_role']); - - // View newly created API Key - await pageObjects.apiKeys.clickExistingApiKeyToOpenFlyout(apiKeyName); - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('API key details'); - - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); - - // Status should be displayed - const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); - expect(await apiKeyStatus).to.be('Expires in a day'); - - const apiKeyMetadataSwitch = await pageObjects.apiKeys.getMetadataSwitch(); - const apiKeyRestrictPrivilegesSwitch = - await pageObjects.apiKeys.getRestrictPrivilegesSwitch(); - - // Verify metadata and restrict privileges switches are now disabled - expect(await apiKeyMetadataSwitch.isEnabled()).to.be(false); - expect(await apiKeyRestrictPrivilegesSwitch.isEnabled()).to.be(false); - - // Close flyout with cancel - await pageObjects.apiKeys.clickCancelButtonOnApiKeyFlyout(); - - // Undo `read_security_role` - await security.testUser.setRoles(['kibana_admin', 'test_api_keys']); - }); - - it('should show the `API key details` flyout if the expiration date is passed', async () => { - const apiKeyName = 'expired-key'; - - await es.security.grantApiKey({ - api_key: { - name: apiKeyName, - expiration: '1ms', - }, - grant_type: 'password', - run_as: 'elastic', - username: 'elastic', - password: 'changeme', - }); - - await browser.refresh(); - - log.debug('API key created, moving on to view'); - - await pageObjects.apiKeys.clickExistingApiKeyToOpenFlyout(apiKeyName); - - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('API key details'); - - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); - - // Status should be displayed - const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); - expect(await apiKeyStatus).to.be('Expired'); - - const apiKeyMetadataSwitch = await pageObjects.apiKeys.getMetadataSwitch(); - const apiKeyRestrictPrivilegesSwitch = - await pageObjects.apiKeys.getRestrictPrivilegesSwitch(); - - // Verify metadata and restrict privileges switches are now disabled - expect(await apiKeyMetadataSwitch.isEnabled()).to.be(false); - expect(await apiKeyRestrictPrivilegesSwitch.isEnabled()).to.be(false); - - await pageObjects.apiKeys.clickCancelButtonOnApiKeyFlyout(); - }); - - it('should show the `API key details flyout` if the API key does not belong to the user', async () => { - const apiKeyName = 'other-key'; - - await es.security.grantApiKey({ - api_key: { - name: apiKeyName, - }, - grant_type: 'password', - run_as: otherUser.username, - username: 'elastic', - password: 'changeme', - }); - - await browser.refresh(); - - log.debug('API key created, moving on to view'); - await pageObjects.apiKeys.clickExistingApiKeyToOpenFlyout(apiKeyName); - expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); - expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('API key details'); + const apiKeyName = 'Happy API Key'; + await pageObjects.apiKeys.clickOnPromptCreateApiKey(); + expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys/create'); + expect(await pageObjects.apiKeys.getFlyoutTitleText()).to.be('Create API key'); - // Verify name input box are disabled - const apiKeyNameInput = await pageObjects.apiKeys.getApiKeyName(); - expect(await apiKeyNameInput.isEnabled()).to.be(false); + await pageObjects.apiKeys.setApiKeyName(apiKeyName); + await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); + const newApiKeyCreation = await pageObjects.apiKeys.getNewApiKeyCreation(); - // Status should be displayed - const apiKeyStatus = await pageObjects.apiKeys.getFlyoutApiKeyStatus(); - expect(await apiKeyStatus).to.be('Active'); + expect(await browser.getCurrentUrl()).to.not.contain( + 'app/management/security/api_keys/create' + ); + expect(await browser.getCurrentUrl()).to.contain('app/management/security/api_keys'); + expect(await pageObjects.apiKeys.isApiKeyModalExists()).to.be(false); + expect(newApiKeyCreation).to.be(`Created API key '${apiKeyName}'`); - const apiKeyMetadataSwitch = await pageObjects.apiKeys.getMetadataSwitch(); - const apiKeyRestrictPrivilegesSwitch = - await pageObjects.apiKeys.getRestrictPrivilegesSwitch(); - - // Verify metadata and restrict privileges switches are now disabled - expect(await apiKeyMetadataSwitch.isEnabled()).to.be(false); - expect(await apiKeyRestrictPrivilegesSwitch.isEnabled()).to.be(false); - - await pageObjects.apiKeys.clickCancelButtonOnApiKeyFlyout(); - }); - }); - - describe('deletes API key(s)', function () { - before(async () => { - await security.testUser.setRoles(['kibana_admin', 'test_api_keys']); - await pageObjects.common.navigateToUrl('management', 'security/api_keys', { - shouldUseHashForSubUrl: false, - }); - }); - - beforeEach(async () => { - await pageObjects.apiKeys.clickOnPromptCreateApiKey(); - await pageObjects.apiKeys.setApiKeyName('api key 1'); - await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); - await ensureApiKeysExist(['api key 1']); - }); - - it('one by one', async () => { - await pageObjects.apiKeys.deleteAllApiKeyOneByOne(); - expect(await pageObjects.apiKeys.getApiKeysFirstPromptTitle()).to.be( - 'Create your first API key' - ); - }); - - it('by bulk', async () => { - await pageObjects.apiKeys.clickOnTableCreateApiKey(); - await pageObjects.apiKeys.setApiKeyName('api key 2'); - await pageObjects.apiKeys.clickSubmitButtonOnApiKeyFlyout(); - - // Make sure all API keys we want to delete are created and rendered. - await ensureApiKeysExist(['api key 1', 'api key 2']); - - await pageObjects.apiKeys.bulkDeleteApiKeys(); - expect(await pageObjects.apiKeys.getApiKeysFirstPromptTitle()).to.be( - 'Create your first API key' - ); - }); + await pageObjects.apiKeys.deleteAllApiKeyOneByOne(); }); }); }; diff --git a/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts b/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts index 4a8663666026c..1e32185187f8d 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/navigation.cy.ts @@ -5,7 +5,8 @@ * 2.0. */ -describe('Serverless', () => { +// Flaky in serverless tests +describe.skip('Serverless', () => { beforeEach(() => { cy.loginAsElasticUser(); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/observability_onboarding/home.cy.ts b/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/observability_onboarding/home.cy.ts index 7e74c75b62ebc..b0f95e0f66438 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/observability_onboarding/home.cy.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/cypress/e2e/observability_onboarding/home.cy.ts @@ -5,7 +5,8 @@ * 2.0. */ -describe('[Serverless Observability onboarding] Landing page', () => { +// Flaky in serverless tests +describe.skip('[Serverless Observability onboarding] Landing page', () => { beforeEach(() => { cy.loginAsElasticUser(); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/cypress/oblt_config.base.ts b/x-pack/test_serverless/functional/test_suites/observability/cypress/oblt_config.base.ts index 22bd611067f48..5508b8cd1a618 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/cypress/oblt_config.base.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/cypress/oblt_config.base.ts @@ -16,10 +16,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...svlSharedConfig.getAll(), esTestCluster: { ...svlSharedConfig.get('esTestCluster'), - serverArgs: [ - ...svlSharedConfig.get('esTestCluster.serverArgs'), - 'xpack.security.enabled=true', - ], + serverArgs: [...svlSharedConfig.get('esTestCluster.serverArgs')], }, kbnTestServer: { ...svlSharedConfig.get('kbnTestServer'), diff --git a/yarn.lock b/yarn.lock index a86858b1a6d53..47f2d2206ecd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2193,6 +2193,24 @@ resolved "https://registry.yarnpkg.com/@foliojs-fork/restructure/-/restructure-2.0.2.tgz#73759aba2aff1da87b7c4554e6839c70d43c92b4" integrity sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA== +"@frsource/base64@1.0.17": + version "1.0.17" + resolved "https://registry.yarnpkg.com/@frsource/base64/-/base64-1.0.17.tgz#b5a37e2ffab4f7fc9ef2e9f660dd3f38ccb05ff4" + integrity sha512-QyMv52jCRIMUIlDM6ysSVPc6Cp3KCTu6/YeLUyJpTEhleXssYB3CT5PqmQijGGwu4819qvan8Eu4PWJRAW5Akg== + +"@frsource/cypress-plugin-visual-regression-diff@^3.3.10": + version "3.3.10" + resolved "https://registry.yarnpkg.com/@frsource/cypress-plugin-visual-regression-diff/-/cypress-plugin-visual-regression-diff-3.3.10.tgz#f8c42d457409c4ac3868814085894db705026e97" + integrity sha512-ZjfOpdmXUgNRfLpsbrYiDujUzNEgLx+3dMtvMJHO3d+Yri0wniMB3mukf5+58QUMXuw8mr1cLoBkeWr1UxCOpA== + dependencies: + "@frsource/base64" "1.0.17" + glob "8.1.0" + meta-png "1.0.6" + move-file "2.1.0" + pixelmatch "5.3.0" + pngjs "7.0.0" + sharp "0.32.1" + "@gar/promisify@^1.0.1", "@gar/promisify@^1.1.3": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" @@ -5093,6 +5111,10 @@ version "0.0.0" uid "" +"@kbn/profiling-data-access-plugin@link:x-pack/plugins/profiling_data_access": + version "0.0.0" + uid "" + "@kbn/profiling-plugin@link:x-pack/plugins/profiling": version "0.0.0" uid "" @@ -5925,6 +5947,10 @@ version "0.0.0" uid "" +"@kbn/unified-data-table@link:packages/kbn-unified-data-table": + version "0.0.0" + uid "" + "@kbn/unified-field-list-examples-plugin@link:examples/unified_field_list_examples": version "0.0.0" uid "" @@ -17399,6 +17425,17 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + glob@^10.2.2: version "10.2.7" resolved "https://registry.yarnpkg.com/glob/-/glob-10.2.7.tgz#9dd2828cd5bc7bd861e7738d91e7113dda41d7d8" @@ -21787,6 +21824,11 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +meta-png@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/meta-png/-/meta-png-1.0.6.tgz#34d78a403cc1c809978d3e9f89485a2700daafce" + integrity sha512-eQtEi5E9axqwqA/sDK1dyhX9kYHCUe2m+45aQ3JHrozjGPs+/ab+hdhPp7A3GUNW+ZAbavrsg5xQ4r5jkGDX+A== + methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -22370,6 +22412,13 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +move-file@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/move-file/-/move-file-2.1.0.tgz#3bec9d34fbe4832df6865f112cda4492b56e8507" + integrity sha512-i9qLW6gqboJ5Ht8bauZi7KlTnQ3QFpBCvMvFfEcHADKgHGeJ9BZMO7SFCTwHPV9Qa0du9DYY1Yx3oqlGt30nXA== + dependencies: + path-exists "^4.0.0" + mri@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" @@ -23939,7 +23988,7 @@ piscina@^3.2.0: optionalDependencies: nice-napi "^1.0.2" -pixelmatch@^5.3.0: +pixelmatch@5.3.0, pixelmatch@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.3.0.tgz#5e5321a7abedfb7962d60dbf345deda87cb9560a" integrity sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q== @@ -24035,6 +24084,11 @@ png-js@^1.0.0: resolved "https://registry.yarnpkg.com/png-js/-/png-js-1.0.0.tgz#e5484f1e8156996e383aceebb3789fd75df1874d" integrity sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g== +pngjs@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26" + integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== + pngjs@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" @@ -27004,7 +27058,7 @@ shallowequal@^1.1.0: resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== -sharp@^0.32.0: +sharp@0.32.1, sharp@^0.32.0: version "0.32.1" resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.1.tgz#41aa0d0b2048b2e0ee453d9fcb14ec1f408390fe" integrity sha512-kQTFtj7ldpUqSe8kDxoGLZc1rnMFU0AO2pqbX6pLy3b7Oj8ivJIdoKNwxHVQG2HN6XpHPJqCSM2nsma2gOXvOg==