diff --git a/.buildkite/pipelines/pull_request/deploy_cloud.yml b/.buildkite/pipelines/pull_request/deploy_cloud.yml index 7185911953232..5306b4f0094bb 100644 --- a/.buildkite/pipelines/pull_request/deploy_cloud.yml +++ b/.buildkite/pipelines/pull_request/deploy_cloud.yml @@ -5,6 +5,7 @@ steps: queue: n2-2-spot depends_on: build timeout_in_minutes: 30 + soft_fail: true retry: automatic: - exit_status: '-1' diff --git a/.buildkite/scripts/common/setup_bazel.sh b/.buildkite/scripts/common/setup_bazel.sh index de381010b8aa3..a60543e36c941 100755 --- a/.buildkite/scripts/common/setup_bazel.sh +++ b/.buildkite/scripts/common/setup_bazel.sh @@ -11,7 +11,7 @@ cat < $KIBANA_DIR/.bazelrc build --build_metadata=ROLE=CI EOF -BAZEL_CACHE_MODE=${BAZEL_CACHE_MODE:-gcs} +BAZEL_CACHE_MODE=none if [[ "$BAZEL_CACHE_MODE" == "gcs" ]]; then echo "[bazel] enabling caching with GCS buckets" diff --git a/.buildkite/scripts/steps/artifacts/build.sh b/.buildkite/scripts/steps/artifacts/build.sh index 337d0289daa72..7c18dcb328a28 100644 --- a/.buildkite/scripts/steps/artifacts/build.sh +++ b/.buildkite/scripts/steps/artifacts/build.sh @@ -29,5 +29,6 @@ if [ -d .beats ]; then cd .beats buildkite-agent artifact upload 'metricbeat-*' buildkite-agent artifact upload 'filebeat-*' + buildkite-agent artifact upload 'beats_manifest.json' cd - fi diff --git a/.buildkite/scripts/steps/artifacts/cloud.sh b/.buildkite/scripts/steps/artifacts/cloud.sh index 4d2317ce0b6c7..16f280f68c539 100644 --- a/.buildkite/scripts/steps/artifacts/cloud.sh +++ b/.buildkite/scripts/steps/artifacts/cloud.sh @@ -7,31 +7,26 @@ set -euo pipefail source "$(dirname "$0")/../../common/util.sh" source .buildkite/scripts/steps/artifacts/env.sh -echo "--- Build and publish Cloud image" +echo "--- Push docker image" mkdir -p target -download_artifact "kibana-$FULL_VERSION-linux-x86_64.tar.gz" ./target --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" +download_artifact "kibana-cloud-$FULL_VERSION-docker-image.tar.gz" ./target --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" +docker load < "target/kibana-cloud-$FULL_VERSION-docker-image.tar.gz" TAG="$FULL_VERSION-$GIT_COMMIT" +KIBANA_BASE_IMAGE="docker.elastic.co/kibana-ci/kibana-cloud:$FULL_VERSION" KIBANA_TEST_IMAGE="docker.elastic.co/kibana-ci/kibana-cloud:$TAG" +# docker.elastic.co/kibana-ci/kibana-cloud:$FULL_VERSION -> :$FULL_VERSION-$GIT_COMMIT +docker tag "$KIBANA_BASE_IMAGE" "$KIBANA_TEST_IMAGE" + echo "$KIBANA_DOCKER_PASSWORD" | docker login -u "$KIBANA_DOCKER_USERNAME" --password-stdin docker.elastic.co trap 'docker logout docker.elastic.co' EXIT if docker manifest inspect $KIBANA_TEST_IMAGE &> /dev/null; then - echo "Distribution already exists, skipping build" + echo "Cloud image already exists, skipping docker push" else - node scripts/build \ - --skip-initialize \ - --skip-generic-folders \ - --skip-platform-folders \ - --skip-archives \ - --docker-images \ - --docker-tag-qualifier="$GIT_COMMIT" \ - --docker-push \ - --skip-docker-ubi \ - --skip-docker-ubuntu \ - --skip-docker-contexts + docker image push "$KIBANA_TEST_IMAGE" fi docker logout docker.elastic.co diff --git a/.buildkite/scripts/steps/artifacts/publish.sh b/.buildkite/scripts/steps/artifacts/publish.sh index 395a8196780d3..6b79841b7f830 100644 --- a/.buildkite/scripts/steps/artifacts/publish.sh +++ b/.buildkite/scripts/steps/artifacts/publish.sh @@ -58,6 +58,10 @@ if [[ "$BUILDKITE_BRANCH" == "$KIBANA_BASE_BRANCH" ]]; then export VAULT_ROLE_ID="$(retry 5 15 gcloud secrets versions access latest --secret=kibana-buildkite-vault-role-id)" export VAULT_SECRET_ID="$(retry 5 15 gcloud secrets versions access latest --secret=kibana-buildkite-vault-secret-id)" export VAULT_ADDR="https://secrets.elastic.co:8200" + + download_artifact beats_manifest.json /tmp --build "${KIBANA_BUILD_ID:-$BUILDKITE_BUILD_ID}" + export BEATS_MANIFEST_URL=$(jq -r .manifest_url /tmp/beats_manifest.json) + docker run --rm \ --name release-manager \ -e VAULT_ADDR \ @@ -72,6 +76,7 @@ if [[ "$BUILDKITE_BRANCH" == "$KIBANA_BASE_BRANCH" ]]; then --workflow "$WORKFLOW" \ --version "$BASE_VERSION" \ --qualifier "$VERSION_QUALIFIER" \ + --dependency "beats:$BEATS_MANIFEST_URL" \ --artifact-set main ARTIFACTS_SUBDOMAIN="artifacts-$WORKFLOW" diff --git a/.buildkite/scripts/steps/functional/apm_cypress.sh b/.buildkite/scripts/steps/functional/apm_cypress.sh index 77b26fafee920..04f9aee280429 100755 --- a/.buildkite/scripts/steps/functional/apm_cypress.sh +++ b/.buildkite/scripts/steps/functional/apm_cypress.sh @@ -4,6 +4,8 @@ set -euo pipefail source .buildkite/scripts/common/util.sh +APM_CYPRESS_RECORD_KEY="$(retry 5 5 vault read -field=CYPRESS_RECORD_KEY secret/kibana-issues/dev/apm-cypress-dashboard-record-key)" + .buildkite/scripts/bootstrap.sh .buildkite/scripts/download_build_artifacts.sh @@ -15,4 +17,6 @@ cd "$XPACK_DIR" checks-reporter-with-killswitch "APM Cypress Tests" \ node plugins/apm/scripts/test/e2e.js \ - --kibana-install-dir "$KIBANA_BUILD_LOCATION" + --kibana-install-dir "$KIBANA_BUILD_LOCATION" \ + --record \ + --key "$APM_CYPRESS_RECORD_KEY" diff --git a/.buildkite/scripts/steps/lint.sh b/.buildkite/scripts/steps/lint.sh index 8c6a2e2e6202a..301737c9132a0 100755 --- a/.buildkite/scripts/steps/lint.sh +++ b/.buildkite/scripts/steps/lint.sh @@ -16,9 +16,9 @@ echo '--- Lint: eslint' # after possibly commiting fixed files to the repo set +e; if is_pr && ! is_auto_commit_disabled; then - git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 6 node scripts/eslint --no-cache --fix + git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 4 node scripts/eslint --no-cache --fix else - git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 6 node scripts/eslint --no-cache + git ls-files | grep -E '\.(js|mjs|ts|tsx)$' | xargs -n 250 -P 4 node scripts/eslint --no-cache fi eslint_exit=$? diff --git a/.buildkite/scripts/steps/storybooks/build_and_upload.ts b/.buildkite/scripts/steps/storybooks/build_and_upload.ts index dcceca7848910..945f85a820971 100644 --- a/.buildkite/scripts/steps/storybooks/build_and_upload.ts +++ b/.buildkite/scripts/steps/storybooks/build_and_upload.ts @@ -15,7 +15,7 @@ const STORYBOOKS = [ 'apm', 'canvas', 'ci_composite', - 'cloud', + 'cloud_chat', 'coloring', 'chart_icons', 'controls', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b7d588bc89269..17e8a0f1b4d4b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -332,11 +332,15 @@ x-pack/examples/files_example @elastic/kibana-app-services /x-pack/plugins/event_log/ @elastic/response-ops /x-pack/plugins/task_manager/ @elastic/response-ops /x-pack/plugins/stack_connectors/ @elastic/response-ops -/x-pack/plugins/stack_connectors/public/connector_types/stack/ @elastic/response-ops-execution -/x-pack/plugins/stack_connectors/server/connector_types/stack/ @elastic/response-ops-execution -/x-pack/plugins/stack_connectors/public/connector_types/cases/ @elastic/response-ops-cases -/x-pack/plugins/stack_connectors/server/connector_types/cases/ @elastic/response-ops-cases +/x-pack/plugins/stack_connectors/public/connector_types/stack/ @elastic/response-ops @elastic/response-ops-execution +/x-pack/plugins/stack_connectors/server/connector_types/stack/ @elastic/response-ops @elastic/response-ops-execution +/x-pack/plugins/stack_connectors/public/connector_types/cases/ @elastic/response-ops @elastic/response-ops-cases +/x-pack/plugins/stack_connectors/server/connector_types/cases/ @elastic/response-ops @elastic/response-ops-cases /x-pack/test/alerting_api_integration/ @elastic/response-ops +/x-pack/test/alerting_api_integration/basic/tests/actions/connector_types/stack/ @elastic/response-ops @elastic/response-ops-execution +/x-pack/test/alerting_api_integration/basic/tests/actions/connector_types/cases/ @elastic/response-ops @elastic/response-ops-cases +/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/stack/ @elastic/response-ops @elastic/response-ops-execution +/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/actions/connector_types/cases/ @elastic/response-ops @elastic/response-ops-cases /x-pack/test/plugin_api_integration/test_suites/task_manager/ @elastic/response-ops /x-pack/plugins/triggers_actions_ui/ @elastic/response-ops /x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/response-ops @@ -504,6 +508,11 @@ x-pack/examples/files_example @elastic/kibana-app-services /x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet @elastic/security-detections-response-rules /x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules @elastic/security-detections-response-rules +/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rule_exceptions_route* @elastic/security-solution-platform +/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/find_rule_exceptions_route* @elastic/security-solution-platform +/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route* @elastic/security-solution-platform +/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route* @elastic/security-detections-response-alerts +/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils @elastic/security-solution-platform /x-pack/plugins/security_solution/server/lib/detection_engine/routes/tags @elastic/security-detections-response-rules /x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring @elastic/security-detections-response-rules /x-pack/plugins/security_solution/server/lib/detection_engine/rules @elastic/security-detections-response-rules @@ -745,6 +754,9 @@ packages/core/http/core-http-context-server-internal @elastic/kibana-core packages/core/http/core-http-context-server-mocks @elastic/kibana-core packages/core/http/core-http-request-handler-context-server @elastic/kibana-core packages/core/http/core-http-request-handler-context-server-internal @elastic/kibana-core +packages/core/http/core-http-resources-server @elastic/kibana-core +packages/core/http/core-http-resources-server-internal @elastic/kibana-core +packages/core/http/core-http-resources-server-mocks @elastic/kibana-core packages/core/http/core-http-router-server-internal @elastic/kibana-core packages/core/http/core-http-router-server-mocks @elastic/kibana-core packages/core/http/core-http-server @elastic/kibana-core @@ -821,6 +833,7 @@ packages/core/status/core-status-server-internal @elastic/kibana-core packages/core/status/core-status-server-mocks @elastic/kibana-core packages/core/test-helpers/core-test-helpers-deprecations-getters @elastic/kibana-core packages/core/test-helpers/core-test-helpers-http-setup-browser @elastic/kibana-core +packages/core/test-helpers/core-test-helpers-so-type-serializer @elastic/kibana-core packages/core/theme/core-theme-browser @elastic/kibana-core packages/core/theme/core-theme-browser-internal @elastic/kibana-core packages/core/theme/core-theme-browser-mocks @elastic/kibana-core diff --git a/api_docs/actions.devdocs.json b/api_docs/actions.devdocs.json index cefd0ffd4d6b1..c20f6e15fb966 100644 --- a/api_docs/actions.devdocs.json +++ b/api_docs/actions.devdocs.json @@ -741,13 +741,9 @@ "label": "request", "description": [], "signature": [ - "({ url, data, method, responseSchema, headers, ...config }: { url: string; responseSchema: ", - "Type", - "; method?: ", - "Method", - " | undefined; } & ", - "AxiosRequestConfig", - ") => Promise<", + "({ url, data, method, responseSchema, headers, ...config }: ", + "SubActionRequestParams", + ") => Promise<", "AxiosResponse", ">" ], @@ -763,13 +759,8 @@ "label": "{\n url,\n data,\n method = 'get',\n responseSchema,\n headers,\n ...config\n }", "description": [], "signature": [ - "{ url: string; responseSchema: ", - "Type", - "; method?: ", - "Method", - " | undefined; } & ", - "AxiosRequestConfig", - "" + "SubActionRequestParams", + "" ], "path": "x-pack/plugins/actions/server/sub_action_framework/sub_action_connector.ts", "deprecated": false, @@ -858,6 +849,41 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "actions", + "id": "def-server.urlAllowListValidator", + "type": "Function", + "tags": [], + "label": "urlAllowListValidator", + "description": [], + "signature": [ + "(urlKey: string) => (obj: T, validatorServices: ", + "ValidatorServices", + ") => void" + ], + "path": "x-pack/plugins/actions/server/sub_action_framework/helpers/validators.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "actions", + "id": "def-server.urlAllowListValidator.$1", + "type": "string", + "tags": [], + "label": "urlKey", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/actions/server/sub_action_framework/helpers/validators.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [ @@ -1191,7 +1217,13 @@ "label": "validate", "description": [], "signature": [ - "{ params?: ValidatorType | undefined; config?: ValidatorType | undefined; secrets?: ValidatorType | undefined; connector?: ((config: Config, secrets: Secrets) => string | null) | undefined; } | undefined" + "{ params?: ", + "ValidatorType", + " | undefined; config?: ", + "ValidatorType", + " | undefined; secrets?: ", + "ValidatorType", + " | undefined; connector?: ((config: Config, secrets: Secrets) => string | null) | undefined; } | undefined" ], "path": "x-pack/plugins/actions/server/types.ts", "deprecated": false, @@ -1205,59 +1237,12 @@ "label": "renderParameterTemplates", "description": [], "signature": [ - "((params: Params, variables: Record, actionId?: string | undefined) => Params) | undefined" + "RenderParameterTemplates", + " | undefined" ], "path": "x-pack/plugins/actions/server/types.ts", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "actions", - "id": "def-server.ActionType.renderParameterTemplates.$1", - "type": "Uncategorized", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "Params" - ], - "path": "x-pack/plugins/actions/server/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "actions", - "id": "def-server.ActionType.renderParameterTemplates.$2", - "type": "Object", - "tags": [], - "label": "variables", - "description": [], - "signature": [ - "Record" - ], - "path": "x-pack/plugins/actions/server/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "actions", - "id": "def-server.ActionType.renderParameterTemplates.$3", - "type": "string", - "tags": [], - "label": "actionId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/actions/server/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "actions", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index 8c70634191ac9..c8022a3dc8f13 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Response Ops](https://github.com/orgs/elastic/teams/response-ops) for q | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 214 | 0 | 209 | 19 | +| 213 | 0 | 208 | 23 | ## Client diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 5f708b7bd5b22..db45d8b0ccf58 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: 2022-10-03 +date: 2022-10-06 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 affc8c08a679c..7df3eeb961b09 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.devdocs.json b/api_docs/alerting.devdocs.json index 9971fcee0a58a..cf275b4f7fda8 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -551,9 +551,9 @@ ", filterOpts: ", "AlertingAuthorizationFilterOpts", ") => Promise<{ filter?: ", - "KueryNode", - " | ", "JsonObject", + " | ", + "KueryNode", " | undefined; ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void; }>" ], "path": "x-pack/plugins/alerting/server/authorization/alerting_authorization.ts", @@ -634,9 +634,9 @@ "text": "WriteOperations" }, ") => Promise<{ filter?: ", - "KueryNode", - " | ", "JsonObject", + " | ", + "KueryNode", " | undefined; ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void; }>" ], "path": "x-pack/plugins/alerting/server/authorization/alerting_authorization.ts", @@ -2782,7 +2782,7 @@ "section": "def-common.RuleTypeParams", "text": "RuleTypeParams" }, - " = never>({ id, includeLegacyId, }: { id: string; includeLegacyId?: boolean | undefined; }) => Promise<", + " = never>({ id, includeLegacyId, includeSnoozeData, }: { id: string; includeLegacyId?: boolean | undefined; includeSnoozeData?: boolean | undefined; }) => Promise<", { "pluginId": "alerting", "scope": "common", @@ -5085,7 +5085,7 @@ "label": "status", "description": [], "signature": [ - "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"ok\" | \"active\"" + "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"active\" | \"ok\"" ], "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, @@ -6055,7 +6055,7 @@ "label": "RuleExecutionStatuses", "description": [], "signature": [ - "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"ok\" | \"active\"" + "\"error\" | \"warning\" | \"unknown\" | \"pending\" | \"active\" | \"ok\"" ], "path": "x-pack/plugins/alerting/common/rule.ts", "deprecated": false, diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index dba2b5b8a03fa..e5cbe70302b94 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index e327d3d9ef266..e7c08ef112a82 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index 8465fcc62bbbe..143b086150408 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.devdocs.json b/api_docs/bfetch.devdocs.json index f060159bc0f3a..32dbe24517f93 100644 --- a/api_docs/bfetch.devdocs.json +++ b/api_docs/bfetch.devdocs.json @@ -370,7 +370,9 @@ "IRouter", "<", "RequestHandlerContext", - "> | undefined) => void" + "> | undefined, options?: ", + "RouteConfigOptions", + "<\"get\" | \"post\" | \"put\" | \"delete\"> | undefined) => void" ], "path": "src/plugins/bfetch/server/plugin.ts", "deprecated": false, @@ -450,6 +452,22 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "bfetch", + "id": "def-server.BfetchServerSetup.addStreamingResponseRoute.$5", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "RouteConfigOptions", + "<\"get\" | \"post\" | \"put\" | \"delete\"> | undefined" + ], + "path": "src/plugins/bfetch/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [] diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index b4d39167b8afc..415ab28433c84 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 80 | 1 | 71 | 2 | +| 81 | 1 | 72 | 2 | ## Client diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 964d7c080f50e..78001f970e6af 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 1b56bb9f2bb5a..4bdb21a16e58f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index 5971c6140b9d0..2195dc276c86e 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.devdocs.json b/api_docs/cloud.devdocs.json index 97aac894f3a0e..89134783e726f 100644 --- a/api_docs/cloud.devdocs.json +++ b/api_docs/cloud.devdocs.json @@ -2,27 +2,7 @@ "id": "cloud", "client": { "classes": [], - "functions": [ - { - "parentPluginId": "cloud", - "id": "def-public.Chat", - "type": "Function", - "tags": [], - "label": "Chat", - "description": [ - "\nA lazily-loaded component that will display a trigger that will allow the user to chat with a\nhuman operator when the service is enabled; otherwise, it renders nothing." - ], - "signature": [ - "() => JSX.Element" - ], - "path": "x-pack/plugins/cloud/public/components/index.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [], - "initialIsOpen": false - } - ], + "functions": [], "interfaces": [ { "parentPluginId": "cloud", @@ -132,22 +112,6 @@ "path": "x-pack/plugins/cloud/public/plugin.tsx", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "cloud", - "id": "def-public.CloudConfigType.chat", - "type": "Object", - "tags": [], - "label": "chat", - "description": [ - "Configuration to enable live chat in Cloud-enabled instances of Kibana." - ], - "signature": [ - "{ enabled: boolean; chatURL: string; }" - ], - "path": "x-pack/plugins/cloud/public/plugin.tsx", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false @@ -209,6 +173,83 @@ "trackAdoption": false } ] + }, + { + "parentPluginId": "cloud", + "id": "def-public.CloudStart.isCloudEnabled", + "type": "boolean", + "tags": [], + "label": "isCloudEnabled", + "description": [ + "\n`true` when Kibana is running on Elastic Cloud." + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cloud", + "id": "def-public.CloudStart.cloudId", + "type": "string", + "tags": [], + "label": "cloudId", + "description": [ + "\nCloud ID. Undefined if not running on Cloud." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cloud", + "id": "def-public.CloudStart.deploymentUrl", + "type": "string", + "tags": [], + "label": "deploymentUrl", + "description": [ + "\nThe full URL to the deployment management page on Elastic Cloud. Undefined if not running on Cloud." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cloud", + "id": "def-public.CloudStart.profileUrl", + "type": "string", + "tags": [], + "label": "profileUrl", + "description": [ + "\nThe full URL to the user profile page on Elastic Cloud. Undefined if not running on Cloud." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "cloud", + "id": "def-public.CloudStart.organizationUrl", + "type": "string", + "tags": [], + "label": "organizationUrl", + "description": [ + "\nThe full URL to the organization management page on Elastic Cloud. Undefined if not running on Cloud." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -336,6 +377,38 @@ "path": "x-pack/plugins/cloud/public/plugin.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "cloud", + "id": "def-public.CloudSetup.registerCloudService", + "type": "Function", + "tags": [], + "label": "registerCloudService", + "description": [], + "signature": [ + "(contextProvider: React.FC<{}>) => void" + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "cloud", + "id": "def-public.CloudSetup.registerCloudService.$1", + "type": "Function", + "tags": [], + "label": "contextProvider", + "description": [], + "signature": [ + "React.FC<{}>" + ], + "path": "x-pack/plugins/cloud/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "lifecycle": "setup", diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 07a722e9fc63c..f822ee3265a60 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; @@ -21,16 +21,13 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 29 | 0 | 24 | 0 | +| 34 | 0 | 26 | 0 | ## Client ### Setup -### Functions - - ### Interfaces diff --git a/api_docs/cloud_chat.devdocs.json b/api_docs/cloud_chat.devdocs.json new file mode 100644 index 0000000000000..a5c0e8eb90ccd --- /dev/null +++ b/api_docs/cloud_chat.devdocs.json @@ -0,0 +1,47 @@ +{ + "id": "cloudChat", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "cloudChat", + "id": "def-public.Chat", + "type": "Function", + "tags": [], + "label": "Chat", + "description": [ + "\nA lazily-loaded component that will display a trigger that will allow the user to chat with a\nhuman operator when the service is enabled; otherwise, it renders nothing." + ], + "signature": [ + "() => JSX.Element" + ], + "path": "x-pack/plugins/cloud_integrations/cloud_chat/public/components/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/cloud_chat.mdx b/api_docs/cloud_chat.mdx new file mode 100644 index 0000000000000..e96d47434b297 --- /dev/null +++ b/api_docs/cloud_chat.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibCloudChatPluginApi +slug: /kibana-dev-docs/api/cloudChat +title: "cloudChat" +image: https://source.unsplash.com/400x175/?github +description: API docs for the cloudChat plugin +date: 2022-10-06 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudChat'] +--- +import cloudChatObj from './cloud_chat.devdocs.json'; + +Chat available on Elastic Cloud deployments for quicker assistance. + +Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 1 | 0 | 0 | 0 | + +## Client + +### Functions + + diff --git a/api_docs/cloud_experiments.devdocs.json b/api_docs/cloud_experiments.devdocs.json index 0f827e35ec52a..d08957de16642 100644 --- a/api_docs/cloud_experiments.devdocs.json +++ b/api_docs/cloud_experiments.devdocs.json @@ -94,119 +94,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "cloudExperiments", - "id": "def-common.CloudExperimentsPluginSetup", - "type": "Interface", - "tags": [], - "label": "CloudExperimentsPluginSetup", - "description": [ - "\nThe contract of the setup lifecycle method.\n" - ], - "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "cloudExperiments", - "id": "def-common.CloudExperimentsPluginSetup.identifyUser", - "type": "Function", - "tags": [ - "deprecated" - ], - "label": "identifyUser", - "description": [ - "\nIdentifies the user in the A/B testing service.\nFor now, we only rely on the user ID. In the future, we may request further details for more targeted experiments." - ], - "signature": [ - "(userId: string, userMetadata?: Record | undefined) => void" - ], - "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", - "deprecated": true, - "trackAdoption": false, - "references": [ - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.tsx" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/server/plugin.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/server/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/server/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/server/plugin.test.ts" - }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/server/plugin.test.ts" - } - ], - "children": [ - { - "parentPluginId": "cloudExperiments", - "id": "def-common.CloudExperimentsPluginSetup.identifyUser.$1", - "type": "string", - "tags": [], - "label": "userId", - "description": [ - "The unique identifier of the user in the experiment." - ], - "signature": [ - "string" - ], - "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "cloudExperiments", - "id": "def-common.CloudExperimentsPluginSetup.identifyUser.$2", - "type": "Object", - "tags": [], - "label": "userMetadata", - "description": [ - "Additional attributes to the user. Take care to ensure these values do not contain PII." - ], - "signature": [ - "Record | undefined" - ], - "path": "x-pack/plugins/cloud_integrations/cloud_experiments/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, { "parentPluginId": "cloudExperiments", "id": "def-common.CloudExperimentsPluginStart", diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index 8cb19bfe8beb9..5e5d6c0623095 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/@elastic/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 0 | 0 | +| 12 | 0 | 0 | 0 | ## Common diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 6c31131981413..258d23dc4e05b 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: 2022-10-03 +date: 2022-10-06 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 69717a2855de0..830b195a50b76 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index d120725ebf6c3..e5fa584a95d47 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/core.devdocs.json b/api_docs/core.devdocs.json index 67fa46292601f..197b485695674 100644 --- a/api_docs/core.devdocs.json +++ b/api_docs/core.devdocs.json @@ -907,8 +907,8 @@ "path": "x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.tsx" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.ts" }, { "plugin": "telemetry", @@ -979,44 +979,44 @@ "path": "packages/core/status/core-status-server-internal/src/status_service.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { "plugin": "@kbn/core-analytics-browser-mocks", @@ -10930,14 +10930,6 @@ "plugin": "graph", "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts" - }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/saved_object.test.ts" @@ -14790,6 +14782,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/app/app.tsx" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts" + }, { "plugin": "@kbn/core-application-browser-internal", "path": "packages/core/application/core-application-browser-internal/src/ui/app_container.tsx" @@ -15374,7 +15374,11 @@ "SavedObjectsFindOptionsReference", " | ", "SavedObjectsFindOptionsReference", - "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; preference?: string | undefined; }" + "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; hasNoReference?: ", + "SavedObjectsFindOptionsReference", + " | ", + "SavedObjectsFindOptionsReference", + "[] | undefined; hasNoReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; preference?: string | undefined; }" ], "path": "node_modules/@types/kbn__core-saved-objects-api-browser/index.d.ts", "deprecated": false, @@ -19658,8 +19662,8 @@ "path": "x-pack/plugins/cloud/common/register_cloud_deployment_id_analytics_context.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.tsx" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.ts" }, { "plugin": "telemetry", @@ -19730,44 +19734,44 @@ "path": "packages/core/status/core-status-server-internal/src/status_service.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.test.ts" + "plugin": "security", + "path": "x-pack/plugins/security/public/analytics/register_user_context.test.ts" }, { "plugin": "@kbn/core-analytics-browser-mocks", @@ -21813,13 +21817,7 @@ "<", "RequestHandlerContext", "> & { resources: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResources", - "text": "HttpResources" - }, + "HttpResources", "; }" ], "path": "src/core/server/index.ts", @@ -25938,7 +25936,10 @@ "description": [ "\nHttpResources service is responsible for serving static & dynamic assets for Kibana application via HTTP.\nProvides API allowing plug-ins to respond with:\n- a pre-configured HTML page bootstrapping Kibana client app\n- custom HTML page\n- custom JS script file." ], - "path": "src/core/server/http_resources/types.ts", + "signature": [ + "HttpResources" + ], + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -25959,16 +25960,10 @@ ">(route: ", "RouteConfig", ", handler: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesRequestHandler", - "text": "HttpResourcesRequestHandler" - }, + "HttpResourcesRequestHandler", ") => void" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -25983,7 +25978,7 @@ "RouteConfig", "" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -25996,16 +25991,10 @@ "label": "handler", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesRequestHandler", - "text": "HttpResourcesRequestHandler" - }, + "HttpResourcesRequestHandler", "" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -26025,7 +26014,10 @@ "description": [ "\nAllows to configure HTTP response parameters" ], - "path": "src/core/server/http_resources/types.ts", + "signature": [ + "HttpResourcesRenderOptions" + ], + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -26042,7 +26034,7 @@ "ResponseHeaders", " | undefined" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false } @@ -26058,7 +26050,10 @@ "description": [ "\nExtended set of {@link KibanaResponseFactory} helpers used to respond with HTML or JS resource." ], - "path": "src/core/server/http_resources/types.ts", + "signature": [ + "HttpResourcesServiceToolkit" + ], + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -26073,18 +26068,12 @@ ], "signature": [ "(options?: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesRenderOptions", - "text": "HttpResourcesRenderOptions" - }, + "HttpResourcesRenderOptions", " | undefined) => Promise<", "IKibanaResponse", ">" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -26096,16 +26085,10 @@ "label": "options", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesRenderOptions", - "text": "HttpResourcesRenderOptions" - }, + "HttpResourcesRenderOptions", " | undefined" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": false @@ -26124,18 +26107,12 @@ ], "signature": [ "(options?: ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesRenderOptions", - "text": "HttpResourcesRenderOptions" - }, + "HttpResourcesRenderOptions", " | undefined) => Promise<", "IKibanaResponse", ">" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -26147,16 +26124,10 @@ "label": "options", "description": [], "signature": [ - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesRenderOptions", - "text": "HttpResourcesRenderOptions" - }, + "HttpResourcesRenderOptions", " | undefined" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": false @@ -26180,7 +26151,7 @@ "IKibanaResponse", "" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -26194,7 +26165,7 @@ "signature": [ "HttpResponseOptions" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -26218,7 +26189,7 @@ "IKibanaResponse", "" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -26232,7 +26203,7 @@ "signature": [ "HttpResponseOptions" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -29385,36 +29356,6 @@ ], "initialIsOpen": false }, - { - "parentPluginId": "core", - "id": "def-server.IRenderOptions", - "type": "Interface", - "tags": [], - "label": "IRenderOptions", - "description": [], - "path": "src/core/server/rendering/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "core", - "id": "def-server.IRenderOptions.isAnonymousPage", - "type": "CompoundType", - "tags": [], - "label": "isAnonymousPage", - "description": [ - "\nSet whether the page is anonymous, which determines what plugins are enabled and whether to output user settings in the page metadata.\n`false` by default." - ], - "signature": [ - "boolean | undefined" - ], - "path": "src/core/server/rendering/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "core", "id": "def-server.IRouter", @@ -36904,6 +36845,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "core", + "id": "def-server.OpsMetrics.elasticsearch_client", + "type": "Object", + "tags": [], + "label": "elasticsearch_client", + "description": [ + "\nMetrics related to the elasticsearch client" + ], + "signature": [ + "ElasticsearchClientsMetrics" + ], + "path": "node_modules/@types/kbn__core-metrics-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "core", "id": "def-server.OpsMetrics.process", @@ -40612,14 +40569,6 @@ "plugin": "graph", "path": "x-pack/plugins/graph/public/helpers/saved_workspace_utils.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts" - }, { "plugin": "savedObjects", "path": "src/plugins/saved_objects/public/saved_object/saved_object.test.ts" @@ -44338,6 +44287,41 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsFindOptions.hasNoReference", + "type": "CompoundType", + "tags": [], + "label": "hasNoReference", + "description": [ + "\nSearch for documents *not* having a reference to the specified objects.\nUse `hasNoReferenceOperator` to specify the operator to use when searching for multiple references." + ], + "signature": [ + "SavedObjectsFindOptionsReference", + " | ", + "SavedObjectsFindOptionsReference", + "[] | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-api-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "core", + "id": "def-server.SavedObjectsFindOptions.hasNoReferenceOperator", + "type": "CompoundType", + "tags": [], + "label": "hasNoReferenceOperator", + "description": [ + "\nThe operator to use when searching by multiple references using the `hasNoReference` option. Defaults to `OR`" + ], + "signature": [ + "\"AND\" | \"OR\" | undefined" + ], + "path": "node_modules/@types/kbn__core-saved-objects-api-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "core", "id": "def-server.SavedObjectsFindOptions.defaultSearchOperator", @@ -51918,20 +51902,14 @@ "): ", "IKibanaResponse", "; } & ", - { - "pluginId": "core", - "scope": "server", - "docId": "kibCorePluginApi", - "section": "def-server.HttpResourcesServiceToolkit", - "text": "HttpResourcesServiceToolkit" - }, + "HttpResourcesServiceToolkit", ") => ", "IKibanaResponse", " | Promise<", "IKibanaResponse", ">" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "returnComment": [], @@ -52000,7 +51978,7 @@ "signature": [ "HttpResponseOptions" ], - "path": "src/core/server/http_resources/types.ts", + "path": "node_modules/@types/kbn__core-http-resources-server/index.d.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -53721,7 +53699,11 @@ "SavedObjectsFindOptionsReference", " | ", "SavedObjectsFindOptionsReference", - "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; }" + "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; hasNoReference?: ", + "SavedObjectsFindOptionsReference", + " | ", + "SavedObjectsFindOptionsReference", + "[] | undefined; hasNoReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; }" ], "path": "node_modules/@types/kbn__core-saved-objects-api-server/index.d.ts", "deprecated": false, @@ -53974,10 +53956,9 @@ "\n A user credentials container.\nIt accommodates the necessary auth credentials to impersonate the current user.\n" ], "signature": [ - "FakeRequest", - " | ", "KibanaRequest", - "" + " | ", + "FakeRequest" ], "path": "node_modules/@types/kbn__core-elasticsearch-server/index.d.ts", "deprecated": false, diff --git a/api_docs/core.mdx b/api_docs/core.mdx index 2ce73b73214aa..a1e985bca2c7e 100644 --- a/api_docs/core.mdx +++ b/api_docs/core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/core title: "core" image: https://source.unsplash.com/400x175/?github description: API docs for the core plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'core'] --- import coreObj from './core.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) for que | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 2688 | 0 | 30 | 0 | +| 2689 | 0 | 23 | 0 | ## Client diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index c9bd9c16e7214..b142fb34cfb66 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: 2022-10-03 +date: 2022-10-06 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 7fa93934def07..86181c9b1b96f 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: 2022-10-03 +date: 2022-10-06 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 4f0b134f643ca..1c3208091d7d7 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: 2022-10-03 +date: 2022-10-06 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 10ca74caf4ce6..33d5834e2191a 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -2588,7 +2588,7 @@ "description": [], "signature": [ "PluginInitializerContext", - "; }>; sessions: Readonly<{} & { enabled: boolean; pageSize: number; trackingInterval: moment.Duration; cleanupInterval: moment.Duration; expireInterval: moment.Duration; monitoringTaskTimeout: moment.Duration; notTouchedTimeout: moment.Duration; notTouchedInProgressTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" + "; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" ], "path": "src/plugins/data/public/plugin.ts", "deprecated": false, @@ -7523,6 +7523,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-public.IKibanaSearchResponse.isStored", + "type": "CompoundType", + "tags": [], + "label": "isStored", + "description": [ + "\nIndicates whether the search has been saved to a search-session object and long keepAlive was set" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-public.IKibanaSearchResponse.warning", @@ -7649,6 +7665,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-public.ISearchOptions.isSearchStored", + "type": "CompoundType", + "tags": [], + "label": "isSearchStored", + "description": [ + "\nWhether the search was successfully polled after session was saved. Search was added to a session saved object and keepAlive extended." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-public.ISearchOptions.isRestore", @@ -11748,7 +11780,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; }>; sessions: Readonly<{} & { enabled: boolean; pageSize: number; trackingInterval: moment.Duration; cleanupInterval: moment.Duration; expireInterval: moment.Duration; monitoringTaskTimeout: moment.Duration; notTouchedTimeout: moment.Duration; notTouchedInProgressTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" + "; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>>" ], "path": "src/plugins/data/server/plugin.ts", "deprecated": false, @@ -17029,6 +17061,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-server.ISearchOptions.isSearchStored", + "type": "CompoundType", + "tags": [], + "label": "isSearchStored", + "description": [ + "\nWhether the search was successfully polled after session was saved. Search was added to a session saved object and keepAlive extended." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-server.ISearchOptions.isRestore", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 3cda1cdf63de6..eea73f4aaae1d 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3213 | 33 | 2509 | 23 | +| 3221 | 33 | 2513 | 24 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 09c0ef0d696bf..ad2475ad665e9 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3213 | 33 | 2509 | 23 | +| 3221 | 33 | 2513 | 24 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 3be2133617864..08d6314c52ffe 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -208,7 +208,9 @@ "Observable", "<", "SessionMeta", - ">; hasAccess: () => boolean; trackSearch: (searchDescriptor: TrackSearchDescriptor) => () => void; getSessionId: () => string | undefined; getSession$: () => ", + ">; readonly disableSaveAfterSearchesExpire$: ", + "Observable", + "; hasAccess: () => boolean; trackSearch: (searchDescriptor: TrackSearchDescriptor) => TrackSearchHandler; getSessionId: () => string | undefined; getSession$: () => ", "Observable", "; isStored: () => boolean; isRestore: () => boolean; restore: (sessionId: string) => void; continue: (sessionId: string) => void; clear: () => void; cancel: () => Promise; renameCurrentSession: (newName: string) => Promise; isCurrentSession: (sessionId?: string | undefined) => boolean; getSearchOptions: (sessionId?: string | undefined) => Required; find: (options: Omit<", "SavedObjectsFindOptions", ", \"type\">) => Promise<", - "SavedObjectsFindResponse", - ">; update: (sessionId: string, attributes: unknown) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" + }, + ">; update: (sessionId: string, attributes: unknown) => Promise<", "SavedObjectsUpdateResponse", "<", { @@ -638,7 +646,9 @@ "Observable", "<", "SessionMeta", - ">; hasAccess: () => boolean; trackSearch: (searchDescriptor: TrackSearchDescriptor) => () => void; getSessionId: () => string | undefined; getSession$: () => ", + ">; readonly disableSaveAfterSearchesExpire$: ", + "Observable", + "; hasAccess: () => boolean; trackSearch: (searchDescriptor: TrackSearchDescriptor) => TrackSearchHandler; getSessionId: () => string | undefined; getSession$: () => ", "Observable", "; isStored: () => boolean; isRestore: () => boolean; restore: (sessionId: string) => void; continue: (sessionId: string) => void; clear: () => void; cancel: () => Promise; renameCurrentSession: (newName: string) => Promise; isCurrentSession: (sessionId?: string | undefined) => boolean; getSearchOptions: (sessionId?: string | undefined) => Required; find: (options: Omit<", "SavedObjectsFindOptions", ", \"type\">) => Promise<", - "SavedObjectsFindResponse", - ">; update: (sessionId: string, attributes: unknown) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" + }, + ">; update: (sessionId: string, attributes: unknown) => Promise<", "SavedObjectsUpdateResponse", "<", { @@ -1228,8 +1244,14 @@ ">; find: (options: Omit<", "SavedObjectsFindOptions", ", \"type\">) => Promise<", - "SavedObjectsFindResponse", - ">; update: (sessionId: string, attributes: unknown) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" + }, + ">; update: (sessionId: string, attributes: unknown) => Promise<", "SavedObjectsUpdateResponse", "<", { @@ -1288,7 +1310,9 @@ "Observable", "<", "SessionMeta", - ">; hasAccess: () => boolean; trackSearch: (searchDescriptor: TrackSearchDescriptor) => () => void; getSessionId: () => string | undefined; getSession$: () => ", + ">; readonly disableSaveAfterSearchesExpire$: ", + "Observable", + "; hasAccess: () => boolean; trackSearch: (searchDescriptor: TrackSearchDescriptor) => TrackSearchHandler; getSessionId: () => string | undefined; getSession$: () => ", "Observable", "; isStored: () => boolean; isRestore: () => boolean; restore: (sessionId: string) => void; continue: (sessionId: string) => void; clear: () => void; cancel: () => Promise; renameCurrentSession: (newName: string) => Promise; isCurrentSession: (sessionId?: string | undefined) => boolean; getSearchOptions: (sessionId?: string | undefined) => Required; }>; sessions: Readonly<{} & { enabled: boolean; pageSize: number; trackingInterval: moment.Duration; cleanupInterval: moment.Duration; expireInterval: moment.Duration; monitoringTaskTimeout: moment.Duration; notTouchedTimeout: moment.Duration; notTouchedInProgressTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>" + "Readonly<{} & { search: Readonly<{} & { aggs: Readonly<{} & { shardDelay: Readonly<{} & { enabled: boolean; }>; }>; sessions: Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }>; }>" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -1564,7 +1588,7 @@ "section": "def-server.CoreStart", "text": "CoreStart" }, - ", deps: StartDependencies) => Promise" + ", deps: StartDependencies) => void" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -1842,8 +1866,8 @@ "label": "find", "description": [], "signature": [ - "({ savedObjectsClient }: ", - "SearchSessionDependencies", + "({ savedObjectsClient, internalElasticsearchClient }: ", + "SearchSessionStatusDependencies", ", user: ", { "pluginId": "security", @@ -1855,16 +1879,14 @@ " | null, options: Omit<", "SavedObjectsFindOptions", ", \"type\">) => Promise<", - "SavedObjectsFindResponse", - "<", { "pluginId": "data", "scope": "common", "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionSavedObjectAttributes", - "text": "SearchSessionSavedObjectAttributes" + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" }, - ", unknown>>" + ">" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -1875,10 +1897,10 @@ "id": "def-server.SearchSessionService.find.$1", "type": "Object", "tags": [], - "label": "{ savedObjectsClient }", + "label": "{ savedObjectsClient, internalElasticsearchClient }", "description": [], "signature": [ - "SearchSessionDependencies" + "SearchSessionStatusDependencies" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -2398,6 +2420,93 @@ ], "returnComment": [] }, + { + "parentPluginId": "data", + "id": "def-server.SearchSessionService.status", + "type": "Function", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "(deps: ", + "SearchSessionStatusDependencies", + ", user: ", + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + " | null, sessionId: string) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionStatusResponse", + "text": "SearchSessionStatusResponse" + }, + ">" + ], + "path": "src/plugins/data/server/search/session/session_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-server.SearchSessionService.status.$1", + "type": "Object", + "tags": [], + "label": "deps", + "description": [], + "signature": [ + "SearchSessionStatusDependencies" + ], + "path": "src/plugins/data/server/search/session/session_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "data", + "id": "def-server.SearchSessionService.status.$2", + "type": "CompoundType", + "tags": [], + "label": "user", + "description": [], + "signature": [ + { + "pluginId": "security", + "scope": "common", + "docId": "kibSecurityPluginApi", + "section": "def-common.AuthenticatedUser", + "text": "AuthenticatedUser" + }, + " | null" + ], + "path": "src/plugins/data/server/search/session/session_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "data", + "id": "def-server.SearchSessionService.status.$3", + "type": "string", + "tags": [], + "label": "sessionId", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/data/server/search/session/session_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "data", "id": "def-server.SearchSessionService.asScopedProvider", @@ -2406,7 +2515,7 @@ "label": "asScopedProvider", "description": [], "signature": [ - "({ savedObjects }: ", + "({ savedObjects, elasticsearch }: ", { "pluginId": "core", "scope": "server", @@ -2432,7 +2541,7 @@ "section": "def-common.ISearchOptions", "text": "ISearchOptions" }, - ") => Promise; trackId: (args_0: ", + ") => Promise; trackId: (searchRequest: ", { "pluginId": "data", "scope": "common", @@ -2440,7 +2549,7 @@ "section": "def-common.IKibanaSearchRequest", "text": "IKibanaSearchRequest" }, - ", args_1: string, args_2: ", + ", searchId: string, options: ", { "pluginId": "data", "scope": "common", @@ -2479,16 +2588,14 @@ ">>; find: (options: Omit<", "SavedObjectsFindOptions", ", \"type\">) => Promise<", - "SavedObjectsFindResponse", - "<", { "pluginId": "data", "scope": "common", "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionSavedObjectAttributes", - "text": "SearchSessionSavedObjectAttributes" + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" }, - ", unknown>>; update: (sessionId: string, attributes: Partial<", + ">; update: (sessionId: string, attributes: Partial<", { "pluginId": "data", "scope": "common", @@ -2526,7 +2633,15 @@ "section": "def-common.SearchSessionSavedObjectAttributes", "text": "SearchSessionSavedObjectAttributes" }, - ">>; delete: (sessionId: string) => Promise<{}>; getConfig: () => Readonly<{} & { enabled: boolean; pageSize: number; trackingInterval: moment.Duration; cleanupInterval: moment.Duration; expireInterval: moment.Duration; monitoringTaskTimeout: moment.Duration; notTouchedTimeout: moment.Duration; notTouchedInProgressTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }" + ">>; delete: (sessionId: string) => Promise<{}>; status: (sessionId: string) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionStatusResponse", + "text": "SearchSessionStatusResponse" + }, + ">; getConfig: () => Readonly<{} & { enabled: boolean; notTouchedTimeout: moment.Duration; maxUpdateRetries: number; defaultExpiration: moment.Duration; management: Readonly<{} & { refreshInterval: moment.Duration; maxSessions: number; refreshTimeout: moment.Duration; expiresSoonWarning: moment.Duration; }>; }>; }" ], "path": "src/plugins/data/server/search/session/session_service.ts", "deprecated": false, @@ -2537,7 +2652,7 @@ "id": "def-server.SearchSessionService.asScopedProvider.$1", "type": "Object", "tags": [], - "label": "{ savedObjects }", + "label": "{ savedObjects, elasticsearch }", "description": [], "signature": [ { @@ -2693,15 +2808,7 @@ "label": "attributes", "description": [], "signature": [ - "{ sessionId?: string | undefined; name?: string | undefined; appId?: string | undefined; created?: string | undefined; touched?: string | undefined; expires?: string | undefined; completed?: string | null | undefined; status?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionStatus", - "text": "SearchSessionStatus" - }, - " | undefined; locatorId?: string | undefined; initialState?: ", + "{ sessionId?: string | undefined; name?: string | undefined; appId?: string | undefined; created?: string | undefined; expires?: string | undefined; locatorId?: string | undefined; initialState?: ", "SerializableRecord", " | undefined; restoreState?: ", "SerializableRecord", @@ -2713,7 +2820,7 @@ "section": "def-common.SearchSessionRequestInfo", "text": "SearchSessionRequestInfo" }, - "> | undefined; persisted?: boolean | undefined; realmType?: string | undefined; realmName?: string | undefined; username?: string | undefined; version?: string | undefined; }" + "> | undefined; realmType?: string | undefined; realmName?: string | undefined; username?: string | undefined; version?: string | undefined; isCanceled?: boolean | undefined; }" ], "path": "src/plugins/data/server/search/session/types.ts", "deprecated": false, @@ -2770,16 +2877,14 @@ "(options: Omit<", "SavedObjectsFindOptions", ", \"type\">) => Promise<", - "SavedObjectsFindResponse", - "<", { "pluginId": "data", "scope": "common", "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionSavedObjectAttributes", - "text": "SearchSessionSavedObjectAttributes" + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" }, - ", unknown>>" + ">" ], "path": "src/plugins/data/server/search/types.ts", "deprecated": false, @@ -2802,7 +2907,11 @@ "SavedObjectsFindOptionsReference", " | ", "SavedObjectsFindOptionsReference", - "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; pit?: ", + "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; hasNoReference?: ", + "SavedObjectsFindOptionsReference", + " | ", + "SavedObjectsFindOptionsReference", + "[] | undefined; hasNoReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; pit?: ", "SavedObjectsPitParams", " | undefined; }" ], @@ -2864,15 +2973,7 @@ "label": "attributes", "description": [], "signature": [ - "{ sessionId?: string | undefined; name?: string | undefined; appId?: string | undefined; created?: string | undefined; touched?: string | undefined; expires?: string | undefined; completed?: string | null | undefined; status?: ", - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionStatus", - "text": "SearchSessionStatus" - }, - " | undefined; locatorId?: string | undefined; initialState?: ", + "{ sessionId?: string | undefined; name?: string | undefined; appId?: string | undefined; created?: string | undefined; expires?: string | undefined; locatorId?: string | undefined; initialState?: ", "SerializableRecord", " | undefined; restoreState?: ", "SerializableRecord", @@ -2884,7 +2985,7 @@ "section": "def-common.SearchSessionRequestInfo", "text": "SearchSessionRequestInfo" }, - "> | undefined; persisted?: boolean | undefined; realmType?: string | undefined; realmName?: string | undefined; username?: string | undefined; version?: string | undefined; }" + "> | undefined; realmType?: string | undefined; realmName?: string | undefined; username?: string | undefined; version?: string | undefined; isCanceled?: boolean | undefined; }" ], "path": "src/plugins/data/server/search/session/types.ts", "deprecated": false, @@ -2999,6 +3100,42 @@ "trackAdoption": false } ] + }, + { + "parentPluginId": "data", + "id": "def-server.IScopedSearchClient.getSessionStatus", + "type": "Function", + "tags": [], + "label": "getSessionStatus", + "description": [], + "signature": [ + "(sessionId: string) => Promise<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionStatusResponse", + "text": "SearchSessionStatusResponse" + }, + ">" + ], + "path": "src/plugins/data/server/search/types.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-server.IScopedSearchClient.getSessionStatus.$1", + "type": "string", + "tags": [], + "label": "sessionId", + "description": [], + "path": "src/plugins/data/server/search/session/types.ts", + "deprecated": false, + "trackAdoption": false + } + ] } ], "initialIsOpen": false @@ -26585,6 +26722,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-common.IKibanaSearchResponse.isStored", + "type": "CompoundType", + "tags": [], + "label": "isStored", + "description": [ + "\nIndicates whether the search has been saved to a search-session object and long keepAlive was set" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-common.IKibanaSearchResponse.warning", @@ -27044,6 +27197,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "data", + "id": "def-common.ISearchOptions.isSearchStored", + "type": "CompoundType", + "tags": [], + "label": "isSearchStored", + "description": [ + "\nWhether the search was successfully polled after session was saved. Search was added to a session saved object and keepAlive extended." + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "data", "id": "def-common.ISearchOptions.isRestore", @@ -28211,10 +28380,10 @@ }, { "parentPluginId": "data", - "id": "def-common.SearchSessionFindOptions", + "id": "def-common.SearchSessionRequestInfo", "type": "Interface", "tags": [], - "label": "SearchSessionFindOptions", + "label": "SearchSessionRequestInfo", "description": [], "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, @@ -28222,55 +28391,12 @@ "children": [ { "parentPluginId": "data", - "id": "def-common.SearchSessionFindOptions.page", - "type": "number", - "tags": [], - "label": "page", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionFindOptions.perPage", - "type": "number", - "tags": [], - "label": "perPage", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionFindOptions.sortField", - "type": "string", - "tags": [], - "label": "sortField", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionFindOptions.sortOrder", + "id": "def-common.SearchSessionRequestInfo.id", "type": "string", "tags": [], - "label": "sortOrder", - "description": [], - "signature": [ - "string | undefined" + "label": "id", + "description": [ + "\nID of the async search request" ], "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, @@ -28278,13 +28404,12 @@ }, { "parentPluginId": "data", - "id": "def-common.SearchSessionFindOptions.filter", + "id": "def-common.SearchSessionRequestInfo.strategy", "type": "string", "tags": [], - "label": "filter", - "description": [], - "signature": [ - "string | undefined" + "label": "strategy", + "description": [ + "\nSearch strategy used to submit the search request" ], "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, @@ -28295,10 +28420,10 @@ }, { "parentPluginId": "data", - "id": "def-common.SearchSessionRequestInfo", + "id": "def-common.SearchSessionRequestStatus", "type": "Interface", "tags": [], - "label": "SearchSessionRequestInfo", + "label": "SearchSessionRequestStatus", "description": [], "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, @@ -28306,38 +28431,19 @@ "children": [ { "parentPluginId": "data", - "id": "def-common.SearchSessionRequestInfo.id", - "type": "string", - "tags": [], - "label": "id", - "description": [ - "\nID of the async search request" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionRequestInfo.strategy", - "type": "string", - "tags": [], - "label": "strategy", - "description": [ - "\nSearch strategy used to submit the search request" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionRequestInfo.status", - "type": "string", + "id": "def-common.SearchSessionRequestStatus.status", + "type": "Enum", "tags": [], "label": "status", - "description": [ - "\nstatus" + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchStatus", + "text": "SearchStatus" + } ], "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, @@ -28345,7 +28451,7 @@ }, { "parentPluginId": "data", - "id": "def-common.SearchSessionRequestInfo.error", + "id": "def-common.SearchSessionRequestStatus.error", "type": "string", "tags": [], "label": "error", @@ -28429,19 +28535,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionSavedObjectAttributes.touched", - "type": "string", - "tags": [], - "label": "touched", - "description": [ - "\nLast touch time of the session" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "data", "id": "def-common.SearchSessionSavedObjectAttributes.expires", @@ -28455,44 +28548,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionSavedObjectAttributes.completed", - "type": "CompoundType", - "tags": [], - "label": "completed", - "description": [ - "\nTime of transition into completed state,\n\nCan be \"null\" in case already completed session\ntransitioned into in-progress session" - ], - "signature": [ - "string | null | undefined" - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionSavedObjectAttributes.status", - "type": "Enum", - "tags": [], - "label": "status", - "description": [ - "\nstatus" - ], - "signature": [ - { - "pluginId": "data", - "scope": "common", - "docId": "kibDataSearchPluginApi", - "section": "def-common.SearchSessionStatus", - "text": "SearchSessionStatus" - } - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "data", "id": "def-common.SearchSessionSavedObjectAttributes.locatorId", @@ -28567,19 +28622,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "data", - "id": "def-common.SearchSessionSavedObjectAttributes.persisted", - "type": "boolean", - "tags": [], - "label": "persisted", - "description": [ - "\nThis value is true if the session was actively stored by the user. If it is false, the session may be purged by the system." - ], - "path": "src/plugins/data/common/search/session/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "data", "id": "def-common.SearchSessionSavedObjectAttributes.realmType", @@ -28636,6 +28678,118 @@ "path": "src/plugins/data/common/search/session/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "data", + "id": "def-common.SearchSessionSavedObjectAttributes.isCanceled", + "type": "CompoundType", + "tags": [], + "label": "isCanceled", + "description": [ + "\n`true` if session was cancelled" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data/common/search/session/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "data", + "id": "def-common.SearchSessionsFindResponse", + "type": "Interface", + "tags": [], + "label": "SearchSessionsFindResponse", + "description": [ + "\nList of search session objects with on-the-fly calculated search session statuses" + ], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionsFindResponse", + "text": "SearchSessionsFindResponse" + }, + " extends ", + "SavedObjectsFindResponse", + "<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionSavedObjectAttributes", + "text": "SearchSessionSavedObjectAttributes" + }, + ", unknown>" + ], + "path": "src/plugins/data/common/search/session/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.SearchSessionsFindResponse.statuses", + "type": "Object", + "tags": [], + "label": "statuses", + "description": [ + "\nMap containing calculated statuses of search sessions from the find response" + ], + "signature": [ + "{ [x: string]: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionStatusResponse", + "text": "SearchSessionStatusResponse" + }, + "; }" + ], + "path": "src/plugins/data/common/search/session/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "data", + "id": "def-common.SearchSessionStatusResponse", + "type": "Interface", + "tags": [], + "label": "SearchSessionStatusResponse", + "description": [ + "\nOn-the-fly calculated search session status" + ], + "path": "src/plugins/data/common/search/session/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.SearchSessionStatusResponse.status", + "type": "Enum", + "tags": [], + "label": "status", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.SearchSessionStatus", + "text": "SearchSessionStatus" + } + ], + "path": "src/plugins/data/common/search/session/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -29632,6 +29786,18 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "data", + "id": "def-common.SearchStatus", + "type": "Enum", + "tags": [], + "label": "SearchStatus", + "description": [], + "path": "src/plugins/data/common/search/session/status.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "data", "id": "def-common.SortDirection", @@ -32811,7 +32977,7 @@ "signature": [ "{ executionContext?: ", "KibanaExecutionContext", - " | undefined; isStored?: boolean | undefined; isRestore?: boolean | undefined; sessionId?: string | undefined; strategy?: string | undefined; legacyHitsTotal?: boolean | undefined; }" + " | undefined; isStored?: boolean | undefined; isRestore?: boolean | undefined; sessionId?: string | undefined; strategy?: string | undefined; legacyHitsTotal?: boolean | undefined; isSearchStored?: boolean | undefined; }" ], "path": "src/plugins/data/common/search/types.ts", "deprecated": false, diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index c3b582462fd7d..ff7beafee5ea0 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3213 | 33 | 2509 | 23 | +| 3221 | 33 | 2513 | 24 | ## Client diff --git a/api_docs/data_view_editor.devdocs.json b/api_docs/data_view_editor.devdocs.json index e3bf819317755..6ecfaa57fcaa8 100644 --- a/api_docs/data_view_editor.devdocs.json +++ b/api_docs/data_view_editor.devdocs.json @@ -151,6 +151,22 @@ "path": "src/plugins/data_view_editor/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "dataViewEditor", + "id": "def-public.DataViewEditorProps.showManagementLink", + "type": "CompoundType", + "tags": [], + "label": "showManagementLink", + "description": [ + "\nif set to true a link to the management page is shown" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/data_view_editor/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 34855c7100cec..b312c83afc6d7 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; @@ -21,7 +21,7 @@ Contact [App Services](https://github.com/orgs/elastic/teams/kibana-app-services | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 15 | 0 | 7 | 0 | +| 16 | 0 | 7 | 0 | ## Client diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 5daa20fdddfef..6707ffdfaac2f 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: 2022-10-03 +date: 2022-10-06 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 fa43c84f3166a..a3f3c0a260ee3 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index 817619ccf49c9..0bd2b7af8fc6b 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: 2022-10-03 +date: 2022-10-06 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 6df0430d04c27..5a0b2da372063 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: 2022-10-03 +date: 2022-10-06 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 3c34e78a89e7f..d82fa6adb7ae1 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -24,15 +24,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | alerting, discover, securitySolution | - | | | stackAlerts, alerting, securitySolution, inputControlVis | - | | | actions, alerting | - | -| | savedObjects, embeddable, fleet, visualizations, dashboard, infra, canvas, graph, securitySolution, actions, alerting, enterpriseSearch, taskManager, savedSearch, ml, @kbn/core-saved-objects-server-internal | - | -| | savedObjects, embeddable, fleet, visualizations, dashboard, infra, canvas, graph, securitySolution, actions, alerting, enterpriseSearch, taskManager, savedSearch, ml, @kbn/core-saved-objects-server-internal | - | +| | savedObjects, embeddable, fleet, visualizations, dashboard, infra, canvas, graph, actions, alerting, enterpriseSearch, securitySolution, taskManager, savedSearch, ml, @kbn/core-saved-objects-server-internal | - | +| | savedObjects, embeddable, fleet, visualizations, dashboard, infra, canvas, graph, actions, alerting, enterpriseSearch, securitySolution, taskManager, savedSearch, ml, @kbn/core-saved-objects-server-internal | - | | | discover, maps, monitoring | - | | | unifiedSearch, discover, maps, infra, graph, securitySolution, stackAlerts, inputControlVis, savedObjects | - | | | data, discover, embeddable | - | | | advancedSettings, discover | - | | | advancedSettings, discover | - | | | securitySolution | - | -| | encryptedSavedObjects, actions, data, cloud, ml, logstash, securitySolution | - | +| | encryptedSavedObjects, actions, data, ml, logstash, securitySolution, cloudChat | - | | | dashboard, dataVisualizer, stackAlerts, expressionPartitionVis | - | | | dataViews, maps | - | | | dataViews, maps | - | @@ -62,7 +62,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | canvas | - | | | canvas | - | | | canvas | - | -| | cloud | - | | | spaces, savedObjectsManagement | - | | | spaces, savedObjectsManagement | - | | | actions, ml, savedObjectsTagging, enterpriseSearch | - | @@ -82,7 +81,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | security, fleet | 8.8.0 | | | security, fleet | 8.8.0 | | | management, fleet, security, kibanaOverview, @kbn/core-application-browser-internal, @kbn/core-application-browser-mocks | 8.8.0 | -| | cloud, apm | 8.8.0 | +| | apm | 8.8.0 | | | security, licenseManagement, ml, apm, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher | 8.8.0 | | | security | 8.8.0 | | | mapsEms | 8.8.0 | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index abe2810379ec2..cbbb60b136a47 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -173,13 +173,11 @@ so TS and code-reference navigation might not highlight them. | -## cloud +## cloudChat | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.tsx#:~:text=environment) | 8.8.0 | -| | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.tsx#:~:text=identifyUser), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/server/plugin.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/server/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/server/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/server/plugin.test.ts#:~:text=identifyUser), [plugin.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/server/plugin.test.ts#:~:text=identifyUser) | - | -| | [chat.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/server/routes/chat.ts#:~:text=authc) | - | +| | [chat.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud_integrations/cloud_chat/server/routes/chat.ts#:~:text=authc) | - | @@ -656,9 +654,9 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts#:~:text=license%24) | 8.8.0 | | | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=authc), [create_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/create_signals_migration_route.ts#:~:text=authc), [delete_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/delete_signals_migration_route.ts#:~:text=authc), [finalize_signals_migration_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/finalize_signals_migration_route.ts#:~:text=authc), [open_close_signals_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/signals/open_close_signals_route.ts#:~:text=authc), [preview_rules_route.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts#:~:text=authc), [common.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts#:~:text=authc) | - | | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/index.tsx#:~:text=onAppLeave), [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/plugin.tsx#:~:text=onAppLeave) | 8.8.0 | -| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler) | 8.8.0 | -| | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts#:~:text=SavedObjectAttributes), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | -| | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts#:~:text=SavedObjectAttributes), [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/risk_score/containers/onboarding/api/saved_objects.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | +| | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [use_timeline_save_prompt.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts#:~:text=AppLeaveHandler)+ 1 more | 8.8.0 | +| | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | +| | [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes), [legacy_migrations.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_migrations.ts#:~:text=SavedObjectAttributes) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 882abd4cb6150..970e2198e16b2 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -66,7 +66,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| cloud | | [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/cloud/public/plugin.tsx#:~:text=environment) | 8.8.0 | | kibanaOverview | | [application.tsx](https://github.com/elastic/kibana/tree/main/src/plugins/kibana_overview/public/application.tsx#:~:text=appBasePath), [app_container.tsx](https://github.com/elastic/kibana/tree/main/packages/core/application/core-application-browser-internal/src/ui/app_container.tsx#:~:text=appBasePath), [application_service.mock.ts](https://github.com/elastic/kibana/tree/main/packages/core/application/core-application-browser-mocks/src/application_service.mock.ts#:~:text=appBasePath) | 8.8.0 | | savedObjectsTaggingOss | | [api.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects_tagging_oss/public/api.ts#:~:text=SavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects_tagging_oss/public/decorator/types.ts#:~:text=SavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects_tagging_oss/public/decorator/types.ts#:~:text=SavedObject), [api.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects_tagging_oss/public/api.ts#:~:text=SavedObject), [api.ts](https://github.com/elastic/kibana/tree/main/src/plugins/saved_objects_tagging_oss/public/api.ts#:~:text=SavedObject) | 8.8.0 | | @kbn/core-application-browser-internal | | [app_container.tsx](https://github.com/elastic/kibana/tree/main/packages/core/application/core-application-browser-internal/src/ui/app_container.tsx#:~:text=onAppLeave), [application_service.mock.ts](https://github.com/elastic/kibana/tree/main/packages/core/application/core-application-browser-mocks/src/application_service.mock.ts#:~:text=onAppLeave) | 8.8.0 | @@ -168,7 +167,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | securitySolution | | [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [policy_config.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/common/license/policy_config.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [fleet_integration.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [license_watch.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/policy/license_watch.test.ts#:~:text=mode), [list.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/routes/actions/list.test.ts#:~:text=mode), [response_actions.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.test.ts#:~:text=mode)+ 3 more | 8.8.0 | | securitySolution | | [query.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts#:~:text=license%24) | 8.8.0 | | securitySolution | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/index.tsx#:~:text=onAppLeave), [plugin.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/plugin.tsx#:~:text=onAppLeave) | 8.8.0 | -| securitySolution | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler) | 8.8.0 | +| securitySolution | | [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [index.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/timelines/components/flyout/index.tsx#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/types.ts#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [routes.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/routes.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [app.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/app/app.tsx#:~:text=AppLeaveHandler), [use_timeline_save_prompt.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/timeline/use_timeline_save_prompt.ts#:~:text=AppLeaveHandler)+ 1 more | 8.8.0 | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 76be86527aaed..b0bdc80f76221 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 9c9793bd2bcfb..1004bc000228f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index bc90ebb67c09b..0a1ae92c44f65 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index 4c4b222a02a7c..fe1b4aaa6b3a0 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: 2022-10-03 +date: 2022-10-06 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 5ab0874911417..647b063aab79f 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: 2022-10-03 +date: 2022-10-06 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 5aa1eae40de53..02f77132a6dd3 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: 2022-10-03 +date: 2022-10-06 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 ba021086e294a..eb9a8b2e6a08d 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: 2022-10-03 +date: 2022-10-06 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 bf991156be210..85ceaecf956d8 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: 2022-10-03 +date: 2022-10-06 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 2c09bd5d65d46..2929235fc1732 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_log.devdocs.json b/api_docs/event_log.devdocs.json index 8361059c91079..b4c0370096cc2 100644 --- a/api_docs/event_log.devdocs.json +++ b/api_docs/event_log.devdocs.json @@ -1312,7 +1312,7 @@ "label": "data", "description": [], "signature": [ - "(Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined)[]" + "(Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ active?: string | number | undefined; recovered?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined)[]" ], "path": "x-pack/plugins/event_log/server/es/cluster_client_adapter.ts", "deprecated": false, @@ -1332,7 +1332,7 @@ "label": "IEvent", "description": [], "signature": [ - "DeepPartial | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}>>> | undefined" + "DeepPartial | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ active?: string | number | undefined; recovered?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}>>> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, @@ -1347,7 +1347,7 @@ "label": "IValidatedEvent", "description": [], "signature": [ - "Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ recovered?: string | number | undefined; active?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined" + "Readonly<{ error?: Readonly<{ type?: string | undefined; id?: string | undefined; message?: string | undefined; code?: string | undefined; stack_trace?: string | undefined; } & {}> | undefined; tags?: string[] | undefined; log?: Readonly<{ logger?: string | undefined; level?: string | undefined; } & {}> | undefined; user?: Readonly<{ name?: string | undefined; } & {}> | undefined; message?: string | undefined; kibana?: Readonly<{ alert?: Readonly<{ rule?: Readonly<{ consumer?: string | undefined; execution?: Readonly<{ status?: string | undefined; metrics?: Readonly<{ number_of_triggered_actions?: string | number | undefined; number_of_generated_actions?: string | number | undefined; alert_counts?: Readonly<{ active?: string | number | undefined; recovered?: string | number | undefined; new?: string | number | undefined; } & {}> | undefined; number_of_searches?: string | number | undefined; total_indexing_duration_ms?: string | number | undefined; es_search_duration_ms?: string | number | undefined; total_search_duration_ms?: string | number | undefined; execution_gap_duration_s?: string | number | undefined; rule_type_run_duration_ms?: string | number | undefined; process_alerts_duration_ms?: string | number | undefined; trigger_actions_duration_ms?: string | number | undefined; process_rule_duration_ms?: string | number | undefined; claim_to_start_duration_ms?: string | number | undefined; prepare_rule_duration_ms?: string | number | undefined; total_run_duration_ms?: string | number | undefined; total_enrichment_duration_ms?: string | number | undefined; } & {}> | undefined; uuid?: string | undefined; status_order?: string | number | undefined; } & {}> | undefined; rule_type_id?: string | undefined; } & {}> | undefined; } & {}> | undefined; version?: string | undefined; alerting?: Readonly<{ status?: string | undefined; instance_id?: string | undefined; action_group_id?: string | undefined; action_subgroup?: string | undefined; } & {}> | undefined; server_uuid?: string | undefined; task?: Readonly<{ id?: string | undefined; schedule_delay?: string | number | undefined; scheduled?: string | undefined; } & {}> | undefined; saved_objects?: Readonly<{ type?: string | undefined; id?: string | undefined; namespace?: string | undefined; rel?: string | undefined; type_id?: string | undefined; } & {}>[] | undefined; space_ids?: string[] | undefined; } & {}> | undefined; ecs?: Readonly<{ version?: string | undefined; } & {}> | undefined; rule?: Readonly<{ name?: string | undefined; description?: string | undefined; category?: string | undefined; id?: string | undefined; version?: string | undefined; license?: string | undefined; reference?: string | undefined; author?: string[] | undefined; ruleset?: string | undefined; uuid?: string | undefined; } & {}> | undefined; event?: Readonly<{ start?: string | undefined; category?: string[] | undefined; type?: string[] | undefined; id?: string | undefined; created?: string | undefined; outcome?: string | undefined; end?: string | undefined; original?: string | undefined; duration?: string | number | undefined; code?: string | undefined; url?: string | undefined; action?: string | undefined; kind?: string | undefined; hash?: string | undefined; severity?: string | number | undefined; dataset?: string | undefined; ingested?: string | undefined; module?: string | undefined; provider?: string | undefined; reason?: string | undefined; reference?: string | undefined; risk_score?: number | undefined; risk_score_norm?: number | undefined; sequence?: string | number | undefined; timezone?: string | undefined; } & {}> | undefined; '@timestamp'?: string | undefined; } & {}> | undefined" ], "path": "x-pack/plugins/event_log/generated/schemas.ts", "deprecated": false, diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 482e1d361a157..544fd761d5cb3 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 2ab9af9772d04..df2e2b21c11e6 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: 2022-10-03 +date: 2022-10-06 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 908d90469c751..5ad24ba7a8bc4 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: 2022-10-03 +date: 2022-10-06 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 aa2ac31f046ec..b2e900dcbcd09 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: 2022-10-03 +date: 2022-10-06 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 fd4412ad3f9e9..e596984a9abf6 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: 2022-10-03 +date: 2022-10-06 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 4f1bd9723f36a..bc8919a722ad4 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: 2022-10-03 +date: 2022-10-06 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 d17081eed3cbf..98cce847e74ba 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: 2022-10-03 +date: 2022-10-06 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 daa61ecf37e7b..0aae88922421c 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: 2022-10-03 +date: 2022-10-06 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 aaf66fd40fa4e..5e961ebb7bc87 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: 2022-10-03 +date: 2022-10-06 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 8e5467dc9cff3..45c1407b31eb7 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: 2022-10-03 +date: 2022-10-06 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 a2a032c0c0bde..1d59a537621ec 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: 2022-10-03 +date: 2022-10-06 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 e650bf57eac7f..497c62b3bd6c2 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: 2022-10-03 +date: 2022-10-06 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 cf00311b239a8..4e47f3e415867 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: 2022-10-03 +date: 2022-10-06 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 0eed4b0b713d0..633c4c7b66686 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 353dfa02a7830..24cb3aefed102 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.devdocs.json b/api_docs/features.devdocs.json index a6e9773502284..7f9018f5e89ce 100644 --- a/api_docs/features.devdocs.json +++ b/api_docs/features.devdocs.json @@ -64,7 +64,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; cases?: Readonly<{ 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; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -1193,7 +1193,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; cases?: Readonly<{ 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; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -2872,7 +2872,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; cases?: Readonly<{ 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; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>[] | undefined; privilegesTooltip?: string | undefined; reserved?: Readonly<{ description: string; privileges: readonly Readonly<{ id: string; privilege: Readonly<{ excludeFromBasePrivileges?: boolean | undefined; requireAllSpaces?: boolean | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; api?: readonly string[] | undefined; app?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; ui: readonly string[]; }>; }>[]; }> | undefined; }>" ], "path": "x-pack/plugins/features/common/kibana_feature.ts", "deprecated": false, @@ -3122,7 +3122,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; cases?: Readonly<{ 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; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }>" ], "path": "x-pack/plugins/features/common/sub_feature.ts", "deprecated": false, @@ -3159,7 +3159,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; cases?: Readonly<{ 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; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]" ], "path": "x-pack/plugins/features/common/sub_feature.ts", "deprecated": false, @@ -3181,7 +3181,7 @@ "section": "def-common.SubFeaturePrivilegeGroupType", "text": "SubFeaturePrivilegeGroupType" }, - "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; cases?: Readonly<{ 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; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }" + "; privileges: readonly Readonly<{ id: string; name: string; includeIn: \"none\" | \"all\" | \"read\"; minimumLicense?: \"basic\" | \"standard\" | \"gold\" | \"platinum\" | \"enterprise\" | \"trial\" | undefined; disabled?: boolean | undefined; management?: Readonly<{ [x: string]: readonly string[]; }> | undefined; cases?: Readonly<{ 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; catalogue?: readonly string[] | undefined; alerting?: Readonly<{ rule?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; alert?: Readonly<{ all?: readonly string[] | undefined; read?: readonly string[] | undefined; }> | undefined; }> | undefined; ui: readonly string[]; app?: readonly string[] | undefined; requireAllSpaces?: boolean | undefined; api?: readonly string[] | undefined; savedObject: Readonly<{ all: readonly string[]; read: readonly string[]; }>; }>[]; }>[]; }" ], "path": "x-pack/plugins/features/common/sub_feature.ts", "deprecated": false, diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 8b7f40f4a359b..7fe206a6ed36c 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: 2022-10-03 +date: 2022-10-06 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 040d820604007..23e1e83418399 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: 2022-10-03 +date: 2022-10-06 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 768f6188371fc..8a784eab30a91 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: 2022-10-03 +date: 2022-10-06 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 8491d90df2446..524666d7d411d 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 59f0a3a2c3c98..268fcade0bb3c 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -8262,6 +8262,20 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "fleet", + "id": "def-common.Agent.outputs", + "type": "Array", + "tags": [], + "label": "outputs", + "description": [], + "signature": [ + "{ api_key_id: string; to_retire_api_key_ids?: { id: string; retired_at: string; }[] | undefined; }[] | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/agent.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "fleet", "id": "def-common.Agent.status", @@ -8390,7 +8404,7 @@ "label": "status", "description": [], "signature": [ - "\"active\" | \"inactive\"" + "\"inactive\" | \"active\"" ], "path": "x-pack/plugins/fleet/common/types/models/agent_policy.ts", "deprecated": false, @@ -14105,7 +14119,7 @@ "section": "def-common.RegistryPackage", "text": "RegistryPackage" }, - ", \"internal\" | \"assets\" | \"readme\" | \"data_streams\" | \"elasticsearch\">" + ", \"elasticsearch\" | \"internal\" | \"assets\" | \"readme\" | \"data_streams\">" ], "path": "x-pack/plugins/fleet/common/types/models/epm.ts", "deprecated": false, diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index b63495e177924..9fe27d03d10bd 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Fleet](https://github.com/orgs/elastic/teams/fleet) for questions regar | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 997 | 3 | 893 | 17 | +| 998 | 3 | 894 | 17 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 97d12a56906f0..661c7226b9915 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.devdocs.json b/api_docs/guided_onboarding.devdocs.json index 27b0b8446a7d8..a186673312896 100644 --- a/api_docs/guided_onboarding.devdocs.json +++ b/api_docs/guided_onboarding.devdocs.json @@ -6,44 +6,111 @@ "interfaces": [ { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuidedOnboardingState", + "id": "def-public.GuideState", "type": "Interface", "tags": [], - "label": "GuidedOnboardingState", + "label": "GuideState", "description": [], - "path": "src/plugins/guided_onboarding/public/types.ts", + "path": "src/plugins/guided_onboarding/common/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuidedOnboardingState.activeGuide", + "id": "def-public.GuideState.guideId", "type": "CompoundType", "tags": [], - "label": "activeGuide", + "label": "guideId", "description": [], "signature": [ - { - "pluginId": "guidedOnboarding", - "scope": "public", - "docId": "kibGuidedOnboardingPluginApi", - "section": "def-public.UseCase", - "text": "UseCase" - }, - " | \"unset\"" + "\"search\" | \"security\" | \"observability\"" ], - "path": "src/plugins/guided_onboarding/public/types.ts", + "path": "src/plugins/guided_onboarding/common/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "guidedOnboarding", - "id": "def-public.GuidedOnboardingState.activeStep", - "type": "string", + "id": "def-public.GuideState.status", + "type": "CompoundType", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "\"complete\" | \"in_progress\" | \"ready_to_complete\"" + ], + "path": "src/plugins/guided_onboarding/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuideState.isActive", + "type": "CompoundType", + "tags": [], + "label": "isActive", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/guided_onboarding/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuideState.steps", + "type": "Array", + "tags": [], + "label": "steps", + "description": [], + "signature": [ + "GuideStep", + "[]" + ], + "path": "src/plugins/guided_onboarding/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuideStep", + "type": "Interface", + "tags": [], + "label": "GuideStep", + "description": [], + "path": "src/plugins/guided_onboarding/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuideStep.id", + "type": "CompoundType", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "\"add_data\" | \"view_dashboard\" | \"tour_observability\" | \"rules\" | \"alerts\" | \"cases\" | \"browse_docs\" | \"search_experience\"" + ], + "path": "src/plugins/guided_onboarding/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuideStep.status", + "type": "CompoundType", "tags": [], - "label": "activeStep", + "label": "status", "description": [], - "path": "src/plugins/guided_onboarding/public/types.ts", + "signature": [ + "\"complete\" | \"in_progress\" | \"inactive\" | \"active\"" + ], + "path": "src/plugins/guided_onboarding/common/types.ts", "deprecated": false, "trackAdoption": false } @@ -55,21 +122,93 @@ "misc": [ { "parentPluginId": "guidedOnboarding", - "id": "def-public.UseCase", + "id": "def-public.GuideId", "type": "Type", "tags": [], - "label": "UseCase", + "label": "GuideId", "description": [], "signature": [ "\"search\" | \"security\" | \"observability\"" ], - "path": "src/plugins/guided_onboarding/public/types.ts", + "path": "src/plugins/guided_onboarding/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.GuideStepIds", + "type": "Type", + "tags": [], + "label": "GuideStepIds", + "description": [], + "signature": [ + "\"add_data\" | \"view_dashboard\" | \"tour_observability\" | \"rules\" | \"alerts\" | \"cases\" | \"browse_docs\" | \"search_experience\"" + ], + "path": "src/plugins/guided_onboarding/common/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false } ], - "objects": [], + "objects": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.guidesConfig", + "type": "Object", + "tags": [], + "label": "guidesConfig", + "description": [], + "path": "src/plugins/guided_onboarding/public/constants/guides_config/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.guidesConfig.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + "GuideConfig" + ], + "path": "src/plugins/guided_onboarding/public/constants/guides_config/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.guidesConfig.observability", + "type": "Object", + "tags": [], + "label": "observability", + "description": [], + "signature": [ + "GuideConfig" + ], + "path": "src/plugins/guided_onboarding/public/constants/guides_config/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "guidedOnboarding", + "id": "def-public.guidesConfig.search", + "type": "Object", + "tags": [], + "label": "search", + "description": [], + "signature": [ + "GuideConfig" + ], + "path": "src/plugins/guided_onboarding/public/constants/guides_config/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "setup": { "parentPluginId": "guidedOnboarding", "id": "def-public.GuidedOnboardingPluginSetup", @@ -103,7 +242,7 @@ "label": "guidedOnboardingApi", "description": [], "signature": [ - "ApiService", + "GuidedOnboardingApi", " | undefined" ], "path": "src/plugins/guided_onboarding/public/types.ts", @@ -156,53 +295,7 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [ - { - "parentPluginId": "guidedOnboarding", - "id": "def-common.API_BASE_PATH", - "type": "string", - "tags": [], - "label": "API_BASE_PATH", - "description": [], - "signature": [ - "\"/api/guided_onboarding\"" - ], - "path": "src/plugins/guided_onboarding/common/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "guidedOnboarding", - "id": "def-common.PLUGIN_ID", - "type": "string", - "tags": [], - "label": "PLUGIN_ID", - "description": [], - "signature": [ - "\"guidedOnboarding\"" - ], - "path": "src/plugins/guided_onboarding/common/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "guidedOnboarding", - "id": "def-common.PLUGIN_NAME", - "type": "string", - "tags": [], - "label": "PLUGIN_NAME", - "description": [], - "signature": [ - "\"guidedOnboarding\"" - ], - "path": "src/plugins/guided_onboarding/common/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - } - ], + "misc": [], "objects": [] } } \ No newline at end of file diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 899b3205a819c..bfda154275b28 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onbo | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 12 | 0 | 12 | 1 | +| 19 | 0 | 19 | 3 | ## Client @@ -31,6 +31,9 @@ Contact [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onbo ### Start +### Objects + + ### Interfaces @@ -45,8 +48,3 @@ Contact [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onbo ### Start -## Common - -### Consts, variables and types - - diff --git a/api_docs/home.devdocs.json b/api_docs/home.devdocs.json index c8e980ff0a0ab..a18ea6d544131 100644 --- a/api_docs/home.devdocs.json +++ b/api_docs/home.devdocs.json @@ -1313,10 +1313,6 @@ "removeBy": "8.8.0", "trackAdoption": false, "references": [ - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/public/plugin.tsx" - }, { "plugin": "apm", "path": "x-pack/plugins/apm/public/plugin.ts" diff --git a/api_docs/home.mdx b/api_docs/home.mdx index 30beb41d12fae..70e3654e91bfd 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index e3ee1798496d0..8f1b666a80453 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: 2022-10-03 +date: 2022-10-06 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 34f9d8fcde852..cba3862d95d89 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: 2022-10-03 +date: 2022-10-06 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 7ab9b9d8573c5..61074d16d2ced 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: 2022-10-03 +date: 2022-10-06 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 4cb29a4632cab..cb51aba7f2373 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: 2022-10-03 +date: 2022-10-06 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 6f257bb854320..5a35131468ca2 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: 2022-10-03 +date: 2022-10-06 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 0dcf9a1b797bc..6a275a46e7838 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: 2022-10-03 +date: 2022-10-06 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 60ab8f506c3a5..121ac90868b8a 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: 2022-10-03 +date: 2022-10-06 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 c459ac8369da3..9f24723d941b5 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts.mdx b/api_docs/kbn_alerts.mdx index aaf236aab90f0..c5813b3057953 100644 --- a/api_docs/kbn_alerts.mdx +++ b/api_docs/kbn_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts title: "@kbn/alerts" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts'] --- import kbnAlertsObj from './kbn_alerts.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 35df4e16f17cd..98a90c24a3b9c 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: 2022-10-03 +date: 2022-10-06 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 0d18980e0b1c0..85bb5b3416f94 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: 2022-10-03 +date: 2022-10-06 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 c4b9427b1a333..87f82dc11043c 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: 2022-10-03 +date: 2022-10-06 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 f06cb724cc729..28beb0ee61025 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: 2022-10-03 +date: 2022-10-06 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 cd5176593f6ad..5bf617a8923c8 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: 2022-10-03 +date: 2022-10-06 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 d6317c64bf48c..6fb409bc10bfb 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index e916c19f16197..cb944dac35f65 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: 2022-10-03 +date: 2022-10-06 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 9ba0d5aeeacf4..bf423b6db5c1c 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index ca208a21625bd..d1f3cb0c2c14a 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: 2022-10-03 +date: 2022-10-06 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 7a1ad1863e07b..fc517e3cf37c8 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 6e102733b051b..273797b541c23 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: 2022-10-03 +date: 2022-10-06 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 cfd53f8e091ff..0a6ac6e29bad6 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: 2022-10-03 +date: 2022-10-06 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 c28b07464ba41..8103b5738c6fa 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: 2022-10-03 +date: 2022-10-06 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 d5c55b31b68c0..e825df3c46462 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: 2022-10-03 +date: 2022-10-06 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 c2de5353062a3..41a2a4ed84e91 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index c5026a994bbff..84e6351219af4 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: 2022-10-03 +date: 2022-10-06 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 a81d5f720c20a..d336ce4cc2268 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index 3ca7cf87f8819..3567a1afbc3c2 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: 2022-10-03 +date: 2022-10-06 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 f4fd135eead55..d7833d02e1cfc 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list.mdx b/api_docs/kbn_content_management_table_list.mdx index 2cb822b645378..21ac5fc7aaf0c 100644 --- a/api_docs/kbn_content_management_table_list.mdx +++ b/api_docs/kbn_content_management_table_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list title: "@kbn/content-management-table-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list'] --- import kbnContentManagementTableListObj from './kbn_content_management_table_list.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 2cf8df7f6fb13..c78d87e1aeeea 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: 2022-10-03 +date: 2022-10-06 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 217056d756e6c..5d171564a7abe 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: 2022-10-03 +date: 2022-10-06 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 8674be0b88a22..2fc6ceee4621f 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: 2022-10-03 +date: 2022-10-06 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 a3e9193110cf9..7724103c05455 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: 2022-10-03 +date: 2022-10-06 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 87edbd5da1573..4e0077433a2f3 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: 2022-10-03 +date: 2022-10-06 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 eba99f7740982..612f56b417235 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: 2022-10-03 +date: 2022-10-06 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 6cd2f00a3f32a..a30cf4db34d8a 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: 2022-10-03 +date: 2022-10-06 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 0e0674185951d..936092d30b255 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: 2022-10-03 +date: 2022-10-06 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 f58bebcf2f5d0..75a8e890239e3 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: 2022-10-03 +date: 2022-10-06 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 3d4d7035f6c1d..ed06fa661c889 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: 2022-10-03 +date: 2022-10-06 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 7681b7a4a3885..9c82389ccd66e 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: 2022-10-03 +date: 2022-10-06 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 02a409c5881de..c8acf0374937e 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: 2022-10-03 +date: 2022-10-06 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_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index b60d8471e15dd..698ec225e76fa 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: 2022-10-03 +date: 2022-10-06 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 39463461d9165..a751549127507 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: 2022-10-03 +date: 2022-10-06 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 2a64da20012e8..463654ac33aec 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: 2022-10-03 +date: 2022-10-06 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 b2056befb2acb..c846ff5981aac 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: 2022-10-03 +date: 2022-10-06 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 6d28c54984174..c74c5f2d80f4a 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: 2022-10-03 +date: 2022-10-06 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 c7628a5a59c63..eb488d9d5170f 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: 2022-10-03 +date: 2022-10-06 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 e01e96164ef47..5b86020001585 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: 2022-10-03 +date: 2022-10-06 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 9ef6e61852ed2..96eca9794ef00 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: 2022-10-03 +date: 2022-10-06 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 57e8483cb0f74..f0709da12a248 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: 2022-10-03 +date: 2022-10-06 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 c4fabecffea39..cc7ceb4cfad68 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: 2022-10-03 +date: 2022-10-06 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 1d7858167c974..59471cc59be49 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: 2022-10-03 +date: 2022-10-06 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_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 3914aa766a64d..4893dcc427556 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: 2022-10-03 +date: 2022-10-06 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 fca144e245a76..a15b15de52afe 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: 2022-10-03 +date: 2022-10-06 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 5be603ffa1f96..523fa46f4be13 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: 2022-10-03 +date: 2022-10-06 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 afde35a745d30..236a34150737b 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: 2022-10-03 +date: 2022-10-06 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 92ba606e6044c..25244e072a891 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: 2022-10-03 +date: 2022-10-06 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 9b3c1070f6623..19f3278d21947 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: 2022-10-03 +date: 2022-10-06 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 e871d2dc0a941..076140b90d41e 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: 2022-10-03 +date: 2022-10-06 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 d591288b81315..eb1229f002cfc 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: 2022-10-03 +date: 2022-10-06 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 7cd809b6b97e1..2d22dfb843f82 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: 2022-10-03 +date: 2022-10-06 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 273051738c41f..7534a721a479f 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: 2022-10-03 +date: 2022-10-06 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 0cddffa5aeab6..33eb96ac86934 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: 2022-10-03 +date: 2022-10-06 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.devdocs.json b/api_docs/kbn_core_elasticsearch_client_server_internal.devdocs.json index 0491f42594311..aa5dd46285c2f 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.devdocs.json @@ -21,10 +21,10 @@ "signature": [ "(config: ", "ElasticsearchClientConfig", - ", { logger, type, scoped, getExecutionContext, agentManager, kibanaVersion, }: { logger: ", + ", { logger, type, scoped, getExecutionContext, agentFactoryProvider, kibanaVersion, }: { logger: ", "Logger", - "; type: string; scoped?: boolean | undefined; getExecutionContext?: (() => string | undefined) | undefined; agentManager: ", - "AgentManager", + "; type: string; scoped?: boolean | undefined; getExecutionContext?: (() => string | undefined) | undefined; agentFactoryProvider: ", + "AgentFactoryProvider", "; kibanaVersion: string; }) => ", "default" ], @@ -52,7 +52,7 @@ "id": "def-server.configureClient.$2", "type": "Object", "tags": [], - "label": "{\n logger,\n type,\n scoped = false,\n getExecutionContext = noop,\n agentManager,\n kibanaVersion,\n }", + "label": "{\n logger,\n type,\n scoped = false,\n getExecutionContext = noop,\n agentFactoryProvider,\n kibanaVersion,\n }", "description": [], "path": "packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.ts", "deprecated": false, @@ -115,13 +115,13 @@ }, { "parentPluginId": "@kbn/core-elasticsearch-client-server-internal", - "id": "def-server.configureClient.$2.agentManager", + "id": "def-server.configureClient.$2.agentFactoryProvider", "type": "Object", "tags": [], - "label": "agentManager", + "label": "agentFactoryProvider", "description": [], "signature": [ - "AgentManager" + "AgentFactoryProvider" ], "path": "packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.ts", "deprecated": false, @@ -220,7 +220,40 @@ "initialIsOpen": false } ], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "@kbn/core-elasticsearch-client-server-internal", + "id": "def-server.AgentStore", + "type": "Interface", + "tags": [], + "label": "AgentStore", + "description": [], + "path": "packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/agent_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-elasticsearch-client-server-internal", + "id": "def-server.AgentStore.getAgents", + "type": "Function", + "tags": [], + "label": "getAgents", + "description": [], + "signature": [ + "() => Set<", + "NetworkAgent", + ">" + ], + "path": "packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/agent_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [], "objects": [] diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index 88eb042d98206..7924bcd56c7d4 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; @@ -21,10 +21,13 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 13 | 0 | 11 | 1 | +| 15 | 0 | 13 | 2 | ## Server ### Functions +### Interfaces + + diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json b/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json index c682403d3d63d..dc17ba9d371c0 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.devdocs.json @@ -10,7 +10,46 @@ }, "server": { "classes": [], - "functions": [], + "functions": [ + { + "parentPluginId": "@kbn/core-elasticsearch-client-server-mocks", + "id": "def-server.createAgentStoreMock", + "type": "Function", + "tags": [], + "label": "createAgentStoreMock", + "description": [], + "signature": [ + "(agents?: Set<", + "NetworkAgent", + ">) => ", + "AgentStore" + ], + "path": "packages/core/elasticsearch/core-elasticsearch-client-server-mocks/src/agent_manager.mocks.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-elasticsearch-client-server-mocks", + "id": "def-server.createAgentStoreMock.$1", + "type": "Object", + "tags": [], + "label": "agents", + "description": [], + "signature": [ + "Set<", + "NetworkAgent", + ">" + ], + "path": "packages/core/elasticsearch/core-elasticsearch-client-server-mocks/src/agent_manager.mocks.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], "interfaces": [ { "parentPluginId": "@kbn/core-elasticsearch-client-server-mocks", diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index bbf4d1f0a58e8..8d2a1aec28763 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; @@ -21,13 +21,16 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 36 | 1 | 32 | 0 | +| 38 | 1 | 34 | 0 | ## Server ### Objects +### Functions + + ### Interfaces diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index c9f8fdbd9b45d..f7cefc24902ee 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: 2022-10-03 +date: 2022-10-06 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 f4032d04f97ca..be6543933f307 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: 2022-10-03 +date: 2022-10-06 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 835c21903b6bf..2ba99dd1aab20 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: 2022-10-03 +date: 2022-10-06 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 47f64412fe99e..2f4903c7dde0e 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: 2022-10-03 +date: 2022-10-06 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 082f5dd46eced..ea3c8e52207de 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: 2022-10-03 +date: 2022-10-06 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 492f874f833eb..d34b1627cafbc 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: 2022-10-03 +date: 2022-10-06 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 f8426b783c45a..73aa85945d91c 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: 2022-10-03 +date: 2022-10-06 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 6efeffd1c91c3..054a4ac5ba881 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: 2022-10-03 +date: 2022-10-06 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 ed8e5ae438b3d..9ad9451b9960b 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: 2022-10-03 +date: 2022-10-06 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 6441c8e326395..b1e313346d29d 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: 2022-10-03 +date: 2022-10-06 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 4f0d3211fa39d..1e5210ca45b9c 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: 2022-10-03 +date: 2022-10-06 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 02fa99d7cb6ce..daa1f2e3cb044 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: 2022-10-03 +date: 2022-10-06 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 40263469ee782..a064f8fd86b7e 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: 2022-10-03 +date: 2022-10-06 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 a6af55aa79cbe..41c88086aeeb2 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: 2022-10-03 +date: 2022-10-06 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 a1c258a426f33..acbbfe8d61a5d 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: 2022-10-03 +date: 2022-10-06 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 a937dccab7fb8..1ed43940640b9 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: 2022-10-03 +date: 2022-10-06 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 a6274dd34b37d..276d38ea534b5 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: 2022-10-03 +date: 2022-10-06 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 6293ae9b58af2..92d65732000df 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: 2022-10-03 +date: 2022-10-06 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 f11227d039fcf..30f91a01b5c12 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: 2022-10-03 +date: 2022-10-06 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 d0ea0e82f7682..c0a010854a4a3 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: 2022-10-03 +date: 2022-10-06 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.devdocs.json b/api_docs/kbn_core_http_resources_server.devdocs.json new file mode 100644 index 0000000000000..4a58d5e1ad9ef --- /dev/null +++ b/api_docs/kbn_core_http_resources_server.devdocs.json @@ -0,0 +1,457 @@ +{ + "id": "@kbn/core-http-resources-server", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResources", + "type": "Interface", + "tags": [], + "label": "HttpResources", + "description": [ + "\nHttpResources service is responsible for serving static & dynamic assets for Kibana application via HTTP.\nProvides API allowing plug-ins to respond with:\n- a pre-configured HTML page bootstrapping Kibana client app\n- custom HTML page\n- custom JS script file." + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResources.register", + "type": "Function", + "tags": [], + "label": "register", + "description": [ + "To register a route handler executing passed function to form response." + ], + "signature": [ + "(route: ", + "RouteConfig", + ", handler: ", + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesRequestHandler", + "text": "HttpResourcesRequestHandler" + }, + ") => void" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResources.register.$1", + "type": "Object", + "tags": [], + "label": "route", + "description": [], + "signature": [ + "RouteConfig", + "" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResources.register.$2", + "type": "Function", + "tags": [], + "label": "handler", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesRequestHandler", + "text": "HttpResourcesRequestHandler" + }, + "" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesRenderOptions", + "type": "Interface", + "tags": [], + "label": "HttpResourcesRenderOptions", + "description": [ + "\nAllows to configure HTTP response parameters" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesRenderOptions.headers", + "type": "CompoundType", + "tags": [], + "label": "headers", + "description": [ + "\nHTTP Headers with additional information about response." + ], + "signature": [ + "ResponseHeaders", + " | undefined" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit", + "type": "Interface", + "tags": [], + "label": "HttpResourcesServiceToolkit", + "description": [ + "\nExtended set of {@link KibanaResponseFactory} helpers used to respond with HTML or JS resource." + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderCoreApp", + "type": "Function", + "tags": [], + "label": "renderCoreApp", + "description": [ + "To respond with HTML page bootstrapping Kibana application." + ], + "signature": [ + "(options?: ", + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesRenderOptions", + "text": "HttpResourcesRenderOptions" + }, + " | undefined) => Promise<", + "IKibanaResponse", + ">" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderCoreApp.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesRenderOptions", + "text": "HttpResourcesRenderOptions" + }, + " | undefined" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderAnonymousCoreApp", + "type": "Function", + "tags": [], + "label": "renderAnonymousCoreApp", + "description": [ + "To respond with HTML page bootstrapping Kibana application without retrieving user-specific information." + ], + "signature": [ + "(options?: ", + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesRenderOptions", + "text": "HttpResourcesRenderOptions" + }, + " | undefined) => Promise<", + "IKibanaResponse", + ">" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderAnonymousCoreApp.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesRenderOptions", + "text": "HttpResourcesRenderOptions" + }, + " | undefined" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderHtml", + "type": "Function", + "tags": [], + "label": "renderHtml", + "description": [ + "To respond with a custom HTML page." + ], + "signature": [ + "(options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", + "" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderHtml.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "HttpResponseOptions" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderJs", + "type": "Function", + "tags": [], + "label": "renderJs", + "description": [ + "To respond with a custom JS script file." + ], + "signature": [ + "(options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", + "" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesServiceToolkit.renderJs.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "HttpResponseOptions" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesRequestHandler", + "type": "Type", + "tags": [], + "label": "HttpResourcesRequestHandler", + "description": [ + "\nExtended version of {@link RequestHandler} having access to {@link HttpResourcesServiceToolkit}\nto respond with HTML or JS resources." + ], + "signature": [ + "(context: Context, request: ", + "KibanaRequest", + ", response: ", + "KibanaSuccessResponseFactory", + " & ", + "KibanaRedirectionResponseFactory", + " & ", + "KibanaErrorResponseFactory", + " & { custom | Error | ", + "Stream", + " | Buffer | { message: string | Error; attributes?: ", + "ResponseErrorAttributes", + " | undefined; } | undefined>(options: ", + "CustomHttpResponseOptions", + "): ", + "IKibanaResponse", + "; } & ", + { + "pluginId": "@kbn/core-http-resources-server", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerPluginApi", + "section": "def-server.HttpResourcesServiceToolkit", + "text": "HttpResourcesServiceToolkit" + }, + ") => ", + "IKibanaResponse", + " | Promise<", + "IKibanaResponse", + ">" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesRequestHandler.$1", + "type": "Uncategorized", + "tags": [], + "label": "context", + "description": [ + "{@link RequestHandlerContext } - the core context exposed for this request." + ], + "signature": [ + "Context" + ], + "path": "node_modules/@types/kbn__core-http-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesRequestHandler.$2", + "type": "Object", + "tags": [], + "label": "request", + "description": [ + "{@link KibanaRequest } - object containing information about requested resource,\nsuch as path, method, headers, parameters, query, body, etc." + ], + "signature": [ + "KibanaRequest", + "" + ], + "path": "node_modules/@types/kbn__core-http-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesRequestHandler.$3", + "type": "Uncategorized", + "tags": [], + "label": "response", + "description": [ + "{@link KibanaResponseFactory } {@libk HttpResourcesServiceToolkit} - a set of helper functions used to respond to a request." + ], + "signature": [ + "ResponseFactory" + ], + "path": "node_modules/@types/kbn__core-http-server/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-http-resources-server", + "id": "def-server.HttpResourcesResponseOptions", + "type": "Type", + "tags": [], + "label": "HttpResourcesResponseOptions", + "description": [ + "\nHTTP Resources response parameters" + ], + "signature": [ + "HttpResponseOptions" + ], + "path": "packages/core/http/core-http-resources-server/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx new file mode 100644 index 0000000000000..8411cd1c66ed6 --- /dev/null +++ b/api_docs/kbn_core_http_resources_server.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: kibKbnCoreHttpResourcesServerPluginApi +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: 2022-10-06 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] +--- +import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 20 | 0 | 6 | 0 | + +## Server + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_http_resources_server_internal.devdocs.json b/api_docs/kbn_core_http_resources_server_internal.devdocs.json new file mode 100644 index 0000000000000..fae7163d58b82 --- /dev/null +++ b/api_docs/kbn_core_http_resources_server_internal.devdocs.json @@ -0,0 +1,200 @@ +{ + "id": "@kbn/core-http-resources-server-internal", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [ + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService", + "type": "Class", + "tags": [], + "label": "HttpResourcesService", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-resources-server-internal", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerInternalPluginApi", + "section": "def-server.HttpResourcesService", + "text": "HttpResourcesService" + }, + " implements ", + "CoreService", + "<", + "InternalHttpResourcesPreboot", + ", void>" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + "CoreContext" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.preboot", + "type": "Function", + "tags": [], + "label": "preboot", + "description": [], + "signature": [ + "(deps: ", + "PrebootDeps", + ") => { createRegistrar: (router: ", + "IRouter", + "<", + "RequestHandlerContext", + ">) => ", + "HttpResources", + "; }" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.preboot.$1", + "type": "Object", + "tags": [], + "label": "deps", + "description": [], + "signature": [ + "PrebootDeps" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.setup", + "type": "Function", + "tags": [], + "label": "setup", + "description": [], + "signature": [ + "(deps: ", + "SetupDeps", + ") => { createRegistrar: (router: ", + "IRouter", + "<", + "RequestHandlerContext", + ">) => ", + "HttpResources", + "; }" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.setup.$1", + "type": "Object", + "tags": [], + "label": "deps", + "description": [], + "signature": [ + "SetupDeps" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.start", + "type": "Function", + "tags": [], + "label": "start", + "description": [], + "signature": [ + "() => void" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-internal", + "id": "def-server.HttpResourcesService.stop", + "type": "Function", + "tags": [], + "label": "stop", + "description": [], + "signature": [ + "() => void" + ], + "path": "packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx new file mode 100644 index 0000000000000..b918bc6d6b705 --- /dev/null +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCoreHttpResourcesServerInternalPluginApi +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: 2022-10-06 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] +--- +import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; + + + +Contact [Owner missing] for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 9 | 0 | 9 | 3 | + +## Server + +### Classes + + diff --git a/api_docs/kbn_core_http_resources_server_mocks.devdocs.json b/api_docs/kbn_core_http_resources_server_mocks.devdocs.json new file mode 100644 index 0000000000000..619ba47e29df4 --- /dev/null +++ b/api_docs/kbn_core_http_resources_server_mocks.devdocs.json @@ -0,0 +1,307 @@ +{ + "id": "@kbn/core-http-resources-server-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.HttpResourcesMock", + "type": "Type", + "tags": [], + "label": "HttpResourcesMock", + "description": [], + "signature": [ + "{ setup: jest.MockInstance<{ createRegistrar: (router: ", + "IRouter", + "<", + "RequestHandlerContext", + ">) => ", + "HttpResources", + "; }, [deps: ", + "SetupDeps", + "]>; start: jest.MockInstance; stop: jest.MockInstance; preboot: jest.MockInstance<{ createRegistrar: (router: ", + "IRouter", + "<", + "RequestHandlerContext", + ">) => ", + "HttpResources", + "; }, [deps: ", + "PrebootDeps", + "]>; } & ", + "PublicMethodsOf", + "<", + "HttpResourcesService", + ">" + ], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [ + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.httpResourcesMock", + "type": "Object", + "tags": [], + "label": "httpResourcesMock", + "description": [], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.httpResourcesMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/core-http-resources-server-mocks", + "scope": "server", + "docId": "kibKbnCoreHttpResourcesServerMocksPluginApi", + "section": "def-server.HttpResourcesMock", + "text": "HttpResourcesMock" + } + ], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.httpResourcesMock.createRegistrar", + "type": "Function", + "tags": [], + "label": "createRegistrar", + "description": [], + "signature": [ + "() => jest.Mocked<", + "HttpResources", + ">" + ], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.httpResourcesMock.createPrebootContract", + "type": "Function", + "tags": [], + "label": "createPrebootContract", + "description": [], + "signature": [ + "() => { createRegistrar: jest.Mock, []>; }" + ], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.httpResourcesMock.createSetupContract", + "type": "Function", + "tags": [], + "label": "createSetupContract", + "description": [], + "signature": [ + "() => { createRegistrar: jest.Mock, []>; }" + ], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-http-resources-server-mocks", + "id": "def-server.httpResourcesMock.createResponseFactory", + "type": "Function", + "tags": [], + "label": "createResponseFactory", + "description": [], + "signature": [ + "() => { renderCoreApp: jest.MockInstance>, [options?: ", + "HttpResourcesRenderOptions", + " | undefined]> & ((options?: ", + "HttpResourcesRenderOptions", + " | undefined) => Promise<", + "IKibanaResponse", + ">); renderAnonymousCoreApp: jest.MockInstance>, [options?: ", + "HttpResourcesRenderOptions", + " | undefined]> & ((options?: ", + "HttpResourcesRenderOptions", + " | undefined) => Promise<", + "IKibanaResponse", + ">); renderHtml: jest.MockInstance<", + "IKibanaResponse", + ", [options: ", + "HttpResponseOptions", + "]> & ((options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", + "); renderJs: jest.MockInstance<", + "IKibanaResponse", + ", [options: ", + "HttpResponseOptions", + "]> & ((options: ", + "HttpResponseOptions", + ") => ", + "IKibanaResponse", + "); ok: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "HttpResponseOptions", + " | undefined]> & ((options?: ", + "HttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); accepted: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "HttpResponseOptions", + " | undefined]> & ((options?: ", + "HttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); noContent: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "HttpResponseOptions", + " | undefined]> & ((options?: ", + "HttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); redirected: jest.MockInstance<", + "IKibanaResponse", + ", [options: ", + "RedirectResponseOptions", + "]> & ((options: ", + "RedirectResponseOptions", + ") => ", + "IKibanaResponse", + "); badRequest: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "ErrorHttpResponseOptions", + " | undefined]> & ((options?: ", + "ErrorHttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); unauthorized: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "ErrorHttpResponseOptions", + " | undefined]> & ((options?: ", + "ErrorHttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); forbidden: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "ErrorHttpResponseOptions", + " | undefined]> & ((options?: ", + "ErrorHttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); notFound: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "ErrorHttpResponseOptions", + " | undefined]> & ((options?: ", + "ErrorHttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); conflict: jest.MockInstance<", + "IKibanaResponse", + ", [options?: ", + "ErrorHttpResponseOptions", + " | undefined]> & ((options?: ", + "ErrorHttpResponseOptions", + " | undefined) => ", + "IKibanaResponse", + "); customError: jest.MockInstance<", + "IKibanaResponse", + ", [options: ", + "CustomHttpResponseOptions", + "<", + "Stream", + " | Buffer | ", + "ResponseError", + ">]> & ((options: ", + "CustomHttpResponseOptions", + "<", + "Stream", + " | Buffer | ", + "ResponseError", + ">) => ", + "IKibanaResponse", + "); custom: jest.MockInstance<", + "IKibanaResponse", + ", [options: ", + "CustomHttpResponseOptions", + " | Error | ", + "Stream", + " | Buffer | { message: string | Error; attributes?: ", + "ResponseErrorAttributes", + " | undefined; } | undefined>]> & ( | Error | ", + "Stream", + " | Buffer | { message: string | Error; attributes?: ", + "ResponseErrorAttributes", + " | undefined; } | undefined>(options: ", + "CustomHttpResponseOptions", + ") => ", + "IKibanaResponse", + "); }" + ], + "path": "packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx new file mode 100644 index 0000000000000..a1250845e2b0b --- /dev/null +++ b/api_docs/kbn_core_http_resources_server_mocks.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: kibKbnCoreHttpResourcesServerMocksPluginApi +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: 2022-10-06 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] +--- +import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 7 | 0 | 7 | 0 | + +## Server + +### Objects + + +### Consts, variables and types + + diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 7654b3f70cc87..5ed760565043c 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: 2022-10-03 +date: 2022-10-06 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 8a2d3a3de3333..f1fe516abbd34 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: 2022-10-03 +date: 2022-10-06 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.mdx b/api_docs/kbn_core_http_server.mdx index 62b834449c23f..aa3be72111768 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: 2022-10-03 +date: 2022-10-06 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 bbda88d5c238c..6bbe24eabfcd4 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: 2022-10-03 +date: 2022-10-06 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 e99fba0127cc2..658135433521f 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: 2022-10-03 +date: 2022-10-06 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 c6da1dc82bc90..022dd32ee2f58 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: 2022-10-03 +date: 2022-10-06 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 140e346128004..0f0453271be2d 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: 2022-10-03 +date: 2022-10-06 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 ddd02e61d7ee4..93f957f1bff0f 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: 2022-10-03 +date: 2022-10-06 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 56636905f7afa..dc3bb6db57760 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: 2022-10-03 +date: 2022-10-06 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 f8ed8c6f0bec6..06ebfa4d3e362 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: 2022-10-03 +date: 2022-10-06 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.mdx b/api_docs/kbn_core_injected_metadata_browser.mdx index 9a02125114dc7..2f6827a5b0d22 100644 --- a/api_docs/kbn_core_injected_metadata_browser.mdx +++ b/api_docs/kbn_core_injected_metadata_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser title: "@kbn/core-injected-metadata-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser'] --- import kbnCoreInjectedMetadataBrowserObj from './kbn_core_injected_metadata_browser.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 d6a078aef0df0..cd821cb9e7553 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: 2022-10-03 +date: 2022-10-06 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 38c283eaaf97e..1c977c5107c9a 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: 2022-10-03 +date: 2022-10-06 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 5cc58ad5a914c..c2bdd99be6230 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: 2022-10-03 +date: 2022-10-06 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 1ab8822af2252..c8edafa6020d9 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: 2022-10-03 +date: 2022-10-06 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 99d9d3f32d3e8..b408b3b53eb4b 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: 2022-10-03 +date: 2022-10-06 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_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 5065fff3211ff..95b863bf59896 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: 2022-10-03 +date: 2022-10-06 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 2e6959cc87594..70027166bc5cf 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: 2022-10-03 +date: 2022-10-06 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 81a53652b4ea2..cda1d082783fd 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: 2022-10-03 +date: 2022-10-06 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.devdocs.json b/api_docs/kbn_core_metrics_collectors_server_internal.devdocs.json index 0de9634445ccd..8713e12e2a39f 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.devdocs.json +++ b/api_docs/kbn_core_metrics_collectors_server_internal.devdocs.json @@ -10,6 +10,100 @@ }, "server": { "classes": [ + { + "parentPluginId": "@kbn/core-metrics-collectors-server-internal", + "id": "def-server.ElasticsearchClientsMetricsCollector", + "type": "Class", + "tags": [], + "label": "ElasticsearchClientsMetricsCollector", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-metrics-collectors-server-internal", + "scope": "server", + "docId": "kibKbnCoreMetricsCollectorsServerInternalPluginApi", + "section": "def-server.ElasticsearchClientsMetricsCollector", + "text": "ElasticsearchClientsMetricsCollector" + }, + " implements ", + "MetricsCollector", + "<", + "ElasticsearchClientsMetrics", + ">" + ], + "path": "packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-metrics-collectors-server-internal", + "id": "def-server.ElasticsearchClientsMetricsCollector.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-metrics-collectors-server-internal", + "id": "def-server.ElasticsearchClientsMetricsCollector.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "agentStore", + "description": [], + "signature": [ + "AgentStore" + ], + "path": "packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-metrics-collectors-server-internal", + "id": "def-server.ElasticsearchClientsMetricsCollector.collect", + "type": "Function", + "tags": [], + "label": "collect", + "description": [], + "signature": [ + "() => Promise<", + "ElasticsearchClientsMetrics", + ">" + ], + "path": "packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/core-metrics-collectors-server-internal", + "id": "def-server.ElasticsearchClientsMetricsCollector.reset", + "type": "Function", + "tags": [], + "label": "reset", + "description": [], + "signature": [ + "() => void" + ], + "path": "packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-metrics-collectors-server-internal", "id": "def-server.EventLoopDelaysMonitor", diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 3d5b6fffdd513..dab15edff1d0f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 24 | 0 | 20 | 0 | +| 29 | 0 | 25 | 0 | ## Server diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 14756f136bd3a..fc2ab0af80d08 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: 2022-10-03 +date: 2022-10-06 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.devdocs.json b/api_docs/kbn_core_metrics_server.devdocs.json index 77ae844e93992..6413560fea457 100644 --- a/api_docs/kbn_core_metrics_server.devdocs.json +++ b/api_docs/kbn_core_metrics_server.devdocs.json @@ -12,6 +12,168 @@ "classes": [], "functions": [], "interfaces": [ + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics", + "type": "Interface", + "tags": [], + "label": "ElasticsearchClientsMetrics", + "description": [ + "\nMetrics related to the elasticsearch clients" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.protocol", + "type": "CompoundType", + "tags": [], + "label": "protocol", + "description": [ + "The protocol (or protocols) that these Agents are using" + ], + "signature": [ + "\"http\" | \"none\" | \"mixed\" | \"https\"" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.connectedNodes", + "type": "number", + "tags": [], + "label": "connectedNodes", + "description": [ + "Number of ES nodes that ES-js client is connecting to" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.nodesWithActiveSockets", + "type": "number", + "tags": [], + "label": "nodesWithActiveSockets", + "description": [ + "Number of nodes with active connections" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.nodesWithIdleSockets", + "type": "number", + "tags": [], + "label": "nodesWithIdleSockets", + "description": [ + "Number of nodes with available connections (alive but idle).\nNote that a node can have both active and idle connections at the same time" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.totalActiveSockets", + "type": "number", + "tags": [], + "label": "totalActiveSockets", + "description": [ + "Total number of active sockets (all nodes, all connections)" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.totalIdleSockets", + "type": "number", + "tags": [], + "label": "totalIdleSockets", + "description": [ + "Total number of available sockets (alive but idle, all nodes, all connections)" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.totalQueuedRequests", + "type": "number", + "tags": [], + "label": "totalQueuedRequests", + "description": [ + "Total number of queued requests (all nodes, all connections)" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.mostActiveNodeSockets", + "type": "number", + "tags": [], + "label": "mostActiveNodeSockets", + "description": [ + "Number of active connections of the node with most active connections" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.averageActiveSocketsPerNode", + "type": "number", + "tags": [], + "label": "averageActiveSocketsPerNode", + "description": [ + "Average of active sockets per node (all connections)" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.mostIdleNodeSockets", + "type": "number", + "tags": [], + "label": "mostIdleNodeSockets", + "description": [ + "Number of idle connections of the node with most idle connections" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientsMetrics.averageIdleSocketsPerNode", + "type": "number", + "tags": [], + "label": "averageIdleSocketsPerNode", + "description": [ + "Average of available (idle) sockets per node (all connections)" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-metrics-server", "id": "def-server.IEventLoopDelaysMonitor", @@ -349,6 +511,28 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.OpsMetrics.elasticsearch_client", + "type": "Object", + "tags": [], + "label": "elasticsearch_client", + "description": [ + "\nMetrics related to the elasticsearch client" + ], + "signature": [ + { + "pluginId": "@kbn/core-metrics-server", + "scope": "server", + "docId": "kibKbnCoreMetricsServerPluginApi", + "section": "def-server.ElasticsearchClientsMetrics", + "text": "ElasticsearchClientsMetrics" + } + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-metrics-server", "id": "def-server.OpsMetrics.process", @@ -779,6 +963,23 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/core-metrics-server", + "id": "def-server.ElasticsearchClientProtocol", + "type": "Type", + "tags": [], + "label": "ElasticsearchClientProtocol", + "description": [ + "\nProtocol(s) used by the Elasticsearch Client" + ], + "signature": [ + "\"http\" | \"none\" | \"mixed\" | \"https\"" + ], + "path": "packages/core/metrics/core-metrics-server/src/metrics.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/core-metrics-server", "id": "def-server.MetricsServiceStart", diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 087dd2dd357ca..d51ee1a48372e 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 48 | 0 | 8 | 0 | +| 62 | 0 | 8 | 0 | ## Server diff --git a/api_docs/kbn_core_metrics_server_internal.devdocs.json b/api_docs/kbn_core_metrics_server_internal.devdocs.json index dfdb1f7c95ef5..0920f42e9bf88 100644 --- a/api_docs/kbn_core_metrics_server_internal.devdocs.json +++ b/api_docs/kbn_core_metrics_server_internal.devdocs.json @@ -36,6 +36,20 @@ "path": "packages/core/metrics/core-metrics-server-internal/src/metrics_service.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-internal", + "id": "def-server.MetricsServiceSetupDeps.elasticsearchService", + "type": "Object", + "tags": [], + "label": "elasticsearchService", + "description": [], + "signature": [ + "InternalElasticsearchServiceSetup" + ], + "path": "packages/core/metrics/core-metrics-server-internal/src/metrics_service.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index 5f5ea85f80056..576df1b888eff 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 5 | 0 | 5 | 0 | +| 6 | 0 | 6 | 0 | ## Server diff --git a/api_docs/kbn_core_metrics_server_mocks.devdocs.json b/api_docs/kbn_core_metrics_server_mocks.devdocs.json index 1ca231c151d2f..9e06f6bcaef02 100644 --- a/api_docs/kbn_core_metrics_server_mocks.devdocs.json +++ b/api_docs/kbn_core_metrics_server_mocks.devdocs.json @@ -133,6 +133,144 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics", + "type": "Object", + "tags": [], + "label": "sampleEsClientMetrics", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.protocol", + "type": "string", + "tags": [], + "label": "protocol", + "description": [], + "signature": [ + "\"https\"" + ], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.connectedNodes", + "type": "number", + "tags": [], + "label": "connectedNodes", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.nodesWithActiveSockets", + "type": "number", + "tags": [], + "label": "nodesWithActiveSockets", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.nodesWithIdleSockets", + "type": "number", + "tags": [], + "label": "nodesWithIdleSockets", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.totalActiveSockets", + "type": "number", + "tags": [], + "label": "totalActiveSockets", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.totalIdleSockets", + "type": "number", + "tags": [], + "label": "totalIdleSockets", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.totalQueuedRequests", + "type": "number", + "tags": [], + "label": "totalQueuedRequests", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.mostActiveNodeSockets", + "type": "number", + "tags": [], + "label": "mostActiveNodeSockets", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.averageActiveSocketsPerNode", + "type": "number", + "tags": [], + "label": "averageActiveSocketsPerNode", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.mostIdleNodeSockets", + "type": "number", + "tags": [], + "label": "mostIdleNodeSockets", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-metrics-server-mocks", + "id": "def-server.sampleEsClientMetrics.averageIdleSocketsPerNode", + "type": "number", + "tags": [], + "label": "averageIdleSocketsPerNode", + "description": [], + "path": "packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false } ] }, diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 6216a6d589ce5..27f2773bcaf1e 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; @@ -21,7 +21,7 @@ Contact Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 7 | 0 | 7 | 0 | +| 19 | 0 | 19 | 0 | ## Server diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 82c2c06e08457..fe5c4df3d7e9d 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: 2022-10-03 +date: 2022-10-06 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 b4eeaf823c522..fc5ddf823aec6 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: 2022-10-03 +date: 2022-10-06 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 04c3664f49b67..d7fa4b1bd0cf0 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: 2022-10-03 +date: 2022-10-06 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 edcf4af2b62ad..2f443063be9ba 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: 2022-10-03 +date: 2022-10-06 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 d120b6ccece74..5bcb7bca3ba2f 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: 2022-10-03 +date: 2022-10-06 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 e4152c45f1f60..cbda3f8cfd60d 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: 2022-10-03 +date: 2022-10-06 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 a571fb85c2ef4..c64ab9e8eb2c0 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: 2022-10-03 +date: 2022-10-06 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 8f4457512da88..3d470003a022a 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: 2022-10-03 +date: 2022-10-06 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 6e25c69de32ee..79cdb7893d28b 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: 2022-10-03 +date: 2022-10-06 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 ce41f3aac1f43..8df3ef3916550 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: 2022-10-03 +date: 2022-10-06 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 0b413f962b275..3aee25fa6049f 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: 2022-10-03 +date: 2022-10-06 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 b31af30c16030..3f7f5ef6918a1 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: 2022-10-03 +date: 2022-10-06 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_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index ec6b64842af42..941308dd87192 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: 2022-10-03 +date: 2022-10-06 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 583b5bc973add..b3f234c67bbb8 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: 2022-10-03 +date: 2022-10-06 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 383e9c6511efa..977c8dce67961 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: 2022-10-03 +date: 2022-10-06 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.devdocs.json b/api_docs/kbn_core_rendering_server_internal.devdocs.json new file mode 100644 index 0000000000000..d765832debee1 --- /dev/null +++ b/api_docs/kbn_core_rendering_server_internal.devdocs.json @@ -0,0 +1,61 @@ +{ + "id": "@kbn/core-rendering-server-internal", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/core-rendering-server-internal", + "id": "def-server.Fonts", + "type": "Function", + "tags": [], + "label": "Fonts", + "description": [], + "signature": [ + "({ url }: React.PropsWithChildren) => JSX.Element" + ], + "path": "packages/core/rendering/core-rendering-server-internal/src/views/fonts.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-rendering-server-internal", + "id": "def-server.Fonts.$1", + "type": "CompoundType", + "tags": [], + "label": "{ url }", + "description": [], + "signature": [ + "React.PropsWithChildren" + ], + "path": "packages/core/rendering/core-rendering-server-internal/src/views/fonts.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx new file mode 100644 index 0000000000000..859521cbf716f --- /dev/null +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCoreRenderingServerInternalPluginApi +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: 2022-10-06 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] +--- +import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 2 | 0 | 2 | 0 | + +## Server + +### Functions + + diff --git a/api_docs/kbn_core_rendering_server_mocks.devdocs.json b/api_docs/kbn_core_rendering_server_mocks.devdocs.json new file mode 100644 index 0000000000000..fc43829e9518e --- /dev/null +++ b/api_docs/kbn_core_rendering_server_mocks.devdocs.json @@ -0,0 +1,95 @@ +{ + "id": "@kbn/core-rendering-server-mocks", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [ + { + "parentPluginId": "@kbn/core-rendering-server-mocks", + "id": "def-server.renderingServiceMock", + "type": "Object", + "tags": [], + "label": "renderingServiceMock", + "description": [], + "path": "packages/core/rendering/core-rendering-server-mocks/src/rendering_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-rendering-server-mocks", + "id": "def-server.renderingServiceMock.create", + "type": "Function", + "tags": [], + "label": "create", + "description": [], + "signature": [ + "() => ", + "RenderingServiceMock" + ], + "path": "packages/core/rendering/core-rendering-server-mocks/src/rendering_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-rendering-server-mocks", + "id": "def-server.renderingServiceMock.createPrebootContract", + "type": "Function", + "tags": [], + "label": "createPrebootContract", + "description": [], + "signature": [ + "() => jest.Mocked<", + "InternalRenderingServiceSetup", + ">" + ], + "path": "packages/core/rendering/core-rendering-server-mocks/src/rendering_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + }, + { + "parentPluginId": "@kbn/core-rendering-server-mocks", + "id": "def-server.renderingServiceMock.createSetupContract", + "type": "Function", + "tags": [], + "label": "createSetupContract", + "description": [], + "signature": [ + "() => jest.Mocked<", + "InternalRenderingServiceSetup", + ">" + ], + "path": "packages/core/rendering/core-rendering-server-mocks/src/rendering_service.mock.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [] + } + ], + "initialIsOpen": false + } + ] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx new file mode 100644 index 0000000000000..02b09cf82fe8e --- /dev/null +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -0,0 +1,30 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnCoreRenderingServerMocksPluginApi +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: 2022-10-06 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] +--- +import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; + + + +Contact Kibana Core for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 4 | 0 | 4 | 1 | + +## Server + +### Objects + + diff --git a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json index bc6024dea788e..19434ae87b701 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_browser.devdocs.json @@ -1980,7 +1980,11 @@ "SavedObjectsFindOptionsReference", " | ", "SavedObjectsFindOptionsReference", - "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; preference?: string | undefined; }" + "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; hasNoReference?: ", + "SavedObjectsFindOptionsReference", + " | ", + "SavedObjectsFindOptionsReference", + "[] | undefined; hasNoReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; preference?: string | undefined; }" ], "path": "packages/core/saved-objects/core-saved-objects-api-browser/src/apis/find.ts", "deprecated": false, diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index e07f5797c7f72..f800ab175a6aa 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: 2022-10-03 +date: 2022-10-06 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 1bff25681bdbf..cae43e5b22b0d 100644 --- a/api_docs/kbn_core_saved_objects_api_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_api_server.devdocs.json @@ -5207,6 +5207,53 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/core-saved-objects-api-server", + "id": "def-server.SavedObjectsFindOptions.hasNoReference", + "type": "CompoundType", + "tags": [], + "label": "hasNoReference", + "description": [ + "\nSearch for documents *not* having a reference to the specified objects.\nUse `hasNoReferenceOperator` to specify the operator to use when searching for multiple references." + ], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + " | ", + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + "[] | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/find.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/core-saved-objects-api-server", + "id": "def-server.SavedObjectsFindOptions.hasNoReferenceOperator", + "type": "CompoundType", + "tags": [], + "label": "hasNoReferenceOperator", + "description": [ + "\nThe operator to use when searching by multiple references using the `hasNoReference` option. Defaults to `OR`" + ], + "signature": [ + "\"AND\" | \"OR\" | undefined" + ], + "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/find.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/core-saved-objects-api-server", "id": "def-server.SavedObjectsFindOptions.defaultSearchOperator", @@ -6447,7 +6494,23 @@ "section": "def-server.SavedObjectsFindOptionsReference", "text": "SavedObjectsFindOptionsReference" }, - "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; }" + "[] | undefined; hasReferenceOperator?: \"AND\" | \"OR\" | undefined; hasNoReference?: ", + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + " | ", + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsFindOptionsReference", + "text": "SavedObjectsFindOptionsReference" + }, + "[] | undefined; hasNoReferenceOperator?: \"AND\" | \"OR\" | undefined; defaultSearchOperator?: \"AND\" | \"OR\" | undefined; namespaces?: string[] | undefined; typeToNamespacesMap?: Map | undefined; preference?: string | undefined; }" ], "path": "packages/core/saved-objects/core-saved-objects-api-server/src/apis/create_point_in_time_finder.ts", "deprecated": false, diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 8a3662b8b470c..86c81053a0d32 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: 2022-10-03 +date: 2022-10-06 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 Kibana Core for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 308 | 1 | 137 | 0 | +| 310 | 1 | 137 | 0 | ## Server diff --git a/api_docs/kbn_core_saved_objects_api_server_internal.mdx b/api_docs/kbn_core_saved_objects_api_server_internal.mdx index 7244cfe8beb60..ae27ed5870cc3 100644 --- a/api_docs/kbn_core_saved_objects_api_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-internal title: "@kbn/core-saved-objects-api-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-internal plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-internal'] --- import kbnCoreSavedObjectsApiServerInternalObj from './kbn_core_saved_objects_api_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 9a62ec00bb37c..626fb644b7ce8 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: 2022-10-03 +date: 2022-10-06 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 4068fcf5e73b5..17e6c27821405 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: 2022-10-03 +date: 2022-10-06 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 7af80f7527944..d37f6015cd789 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: 2022-10-03 +date: 2022-10-06 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 83b6f08887286..752f4433f21be 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: 2022-10-03 +date: 2022-10-06 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 3d8e3d03be29b..dd7230fe80961 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: 2022-10-03 +date: 2022-10-06 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 ad03d6488f2a0..fd80b207a1786 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: 2022-10-03 +date: 2022-10-06 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 b06d26ed9bea4..a54399a09eae8 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: 2022-10-03 +date: 2022-10-06 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 6532dfcaeaf81..b4fbd9d1a266d 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: 2022-10-03 +date: 2022-10-06 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 53092b90fc151..a56b29c91f96f 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: 2022-10-03 +date: 2022-10-06 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 3d1544f4f110f..f7dabede7c494 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: 2022-10-03 +date: 2022-10-06 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 c662be1f8fb09..82b24420b5589 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 8a27161ad18de..0e9e1334e3e2f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index c73c73d974180..b6210307125ac 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: 2022-10-03 +date: 2022-10-06 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 e8fe3856fa57f..3ca33d3256634 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: 2022-10-03 +date: 2022-10-06 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 5eb6ed5fabf23..19a4351c31f18 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: 2022-10-03 +date: 2022-10-06 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 3f9ec5be08ad2..d04df59d4f356 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: 2022-10-03 +date: 2022-10-06 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 fd7956ee7ab43..a96c2b54c908d 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: 2022-10-03 +date: 2022-10-06 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 71ceb6a7bede4..2534a673f1684 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: 2022-10-03 +date: 2022-10-06 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 3916cb3c3119c..9bb80d23dfd14 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: 2022-10-03 +date: 2022-10-06 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 966876de9b0c2..e11fca267daea 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: 2022-10-03 +date: 2022-10-06 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 f3ad0c01cc377..27b696df00b94 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: 2022-10-03 +date: 2022-10-06 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 995497dffa505..43899ddf76a4d 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: 2022-10-03 +date: 2022-10-06 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_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 2db8ecd68b0dc..b267833018328 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: 2022-10-03 +date: 2022-10-06 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_internal.mdx b/api_docs/kbn_core_theme_browser_internal.mdx index 38778f82b4a73..a4f551e1ce3e0 100644 --- a/api_docs/kbn_core_theme_browser_internal.mdx +++ b/api_docs/kbn_core_theme_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-internal title: "@kbn/core-theme-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-internal plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-internal'] --- import kbnCoreThemeBrowserInternalObj from './kbn_core_theme_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index d561c846ba528..db77500f1c43a 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: 2022-10-03 +date: 2022-10-06 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 f4b08646423d6..8891328601ee3 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: 2022-10-03 +date: 2022-10-06 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 607eaa47b682d..eb640e052fd6a 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: 2022-10-03 +date: 2022-10-06 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 15ecdc9fee508..d1c792aa36822 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: 2022-10-03 +date: 2022-10-06 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 6644389a6513b..c179f33b8e35f 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: 2022-10-03 +date: 2022-10-06 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 d486425f2067d..b5986a472e19b 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: 2022-10-03 +date: 2022-10-06 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 98b9aa8e6584a..6d931537f7dcb 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: 2022-10-03 +date: 2022-10-06 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 c287c7d3717f4..94f5096d515fe 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: 2022-10-03 +date: 2022-10-06 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 8d5b6922438e8..625fe34ba1d3e 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: 2022-10-03 +date: 2022-10-06 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 e433b18463057..515733770b1e8 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: 2022-10-03 +date: 2022-10-06 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 ad3dac588eb63..3b3221c6d8a78 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: 2022-10-03 +date: 2022-10-06 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_crypto.mdx b/api_docs/kbn_crypto.mdx index 0e41431342876..32aeb4662b309 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: 2022-10-03 +date: 2022-10-06 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 7f67262cf91c9..5f61fcd38f75e 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 86cc145ec159a..bc19402e70392 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index e46730cf719c3..f6b9c5ed522ff 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: 2022-10-03 +date: 2022-10-06 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 54d0f8713d0fb..a527246dbec89 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: 2022-10-03 +date: 2022-10-06 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 b646fc86f43f5..a63ad446c17ee 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: 2022-10-03 +date: 2022-10-06 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 83091d9879dc4..c4bdbbc95f00b 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index d74d520ff8430..f33cd5818490a 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -300,7 +300,7 @@ "label": "enterpriseSearch", "description": [], "signature": [ - "{ readonly apiKeys: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; readonly contentExtraction: string; readonly crawlerGettingStarted: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly documentLevelSecurity: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly mailService: string; readonly start: string; readonly troubleshootSetup: string; readonly usersAccess: string; }" + "{ readonly apiKeys: string; readonly bulkApi: string; readonly configuration: string; readonly connectors: string; readonly connectorsMongoDB: string; readonly connectorsMySQL: string; readonly connectorsWorkplaceSearch: string; readonly contentExtraction: string; readonly crawlerGettingStarted: string; readonly crawlerManaging: string; readonly crawlerOverview: string; readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; readonly languageClients: string; readonly licenseManagement: string; readonly mailService: string; readonly start: string; readonly troubleshootSetup: string; readonly usersAccess: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -546,7 +546,7 @@ "label": "securitySolution", "description": [], "signature": [ - "{ readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; linux_deadlock: string; }; readonly packageActionTroubleshooting: { es_connection: string; }; readonly threatIntelInt: string; readonly responseActions: string; }" + "{ readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; readonly endpointArtifacts: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; linux_deadlock: string; }; readonly packageActionTroubleshooting: { es_connection: string; }; readonly threatIntelInt: string; readonly responseActions: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -658,7 +658,7 @@ "label": "observability", "description": [], "signature": [ - "{ readonly guide: string; readonly infrastructureThreshold: string; readonly logsThreshold: string; readonly metricsThreshold: string; readonly monitorStatus: string; readonly monitorUptime: string; readonly tlsCertificate: string; readonly uptimeDurationAnomaly: string; readonly monitorLogs: string; readonly analyzeMetrics: string; readonly monitorUptimeSynthetics: string; readonly userExperience: string; readonly createAlerts: string; readonly syntheticsCommandReference: string; }" + "{ readonly guide: string; readonly infrastructureThreshold: string; readonly logsThreshold: string; readonly metricsThreshold: string; readonly monitorStatus: string; readonly monitorUptime: string; readonly tlsCertificate: string; readonly uptimeDurationAnomaly: string; readonly monitorLogs: string; readonly analyzeMetrics: string; readonly monitorUptimeSynthetics: string; readonly userExperience: string; readonly createAlerts: string; readonly syntheticsCommandReference: string; readonly syntheticsProjectMonitors: 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 8913a1a03ab85..ce723e081565b 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: 2022-10-03 +date: 2022-10-06 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 a5d4079c284b0..da82c011247f8 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index 8370c22a01f19..254af794fe507 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 4ad77bfff6559..447de8fbc7849 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index bf9c27ac92b27..4d3187aee95d4 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.devdocs.json b/api_docs/kbn_es_query.devdocs.json index d84edf5ed8652..3bd7db808950c 100644 --- a/api_docs/kbn_es_query.devdocs.json +++ b/api_docs/kbn_es_query.devdocs.json @@ -765,6 +765,47 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.buildOrFilter", + "type": "Function", + "tags": [], + "label": "buildOrFilter", + "description": [ + "\nBuilds an OR filter. An OR filter is a filter with multiple sub-filters. Each sub-filter (FilterItem) represents a\ncondition." + ], + "signature": [ + "(filters: ", + "FilterItem", + "[]) => ", + "OrFilter" + ], + "path": "packages/kbn-es-query/src/filters/build_filters/or_filter.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.buildOrFilter.$1", + "type": "Array", + "tags": [], + "label": "filters", + "description": [ + "An array of OrFilterItem" + ], + "signature": [ + "FilterItem", + "[]" + ], + "path": "packages/kbn-es-query/src/filters/build_filters/or_filter.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.buildPhraseFilter", @@ -1108,7 +1149,7 @@ "section": "def-common.DataViewBase", "text": "DataViewBase" }, - "[] | undefined, { ignoreFilterIfFieldNotInIndex, nestedIgnoreUnmapped }?: ", + "[] | undefined, options?: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -1186,7 +1227,7 @@ "id": "def-common.buildQueryFromFilters.$3", "type": "Object", "tags": [], - "label": "{ ignoreFilterIfFieldNotInIndex = false, nestedIgnoreUnmapped }", + "label": "options", "description": [], "signature": [ { @@ -2699,6 +2740,53 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.isOrFilter", + "type": "Function", + "tags": [], + "label": "isOrFilter", + "description": [], + "signature": [ + "(filter: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + ") => boolean" + ], + "path": "packages/kbn-es-query/src/filters/build_filters/or_filter.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/es-query", + "id": "def-common.isOrFilter.$1", + "type": "Object", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + } + ], + "path": "packages/kbn-es-query/src/filters/build_filters/or_filter.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/es-query", "id": "def-common.isPhraseFilter", diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index 632303fa82c97..c88bc07842c40 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 222 | 1 | 168 | 12 | +| 226 | 1 | 170 | 14 | ## Common diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index 6a6ac63f69acd..aa722e6cc6b08 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: 2022-10-03 +date: 2022-10-06 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 e0525000b5f9f..ef72cac235fa6 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index f9ad3846f19fa..b108ca610fad9 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: 2022-10-03 +date: 2022-10-06 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 9bc0b92168240..0efd1824a65e9 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: 2022-10-03 +date: 2022-10-06 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 359334478d03d..c57dd51b1b47f 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: 2022-10-03 +date: 2022-10-06 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 151e0da4dd3b1..d1779e5e76f60 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_get_repo_files.mdx b/api_docs/kbn_get_repo_files.mdx index 161354bbbcb14..8a977208e5ed1 100644 --- a/api_docs/kbn_get_repo_files.mdx +++ b/api_docs/kbn_get_repo_files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-get-repo-files title: "@kbn/get-repo-files" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/get-repo-files plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/get-repo-files'] --- import kbnGetRepoFilesObj from './kbn_get_repo_files.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 1e054c0706c6f..ce31bb8e7e81b 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: 2022-10-03 +date: 2022-10-06 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 0852dda61f29a..f3a2ae7cad264 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index d4cca06818606..01bf80f297c5b 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: 2022-10-03 +date: 2022-10-06 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 54d4d15fc741e..c5360084d04ca 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: 2022-10-03 +date: 2022-10-06 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 c7ff5b8ab5056..ef600c2c84921 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 262e79df335d1..a9873980a6b27 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index df20b5d894c5e..6ad1ed47c2664 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: 2022-10-03 +date: 2022-10-06 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 4994d60766a45..db7c8e6564d95 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: 2022-10-03 +date: 2022-10-06 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 e5e069f91c957..0fd30b688ee50 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: 2022-10-03 +date: 2022-10-06 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 21477f1c435c7..55b5077c93e28 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 6d9b4a9bb317c..4e945cee6f8ba 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 712dd79f55359..1ee3f785c0026 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: 2022-10-03 +date: 2022-10-06 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 6dcc57446aaad..df7c3a246c022 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: 2022-10-03 +date: 2022-10-06 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 788e96c22f5c3..b3c1a2d04da4c 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 8e2ce8b3d9fdc..f812905cbecef 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 25b2b17e3997b..625e06d638c33 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: 2022-10-03 +date: 2022-10-06 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_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 5f24dc1806b03..373e22799a9aa 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: 2022-10-03 +date: 2022-10-06 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_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 2fa9ac8d84b7a..ea07ae8cee257 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index c5b48fbeff006..523635c337647 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 2a5d7bc10afb8..9c2a6d08b5b61 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: 2022-10-03 +date: 2022-10-06 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 3f87a2b8b79d8..bd61c610b0922 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: 2022-10-03 +date: 2022-10-06 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 76d9089526cec..efbe102abed17 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: 2022-10-03 +date: 2022-10-06 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 3e83e64f435dc..c2e86d4baede3 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: 2022-10-03 +date: 2022-10-06 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 dc887c9ce3056..68dcedaac112f 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: 2022-10-03 +date: 2022-10-06 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 30cf3560edd3a..5b3a980639f36 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index ae485f79249a3..41e10f6dd959b 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index 8249b1eae5a39..bec1923dad883 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.devdocs.json b/api_docs/kbn_rule_data_utils.devdocs.json index 2d6403bd41dfe..513060301f142 100644 --- a/api_docs/kbn_rule_data_utils.devdocs.json +++ b/api_docs/kbn_rule_data_utils.devdocs.json @@ -844,6 +844,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/rule-data-utils", + "id": "def-common.ALERT_TIME_RANGE", + "type": "string", + "tags": [], + "label": "ALERT_TIME_RANGE", + "description": [], + "signature": [ + "\"kibana.alert.time_range\"" + ], + "path": "packages/kbn-rule-data-utils/src/technical_field_names.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/rule-data-utils", "id": "def-common.ALERT_UUID", @@ -942,7 +957,7 @@ "label": "AlertStatus", "description": [], "signature": [ - "\"recovered\" | \"active\"" + "\"active\" | \"recovered\"" ], "path": "packages/kbn-rule-data-utils/src/alerts_as_data_status.ts", "deprecated": false, @@ -1077,7 +1092,7 @@ "label": "TechnicalRuleDataFieldName", "description": [], "signature": [ - "\"tags\" | \"kibana\" | \"@timestamp\" | \"kibana.alert.rule.rule_type_id\" | \"kibana.alert.rule.consumer\" | \"event.action\" | \"kibana.alert.rule.execution.uuid\" | \"kibana.alert.rule.parameters\" | \"kibana.alert.rule.producer\" | \"kibana.space_ids\" | \"kibana.alert.uuid\" | \"kibana.alert.instance.id\" | \"kibana.alert.start\" | \"kibana.alert.end\" | \"kibana.alert.duration.us\" | \"kibana.alert.severity\" | \"kibana.alert.status\" | \"kibana.version\" | \"ecs.version\" | \"kibana.alert.risk_score\" | \"kibana.alert.workflow_status\" | \"kibana.alert.workflow_user\" | \"kibana.alert.workflow_reason\" | \"kibana.alert.system_status\" | \"kibana.alert.action_group\" | \"kibana.alert.reason\" | \"kibana.alert.rule.author\" | \"kibana.alert.rule.category\" | \"kibana.alert.rule.uuid\" | \"kibana.alert.rule.created_at\" | \"kibana.alert.rule.created_by\" | \"kibana.alert.rule.description\" | \"kibana.alert.rule.enabled\" | \"kibana.alert.rule.from\" | \"kibana.alert.rule.interval\" | \"kibana.alert.rule.license\" | \"kibana.alert.rule.name\" | \"kibana.alert.rule.note\" | \"kibana.alert.rule.references\" | \"kibana.alert.rule.rule_id\" | \"kibana.alert.rule.rule_name_override\" | \"kibana.alert.rule.tags\" | \"kibana.alert.rule.to\" | \"kibana.alert.rule.type\" | \"kibana.alert.rule.updated_at\" | \"kibana.alert.rule.updated_by\" | \"kibana.alert.rule.version\" | \"event.kind\" | \"event.module\" | \"kibana.alert.evaluation.threshold\" | \"kibana.alert.evaluation.value\" | \"kibana.alert.building_block_type\" | \"kibana.alert.rule.exceptions_list\" | \"kibana.alert.rule.namespace\" | \"kibana.alert\" | \"kibana.alert.rule\"" + "\"tags\" | \"kibana\" | \"@timestamp\" | \"kibana.alert.rule.rule_type_id\" | \"kibana.alert.rule.consumer\" | \"event.action\" | \"kibana.alert.rule.execution.uuid\" | \"kibana.alert.rule.parameters\" | \"kibana.alert.rule.producer\" | \"kibana.space_ids\" | \"kibana.alert.uuid\" | \"kibana.alert.instance.id\" | \"kibana.alert.start\" | \"kibana.alert.time_range\" | \"kibana.alert.end\" | \"kibana.alert.duration.us\" | \"kibana.alert.severity\" | \"kibana.alert.status\" | \"kibana.version\" | \"ecs.version\" | \"kibana.alert.risk_score\" | \"kibana.alert.workflow_status\" | \"kibana.alert.workflow_user\" | \"kibana.alert.workflow_reason\" | \"kibana.alert.system_status\" | \"kibana.alert.action_group\" | \"kibana.alert.reason\" | \"kibana.alert.rule.author\" | \"kibana.alert.rule.category\" | \"kibana.alert.rule.uuid\" | \"kibana.alert.rule.created_at\" | \"kibana.alert.rule.created_by\" | \"kibana.alert.rule.description\" | \"kibana.alert.rule.enabled\" | \"kibana.alert.rule.from\" | \"kibana.alert.rule.interval\" | \"kibana.alert.rule.license\" | \"kibana.alert.rule.name\" | \"kibana.alert.rule.note\" | \"kibana.alert.rule.references\" | \"kibana.alert.rule.rule_id\" | \"kibana.alert.rule.rule_name_override\" | \"kibana.alert.rule.tags\" | \"kibana.alert.rule.to\" | \"kibana.alert.rule.type\" | \"kibana.alert.rule.updated_at\" | \"kibana.alert.rule.updated_by\" | \"kibana.alert.rule.version\" | \"event.kind\" | \"event.module\" | \"kibana.alert.evaluation.threshold\" | \"kibana.alert.evaluation.value\" | \"kibana.alert.building_block_type\" | \"kibana.alert.rule.exceptions_list\" | \"kibana.alert.rule.namespace\" | \"kibana.alert\" | \"kibana.alert.rule\"" ], "path": "packages/kbn-rule-data-utils/src/technical_field_names.ts", "deprecated": false, diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index a4ef149f8033b..8ec82d44f0d39 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 74 | 0 | 71 | 0 | +| 75 | 0 | 72 | 0 | ## Common diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index ea7380185e08a..d1b78fa30591c 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 4f2b01b578636..6defc3cd40a27 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: 2022-10-03 +date: 2022-10-06 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 35651464e503c..2b4d40afc7485 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 74a60ea3a6e0d..40e8bc6d7eded 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: 2022-10-03 +date: 2022-10-06 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 a2e5cb79e7ec0..4bc6f2284b2aa 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: 2022-10-03 +date: 2022-10-06 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 878d21884f5ab..7ab03ed0421cd 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: 2022-10-03 +date: 2022-10-06 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 7009b4610d376..a0ee497d7f8cb 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: 2022-10-03 +date: 2022-10-06 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 1a8635741da38..e901b9d066c3a 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: 2022-10-03 +date: 2022-10-06 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 ba0f3639d8e00..df181121e0239 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: 2022-10-03 +date: 2022-10-06 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 cc6cd2e0e30ab..06e747627a86a 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: 2022-10-03 +date: 2022-10-06 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 c160feacf522f..b412fd5209b24 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: 2022-10-03 +date: 2022-10-06 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.devdocs.json b/api_docs/kbn_securitysolution_list_utils.devdocs.json index 0518a331879b0..39f11e812f589 100644 --- a/api_docs/kbn_securitysolution_list_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_list_utils.devdocs.json @@ -1514,7 +1514,7 @@ "label": "getNewExceptionItem", "description": [], "signature": [ - "({ listId, namespaceType, ruleName, }: { listId: string; namespaceType: \"single\" | \"agnostic\"; ruleName: string; }) => ", + "({ listId, namespaceType, ruleName, }: { listId: string | undefined; namespaceType: \"single\" | \"agnostic\" | undefined; ruleName: string; }) => ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -1545,6 +1545,9 @@ "tags": [], "label": "listId", "description": [], + "signature": [ + "string | undefined" + ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, "trackAdoption": false @@ -1557,7 +1560,7 @@ "label": "namespaceType", "description": [], "signature": [ - "\"single\" | \"agnostic\"" + "\"single\" | \"agnostic\" | undefined" ], "path": "packages/kbn-securitysolution-list-utils/src/helpers/index.ts", "deprecated": false, @@ -2597,7 +2600,7 @@ "label": "CreateExceptionListItemBuilderSchema", "description": [], "signature": [ - "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }, \"meta\" | \"entries\"> & { meta: { temporaryUuid: string; }; entries: ", + "Omit<{ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }, \"meta\" | \"entries\" | \"list_id\" | \"namespace_type\"> & { meta: { temporaryUuid: string; }; entries: ", { "pluginId": "@kbn/securitysolution-list-utils", "scope": "common", @@ -2605,7 +2608,7 @@ "section": "def-common.BuilderEntry", "text": "BuilderEntry" }, - "[]; }" + "[]; list_id: string | undefined; namespace_type: \"single\" | \"agnostic\" | undefined; }" ], "path": "packages/kbn-securitysolution-list-utils/src/types/index.ts", "deprecated": false, @@ -2782,6 +2785,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/securitysolution-list-utils", + "id": "def-common.ExceptionsBuilderReturnExceptionItem", + "type": "Type", + "tags": [], + "label": "ExceptionsBuilderReturnExceptionItem", + "description": [], + "signature": [ + "{ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }) | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; list_id?: undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; })" + ], + "path": "packages/kbn-securitysolution-list-utils/src/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/securitysolution-list-utils", "id": "def-common.SavedObjectType", diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 1a0fb17e5ced7..33ff58bd8edf9 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 191 | 0 | 149 | 0 | +| 192 | 0 | 150 | 0 | ## Common diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 7aa3b1237d1bd..90713bd098ba8 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: 2022-10-03 +date: 2022-10-06 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 7b831d8213377..289e5355b885e 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: 2022-10-03 +date: 2022-10-06 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 e82e1785f2490..266252a68a52d 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: 2022-10-03 +date: 2022-10-06 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 60f6a7802671b..489dabf77dd29 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: 2022-10-03 +date: 2022-10-06 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 d5b974e9060a3..24ebc24d8defd 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index 434f6ebf7360f..5e6ec0fcb325d 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: 2022-10-03 +date: 2022-10-06 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_user_profile_components.mdx b/api_docs/kbn_shared_ux_avatar_user_profile_components.mdx index aca5844ce1aa5..b1e6c344b6df5 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: 2022-10-03 +date: 2022-10-06 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_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 64ff483b257b8..ae651814e6dd3 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: 2022-10-03 +date: 2022-10-06 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 98810e33e0a49..18bad88743d5c 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: 2022-10-03 +date: 2022-10-06 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 f7ca5b1619118..898b6c22b69a3 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: 2022-10-03 +date: 2022-10-06 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 bae9391ff07c9..1967303104336 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: 2022-10-03 +date: 2022-10-06 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_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index aeabec4b1421b..efa0c2201e765 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: 2022-10-03 +date: 2022-10-06 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_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index 7dc8d4c973138..fc7e236dee26b 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: 2022-10-03 +date: 2022-10-06 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 5386d337930ef..6d862dd2fc16b 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: 2022-10-03 +date: 2022-10-06 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 77248704888b4..9634fb64565c8 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: 2022-10-03 +date: 2022-10-06 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 100b84a823c93..c5e4b39ae9988 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: 2022-10-03 +date: 2022-10-06 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 fc9392a85f8ee..9f71b5cddd6d8 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: 2022-10-03 +date: 2022-10-06 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 75c7b818d2b99..934331840296b 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: 2022-10-03 +date: 2022-10-06 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 46c1575ac211e..a08be21071aab 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: 2022-10-03 +date: 2022-10-06 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 ab3b48e848639..54998fc195f1f 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: 2022-10-03 +date: 2022-10-06 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 be35872625c46..cdb85ac3ba572 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: 2022-10-03 +date: 2022-10-06 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 b5afba9ff421d..2d36d428ed486 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: 2022-10-03 +date: 2022-10-06 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 da1478041d724..f6f277283ae61 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: 2022-10-03 +date: 2022-10-06 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 1b1327a86bd0a..d0f56cc9a61d1 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: 2022-10-03 +date: 2022-10-06 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 0e7e8889a58c6..f22cf1b967820 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: 2022-10-03 +date: 2022-10-06 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_router.mdx b/api_docs/kbn_shared_ux_router.mdx index f9c07c50257c8..2b8daa788df8f 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: 2022-10-03 +date: 2022-10-06 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 a0aca2fcd5aaf..6932fdb8c3515 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: 2022-10-03 +date: 2022-10-06 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 aeae1c356a861..6f13a8ee498e4 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: 2022-10-03 +date: 2022-10-06 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 d5712323de82d..fa0caf396263c 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: 2022-10-03 +date: 2022-10-06 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 3466072027056..2a43bfb51834f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index d6c26edac107d..402053e89565f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_package_json.mdx b/api_docs/kbn_sort_package_json.mdx index 13db8c8155fd0..36f400c24b25c 100644 --- a/api_docs/kbn_sort_package_json.mdx +++ b/api_docs/kbn_sort_package_json.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-package-json title: "@kbn/sort-package-json" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-package-json plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-package-json'] --- import kbnSortPackageJsonObj from './kbn_sort_package_json.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index e96bc3e61652b..33fea0c1e2299 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: 2022-10-03 +date: 2022-10-06 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 b4aac204fc2fc..2eba5dc5be3ef 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: 2022-10-03 +date: 2022-10-06 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 13b0046b3c5f5..526b6c000b2a3 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: 2022-10-03 +date: 2022-10-06 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 5dc57b83e3caf..f324f70d512f0 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: 2022-10-03 +date: 2022-10-06 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 924a8f1d2d36d..d4ba7c7fc7970 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: 2022-10-03 +date: 2022-10-06 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 cc4a486b6dc8e..0c9933569010c 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: 2022-10-03 +date: 2022-10-06 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 38fd9ee192959..188ea7259e9d9 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index efc952ecde5a0..00a3f5284a161 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer.mdx b/api_docs/kbn_type_summarizer.mdx index 1c63f3fb99305..2e7665c6d95d8 100644 --- a/api_docs/kbn_type_summarizer.mdx +++ b/api_docs/kbn_type_summarizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer title: "@kbn/type-summarizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer'] --- import kbnTypeSummarizerObj from './kbn_type_summarizer.devdocs.json'; diff --git a/api_docs/kbn_type_summarizer_core.mdx b/api_docs/kbn_type_summarizer_core.mdx index 346fc07253bf5..2b008c185e4ae 100644 --- a/api_docs/kbn_type_summarizer_core.mdx +++ b/api_docs/kbn_type_summarizer_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-type-summarizer-core title: "@kbn/type-summarizer-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/type-summarizer-core plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/type-summarizer-core'] --- import kbnTypeSummarizerCoreObj from './kbn_type_summarizer_core.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index cc16ed53a0ad1..bf7280adef9c2 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: 2022-10-03 +date: 2022-10-06 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_theme.mdx b/api_docs/kbn_ui_theme.mdx index 768d7656e3a83..50ea7f126932a 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.devdocs.json b/api_docs/kbn_user_profile_components.devdocs.json index d8cd0cfd94f9e..55ddd03b7d6d4 100644 --- a/api_docs/kbn_user_profile_components.devdocs.json +++ b/api_docs/kbn_user_profile_components.devdocs.json @@ -121,6 +121,57 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserAvatarTip", + "type": "Function", + "tags": [], + "label": "UserAvatarTip", + "description": [ + "\nRenders a user avatar with tooltip" + ], + "signature": [ + "({ user, avatar, ...rest }: React.PropsWithChildren<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserAvatarProps", + "text": "UserAvatarProps" + }, + ">) => JSX.Element" + ], + "path": "packages/kbn-user-profile-components/src/user_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserAvatarTip.$1", + "type": "CompoundType", + "tags": [], + "label": "{ user, avatar, ...rest }", + "description": [], + "signature": [ + "React.PropsWithChildren<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserAvatarProps", + "text": "UserAvatarProps" + }, + ">" + ], + "path": "packages/kbn-user-profile-components/src/user_avatar_tip.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/user-profile-components", "id": "def-common.UserProfilesPopover", @@ -236,6 +287,57 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserToolTip", + "type": "Function", + "tags": [], + "label": "UserToolTip", + "description": [ + "\nRenders a tooltip with user information" + ], + "signature": [ + "({ user, avatar, ...rest }: React.PropsWithChildren<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserToolTipProps", + "text": "UserToolTipProps" + }, + ">) => JSX.Element" + ], + "path": "packages/kbn-user-profile-components/src/user_tooltip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserToolTip.$1", + "type": "CompoundType", + "tags": [], + "label": "{ user, avatar, ...rest }", + "description": [], + "signature": [ + "React.PropsWithChildren<", + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserToolTipProps", + "text": "UserToolTipProps" + }, + ">" + ], + "path": "packages/kbn-user-profile-components/src/user_tooltip.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [ @@ -938,6 +1040,79 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserToolTipProps", + "type": "Interface", + "tags": [], + "label": "UserToolTipProps", + "description": [ + "\nProps of {@link UserToolTip} component" + ], + "signature": [ + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserToolTipProps", + "text": "UserToolTipProps" + }, + " extends Omit<", + "EuiToolTipProps", + ", \"title\" | \"content\">" + ], + "path": "packages/kbn-user-profile-components/src/user_tooltip.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserToolTipProps.user", + "type": "Object", + "tags": [], + "label": "user", + "description": [ + "\nUser to be rendered" + ], + "signature": [ + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfileUserInfo", + "text": "UserProfileUserInfo" + } + ], + "path": "packages/kbn-user-profile-components/src/user_tooltip.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/user-profile-components", + "id": "def-common.UserToolTipProps.avatar", + "type": "Object", + "tags": [], + "label": "avatar", + "description": [ + "\nAvatar data of user to be rendered" + ], + "signature": [ + { + "pluginId": "@kbn/user-profile-components", + "scope": "common", + "docId": "kibKbnUserProfileComponentsPluginApi", + "section": "def-common.UserProfileAvatarData", + "text": "UserProfileAvatarData" + }, + " | undefined" + ], + "path": "packages/kbn-user-profile-components/src/user_tooltip.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false } ], "enums": [], diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 321db07786d48..e313a22cdc174 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Owner missing] for questions regarding this plugin. | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 48 | 0 | 3 | 0 | +| 55 | 0 | 5 | 0 | ## Common diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 59733af696053..a78ffe7183c1a 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index d34f5eb451f66..2ced8c278fc30 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: 2022-10-03 +date: 2022-10-06 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 3301abb7449f7..5ae4fd4168333 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 7aba97a043a20..2bfab48ac58d5 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: 2022-10-03 +date: 2022-10-06 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 99437dfa2d79f..560988f43a860 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index b563f5461da0f..4d8e7f8aba762 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: 2022-10-03 +date: 2022-10-06 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 5bb528b470212..02e87f5da1e0d 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: 2022-10-03 +date: 2022-10-06 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 b08fc593fdcc7..7e6d321227846 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: 2022-10-03 +date: 2022-10-06 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 ee26d7bf7b870..d88df8ee0e66a 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: 2022-10-03 +date: 2022-10-06 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 f3039f89e8db3..898eb33a80df7 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: 2022-10-03 +date: 2022-10-06 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 a2bbb989390e5..67093dd6223c2 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: 2022-10-03 +date: 2022-10-06 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 a1ea39b243d1e..157e914e90819 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/lists.devdocs.json b/api_docs/lists.devdocs.json index 40c17f8b9f3ad..83be2ee9706c9 100644 --- a/api_docs/lists.devdocs.json +++ b/api_docs/lists.devdocs.json @@ -288,7 +288,8 @@ "label": "exceptionItems", "description": [], "signature": [ - "({ _version: string | undefined; comments: ({ comment: string; created_at: string; created_by: string; id: string; } & { updated_at?: string | undefined; updated_by?: string | undefined; })[]; created_at: string; created_by: string; description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; })[]; id: string; item_id: string; list_id: string; meta: object | undefined; name: string; namespace_type: \"single\" | \"agnostic\"; os_types: (\"windows\" | \"linux\" | \"macos\")[]; tags: string[]; tie_breaker_id: string; type: \"simple\"; updated_at: string; updated_by: string; } | ({ description: string; entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; list: { id: string; type: \"boolean\" | \"date\" | \"keyword\" | \"ip\" | \"text\" | \"geo_point\" | \"geo_shape\" | \"date_nanos\" | \"long\" | \"double\" | \"date_range\" | \"ip_range\" | \"shape\" | \"short\" | \"binary\" | \"float\" | \"half_float\" | \"integer\" | \"byte\" | \"long_range\" | \"integer_range\" | \"float_range\" | \"double_range\"; }; operator: \"excluded\" | \"included\"; type: \"list\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; } | { field: string; operator: \"excluded\" | \"included\"; type: \"wildcard\"; value: string; } | { entries: ({ field: string; operator: \"excluded\" | \"included\"; type: \"exists\"; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match\"; value: string; } | { field: string; operator: \"excluded\" | \"included\"; type: \"match_any\"; value: string[]; })[]; field: string; type: \"nested\"; })[]; list_id: string; name: string; type: \"simple\"; } & { comments?: { comment: string; }[] | undefined; item_id?: string | undefined; meta?: object | undefined; namespace_type?: \"single\" | \"agnostic\" | undefined; os_types?: (\"windows\" | \"linux\" | \"macos\")[] | undefined; tags?: string[] | undefined; }))[]" + "ExceptionsBuilderReturnExceptionItem", + "[]" ], "path": "x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.tsx", "deprecated": false, diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 167f95ca81b40..c5437eaa00fbd 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 7b13b081164ff..ab152e1e97ced 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.devdocs.json b/api_docs/maps.devdocs.json index 83836732b0bfc..d40b99e5b5795 100644 --- a/api_docs/maps.devdocs.json +++ b/api_docs/maps.devdocs.json @@ -2182,6 +2182,149 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource", + "type": "Interface", + "tags": [], + "label": "IRasterSource", + "description": [], + "signature": [ + { + "pluginId": "maps", + "scope": "public", + "docId": "kibMapsPluginApi", + "section": "def-public.IRasterSource", + "text": "IRasterSource" + }, + " extends ", + { + "pluginId": "maps", + "scope": "public", + "docId": "kibMapsPluginApi", + "section": "def-public.ITMSSource", + "text": "ITMSSource" + } + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource.canSkipSourceUpdate", + "type": "Function", + "tags": [], + "label": "canSkipSourceUpdate", + "description": [], + "signature": [ + "(dataRequest: ", + { + "pluginId": "maps", + "scope": "public", + "docId": "kibMapsPluginApi", + "section": "def-public.DataRequest", + "text": "DataRequest" + }, + ", nextRequestMeta: ", + "DataRequestMeta", + ") => Promise" + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource.canSkipSourceUpdate.$1", + "type": "Object", + "tags": [], + "label": "dataRequest", + "description": [], + "signature": [ + { + "pluginId": "maps", + "scope": "public", + "docId": "kibMapsPluginApi", + "section": "def-public.DataRequest", + "text": "DataRequest" + } + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource.canSkipSourceUpdate.$2", + "type": "CompoundType", + "tags": [], + "label": "nextRequestMeta", + "description": [], + "signature": [ + "DataRequestMeta" + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource.isSourceStale", + "type": "Function", + "tags": [], + "label": "isSourceStale", + "description": [], + "signature": [ + "(mbSource: maplibregl.RasterTileSource, sourceData: ", + "RasterTileSourceData", + ") => boolean" + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource.isSourceStale.$1", + "type": "Object", + "tags": [], + "label": "mbSource", + "description": [], + "signature": [ + "maplibregl.RasterTileSource" + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "maps", + "id": "def-public.IRasterSource.isSourceStale.$2", + "type": "Object", + "tags": [], + "label": "sourceData", + "description": [], + "signature": [ + "RasterTileSourceData" + ], + "path": "x-pack/plugins/maps/public/classes/sources/raster_source/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "maps", "id": "def-public.ITMSSource", diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 84567432aed62..937982b21ad25 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; @@ -21,7 +21,7 @@ Contact [GIS](https://github.com/orgs/elastic/teams/kibana-gis) for questions re | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 256 | 0 | 255 | 25 | +| 263 | 0 | 262 | 26 | ## Client diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 7e0c0528fef4a..e191c22670b83 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: 2022-10-03 +date: 2022-10-06 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 a7a7a0517b9b8..73db15fb02a71 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: 2022-10-03 +date: 2022-10-06 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 e884c213dddbc..a70f6e14d3582 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: 2022-10-03 +date: 2022-10-06 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 37856b288370a..e6e99fc09ca31 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: 2022-10-03 +date: 2022-10-06 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 283d52b0a4c3a..a3dbc653112bc 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: 2022-10-03 +date: 2022-10-06 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 278b15e23d47f..ef9b746fa56f5 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index fd03a2f285ab5..710c9036757f7 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -738,7 +738,7 @@ }, " | undefined; list: () => string[]; }; selectedAlertId?: string | undefined; } & ", "CommonProps", - " & { as?: \"div\" | undefined; } & _EuiFlyoutProps & Omit, HTMLDivElement>, keyof _EuiFlyoutProps> & Omit, HTMLDivElement>, \"key\" | keyof React.HTMLAttributes | \"css\"> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }, \"children\" | \"ref\" | \"type\" | \"onError\" | \"hidden\" | \"color\" | \"id\" | \"className\" | \"size\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"security\" | \"key\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"onClose\" | \"data-test-subj\" | \"css\" | \"as\" | \"paddingSize\" | \"focusTrapProps\" | \"ownFocus\" | \"maxWidth\" | \"hideCloseButton\" | \"closeButtonAriaLabel\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\">, \"children\" | \"type\" | \"onError\" | \"hidden\" | \"color\" | \"id\" | \"alert\" | \"className\" | \"size\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"security\" | \"key\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"onClose\" | \"data-test-subj\" | \"css\" | \"as\" | \"paddingSize\" | \"focusTrapProps\" | \"ownFocus\" | \"alerts\" | \"maxWidth\" | \"hideCloseButton\" | \"closeButtonAriaLabel\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\" | \"isInApp\" | \"observabilityRuleTypeRegistry\" | \"selectedAlertId\"> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }> & { readonly _result: ({ alert, alerts, isInApp, observabilityRuleTypeRegistry, onClose, selectedAlertId, }: AlertsFlyoutProps) => JSX.Element | null; }" + " & { as?: \"div\" | undefined; } & _EuiFlyoutProps & Omit, HTMLDivElement>, keyof _EuiFlyoutProps> & Omit, HTMLDivElement>, \"key\" | keyof React.HTMLAttributes | \"css\"> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }, \"children\" | \"ref\" | \"type\" | \"onError\" | \"hidden\" | \"color\" | \"id\" | \"className\" | \"size\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"security\" | \"key\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"onClose\" | \"data-test-subj\" | \"css\" | \"as\" | \"paddingSize\" | \"focusTrapProps\" | \"ownFocus\" | \"maxWidth\" | \"hideCloseButton\" | \"closeButtonAriaLabel\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\">, \"children\" | \"type\" | \"onError\" | \"hidden\" | \"color\" | \"id\" | \"alert\" | \"className\" | \"size\" | \"title\" | \"onChange\" | \"onKeyDown\" | \"onClick\" | \"security\" | \"key\" | \"defaultValue\" | \"lang\" | \"defaultChecked\" | \"suppressContentEditableWarning\" | \"suppressHydrationWarning\" | \"accessKey\" | \"contentEditable\" | \"contextMenu\" | \"dir\" | \"draggable\" | \"placeholder\" | \"slot\" | \"spellCheck\" | \"style\" | \"tabIndex\" | \"translate\" | \"radioGroup\" | \"role\" | \"about\" | \"datatype\" | \"inlist\" | \"prefix\" | \"property\" | \"resource\" | \"typeof\" | \"vocab\" | \"autoCapitalize\" | \"autoCorrect\" | \"autoSave\" | \"itemProp\" | \"itemScope\" | \"itemType\" | \"itemID\" | \"itemRef\" | \"results\" | \"unselectable\" | \"inputMode\" | \"is\" | \"aria-activedescendant\" | \"aria-atomic\" | \"aria-autocomplete\" | \"aria-busy\" | \"aria-checked\" | \"aria-colcount\" | \"aria-colindex\" | \"aria-colspan\" | \"aria-controls\" | \"aria-current\" | \"aria-describedby\" | \"aria-details\" | \"aria-disabled\" | \"aria-dropeffect\" | \"aria-errormessage\" | \"aria-expanded\" | \"aria-flowto\" | \"aria-grabbed\" | \"aria-haspopup\" | \"aria-hidden\" | \"aria-invalid\" | \"aria-keyshortcuts\" | \"aria-label\" | \"aria-labelledby\" | \"aria-level\" | \"aria-live\" | \"aria-modal\" | \"aria-multiline\" | \"aria-multiselectable\" | \"aria-orientation\" | \"aria-owns\" | \"aria-placeholder\" | \"aria-posinset\" | \"aria-pressed\" | \"aria-readonly\" | \"aria-relevant\" | \"aria-required\" | \"aria-roledescription\" | \"aria-rowcount\" | \"aria-rowindex\" | \"aria-rowspan\" | \"aria-selected\" | \"aria-setsize\" | \"aria-sort\" | \"aria-valuemax\" | \"aria-valuemin\" | \"aria-valuenow\" | \"aria-valuetext\" | \"dangerouslySetInnerHTML\" | \"onCopy\" | \"onCopyCapture\" | \"onCut\" | \"onCutCapture\" | \"onPaste\" | \"onPasteCapture\" | \"onCompositionEnd\" | \"onCompositionEndCapture\" | \"onCompositionStart\" | \"onCompositionStartCapture\" | \"onCompositionUpdate\" | \"onCompositionUpdateCapture\" | \"onFocus\" | \"onFocusCapture\" | \"onBlur\" | \"onBlurCapture\" | \"onChangeCapture\" | \"onBeforeInput\" | \"onBeforeInputCapture\" | \"onInput\" | \"onInputCapture\" | \"onReset\" | \"onResetCapture\" | \"onSubmit\" | \"onSubmitCapture\" | \"onInvalid\" | \"onInvalidCapture\" | \"onLoad\" | \"onLoadCapture\" | \"onErrorCapture\" | \"onKeyDownCapture\" | \"onKeyPress\" | \"onKeyPressCapture\" | \"onKeyUp\" | \"onKeyUpCapture\" | \"onAbort\" | \"onAbortCapture\" | \"onCanPlay\" | \"onCanPlayCapture\" | \"onCanPlayThrough\" | \"onCanPlayThroughCapture\" | \"onDurationChange\" | \"onDurationChangeCapture\" | \"onEmptied\" | \"onEmptiedCapture\" | \"onEncrypted\" | \"onEncryptedCapture\" | \"onEnded\" | \"onEndedCapture\" | \"onLoadedData\" | \"onLoadedDataCapture\" | \"onLoadedMetadata\" | \"onLoadedMetadataCapture\" | \"onLoadStart\" | \"onLoadStartCapture\" | \"onPause\" | \"onPauseCapture\" | \"onPlay\" | \"onPlayCapture\" | \"onPlaying\" | \"onPlayingCapture\" | \"onProgress\" | \"onProgressCapture\" | \"onRateChange\" | \"onRateChangeCapture\" | \"onSeeked\" | \"onSeekedCapture\" | \"onSeeking\" | \"onSeekingCapture\" | \"onStalled\" | \"onStalledCapture\" | \"onSuspend\" | \"onSuspendCapture\" | \"onTimeUpdate\" | \"onTimeUpdateCapture\" | \"onVolumeChange\" | \"onVolumeChangeCapture\" | \"onWaiting\" | \"onWaitingCapture\" | \"onAuxClick\" | \"onAuxClickCapture\" | \"onClickCapture\" | \"onContextMenu\" | \"onContextMenuCapture\" | \"onDoubleClick\" | \"onDoubleClickCapture\" | \"onDrag\" | \"onDragCapture\" | \"onDragEnd\" | \"onDragEndCapture\" | \"onDragEnter\" | \"onDragEnterCapture\" | \"onDragExit\" | \"onDragExitCapture\" | \"onDragLeave\" | \"onDragLeaveCapture\" | \"onDragOver\" | \"onDragOverCapture\" | \"onDragStart\" | \"onDragStartCapture\" | \"onDrop\" | \"onDropCapture\" | \"onMouseDown\" | \"onMouseDownCapture\" | \"onMouseEnter\" | \"onMouseLeave\" | \"onMouseMove\" | \"onMouseMoveCapture\" | \"onMouseOut\" | \"onMouseOutCapture\" | \"onMouseOver\" | \"onMouseOverCapture\" | \"onMouseUp\" | \"onMouseUpCapture\" | \"onSelect\" | \"onSelectCapture\" | \"onTouchCancel\" | \"onTouchCancelCapture\" | \"onTouchEnd\" | \"onTouchEndCapture\" | \"onTouchMove\" | \"onTouchMoveCapture\" | \"onTouchStart\" | \"onTouchStartCapture\" | \"onPointerDown\" | \"onPointerDownCapture\" | \"onPointerMove\" | \"onPointerMoveCapture\" | \"onPointerUp\" | \"onPointerUpCapture\" | \"onPointerCancel\" | \"onPointerCancelCapture\" | \"onPointerEnter\" | \"onPointerEnterCapture\" | \"onPointerLeave\" | \"onPointerLeaveCapture\" | \"onPointerOver\" | \"onPointerOverCapture\" | \"onPointerOut\" | \"onPointerOutCapture\" | \"onGotPointerCapture\" | \"onGotPointerCaptureCapture\" | \"onLostPointerCapture\" | \"onLostPointerCaptureCapture\" | \"onScroll\" | \"onScrollCapture\" | \"onWheel\" | \"onWheelCapture\" | \"onAnimationStart\" | \"onAnimationStartCapture\" | \"onAnimationEnd\" | \"onAnimationEndCapture\" | \"onAnimationIteration\" | \"onAnimationIterationCapture\" | \"onTransitionEnd\" | \"onTransitionEndCapture\" | \"onClose\" | \"data-test-subj\" | \"css\" | \"as\" | \"alerts\" | \"paddingSize\" | \"focusTrapProps\" | \"ownFocus\" | \"maxWidth\" | \"hideCloseButton\" | \"closeButtonAriaLabel\" | \"closeButtonProps\" | \"closeButtonPosition\" | \"maskProps\" | \"outsideClickCloses\" | \"side\" | \"pushMinBreakpoint\" | \"isInApp\" | \"observabilityRuleTypeRegistry\" | \"selectedAlertId\"> & { ref?: React.RefObject | ((instance: HTMLDivElement | null) => void) | null | undefined; }> & { readonly _result: ({ alert, alerts, isInApp, observabilityRuleTypeRegistry, onClose, selectedAlertId, }: AlertsFlyoutProps) => JSX.Element | null; }" ], "path": "x-pack/plugins/observability/public/index.ts", "deprecated": false, @@ -3793,7 +3793,7 @@ "label": "format", "description": [], "signature": [ - "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", @@ -3812,7 +3812,7 @@ "label": "options", "description": [], "signature": [ - "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", @@ -5320,7 +5320,7 @@ "label": "ObservabilityRuleTypeFormatter", "description": [], "signature": [ - "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "(options: { fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", @@ -5339,7 +5339,7 @@ "label": "options", "description": [], "signature": [ - "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", + "{ fields: OutputOf> & Record; formatters: { asDuration: (value: ", "Maybe", ", { defaultValue, extended }?: FormatterOptions) => string; asPercent: (numerator: ", "Maybe", @@ -7759,7 +7759,129 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { id: string; } & { name: string; description: string; indicator: { type: \"slo.apm.transaction_duration\"; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: \"slo.apm.transaction_error_rate\"; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: true; }; budgeting_method: \"occurrences\"; objective: { target: number; }; }, ", + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; revision: number; created_at: Date; updated_at: Date; }, ", + { + "pluginId": "observability", + "scope": "server", + "docId": "kibObservabilityPluginApi", + "section": "def-server.ObservabilityRouteCreateOptions", + "text": "ObservabilityRouteCreateOptions" + }, + "> | undefined; \"PUT /api/observability/slos/{id}\"?: ", + "ServerRoute", + "<\"PUT /api/observability/slos/{id}\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ id: ", + "StringC", + "; }>; body: ", + "PartialC", + "<{ name: ", + "StringC", + "; description: ", + "StringC", + "; indicator: ", + "UnionC", + "<[", + "TypeC", + "<{ type: ", + "LiteralC", + "; params: ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; service: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_type: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_name: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; 'threshold.us': ", + "NumberC", + "; }>; }>, ", + "TypeC", + "<{ type: ", + "LiteralC", + "; params: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; service: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_type: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_name: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; }>, ", + "PartialC", + "<{ good_status_codes: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<\"2xx\">, ", + "LiteralC", + "<\"3xx\">, ", + "LiteralC", + "<\"4xx\">, ", + "LiteralC", + "<\"5xx\">]>>; }>]>; }>]>; time_window: ", + "TypeC", + "<{ duration: ", + "StringC", + "; is_rolling: ", + "LiteralC", + "; }>; budgeting_method: ", + "LiteralC", + "<\"occurrences\">; objective: ", + "TypeC", + "<{ target: ", + "NumberC", + "; }>; }>; }>, ", + { + "pluginId": "observability", + "scope": "server", + "docId": "kibObservabilityPluginApi", + "section": "def-server.ObservabilityRouteHandlerResources", + "text": "ObservabilityRouteHandlerResources" + }, + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; created_at: Date; updated_at: Date; }, ", { "pluginId": "observability", "scope": "server", @@ -7783,7 +7905,7 @@ "TypeC", "<{ type: ", "LiteralC", - "<\"slo.apm.transaction_duration\">; params: ", + "; params: ", "TypeC", "<{ environment: ", "UnionC", @@ -7815,7 +7937,7 @@ "TypeC", "<{ type: ", "LiteralC", - "<\"slo.apm.transaction_error_rate\">; params: ", + "; params: ", "IntersectionC", "<[", "TypeC", @@ -7863,7 +7985,7 @@ "StringC", "; is_rolling: ", "LiteralC", - "; }>; budgeting_method: ", + "; }>; budgeting_method: ", "LiteralC", "<\"occurrences\">; objective: ", "TypeC", @@ -7987,7 +8109,129 @@ "section": "def-server.ObservabilityRouteHandlerResources", "text": "ObservabilityRouteHandlerResources" }, - ", { id: string; } & { name: string; description: string; indicator: { type: \"slo.apm.transaction_duration\"; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: \"slo.apm.transaction_error_rate\"; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: true; }; budgeting_method: \"occurrences\"; objective: { target: number; }; }, ", + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; revision: number; created_at: Date; updated_at: Date; }, ", + { + "pluginId": "observability", + "scope": "server", + "docId": "kibObservabilityPluginApi", + "section": "def-server.ObservabilityRouteCreateOptions", + "text": "ObservabilityRouteCreateOptions" + }, + "> | undefined; \"PUT /api/observability/slos/{id}\"?: ", + "ServerRoute", + "<\"PUT /api/observability/slos/{id}\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ id: ", + "StringC", + "; }>; body: ", + "PartialC", + "<{ name: ", + "StringC", + "; description: ", + "StringC", + "; indicator: ", + "UnionC", + "<[", + "TypeC", + "<{ type: ", + "LiteralC", + "; params: ", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; service: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_type: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_name: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; 'threshold.us': ", + "NumberC", + "; }>; }>, ", + "TypeC", + "<{ type: ", + "LiteralC", + "; params: ", + "IntersectionC", + "<[", + "TypeC", + "<{ environment: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; service: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_type: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; transaction_name: ", + "UnionC", + "<[", + "LiteralC", + "<\"*\">, ", + "StringC", + "]>; }>, ", + "PartialC", + "<{ good_status_codes: ", + "ArrayC", + "<", + "UnionC", + "<[", + "LiteralC", + "<\"2xx\">, ", + "LiteralC", + "<\"3xx\">, ", + "LiteralC", + "<\"4xx\">, ", + "LiteralC", + "<\"5xx\">]>>; }>]>; }>]>; time_window: ", + "TypeC", + "<{ duration: ", + "StringC", + "; is_rolling: ", + "LiteralC", + "; }>; budgeting_method: ", + "LiteralC", + "<\"occurrences\">; objective: ", + "TypeC", + "<{ target: ", + "NumberC", + "; }>; }>; }>, ", + { + "pluginId": "observability", + "scope": "server", + "docId": "kibObservabilityPluginApi", + "section": "def-server.ObservabilityRouteHandlerResources", + "text": "ObservabilityRouteHandlerResources" + }, + ", { id: string; name: string; description: string; indicator: { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; 'threshold.us': number; }; } | { type: string; params: { environment: string; service: string; transaction_type: string; transaction_name: string; } & { good_status_codes?: (\"2xx\" | \"3xx\" | \"4xx\" | \"5xx\")[] | undefined; }; }; time_window: { duration: string; is_rolling: boolean; }; budgeting_method: \"occurrences\"; objective: { target: number; }; created_at: Date; updated_at: Date; }, ", { "pluginId": "observability", "scope": "server", @@ -8011,7 +8255,7 @@ "TypeC", "<{ type: ", "LiteralC", - "<\"slo.apm.transaction_duration\">; params: ", + "; params: ", "TypeC", "<{ environment: ", "UnionC", @@ -8043,7 +8287,7 @@ "TypeC", "<{ type: ", "LiteralC", - "<\"slo.apm.transaction_error_rate\">; params: ", + "; params: ", "IntersectionC", "<[", "TypeC", @@ -8091,7 +8335,7 @@ "StringC", "; is_rolling: ", "LiteralC", - "; }>; budgeting_method: ", + "; }>; budgeting_method: ", "LiteralC", "<\"occurrences\">; objective: ", "TypeC", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index 2f29ba44a8c06..dcab9933d2546 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 5b05f78a15a04..d37f4c7b44ec7 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: 2022-10-03 +date: 2022-10-06 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 b6b1d856686da..1dc8a44fa3580 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,40 +15,43 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 477 | 397 | 38 | +| 486 | 403 | 38 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 32016 | 179 | 21562 | 1007 | +| 32149 | 179 | 21640 | 1023 | ## Plugin Directory | Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| -| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 214 | 0 | 209 | 19 | +| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 213 | 0 | 208 | 23 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 36 | 1 | 32 | 2 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 9 | 0 | 0 | 2 | | | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 379 | 0 | 370 | 24 | | | [APM UI](https://github.com/orgs/elastic/teams/apm-ui) | The user interface for Elastic APM | 38 | 0 | 38 | 52 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 9 | 0 | 9 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 80 | 1 | 71 | 2 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 81 | 1 | 72 | 2 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | | | [ResponseOps](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 87 | 0 | 71 | 28 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 264 | 2 | 249 | 9 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 29 | 0 | 24 | 0 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/@elastic/kibana-core) | Provides the necessary APIs to implement A/B testing scenarios, fetching the variations in configuration and reporting back metrics to track conversion rates of the experiments. | 16 | 0 | 0 | 0 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 34 | 0 | 26 | 0 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 1 | 0 | 0 | 0 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/@elastic/kibana-core) | Provides the necessary APIs to implement A/B testing scenarios, fetching the variations in configuration and reporting back metrics to track conversion rates of the experiments. | 12 | 0 | 0 | 0 | +| cloudFullStory | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | When Kibana runs on Elastic Cloud, this plugin registers FullStory as a shipper for telemetry. | 0 | 0 | 0 | 0 | +| cloudLinks | [Kibana Core](https://github.com/orgs/elastic/teams/@kibana-core) | Adds the links to the Elastic Cloud console | 0 | 0 | 0 | 0 | | | [Cloud Security Posture](https://github.com/orgs/elastic/teams/cloud-posture-security) | The cloud security posture plugin | 18 | 0 | 2 | 3 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 13 | 0 | 13 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Controls Plugin contains embeddable components intended to create a simple query interface for end users, and a powerful editing suite that allows dashboard authors to build controls | 212 | 0 | 204 | 7 | -| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2688 | 0 | 30 | 0 | +| | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 2689 | 0 | 23 | 0 | | crossClusterReplication | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | | [Fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 104 | 0 | 85 | 1 | | | [Kibana Presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 120 | 0 | 113 | 3 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 52 | 0 | 51 | 0 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 3213 | 33 | 2509 | 23 | -| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 15 | 0 | 7 | 0 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 3221 | 33 | 2513 | 24 | +| | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 16 | 0 | 7 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Reusable data view field editor across Kibana | 60 | 0 | 30 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Data view management app | 2 | 0 | 2 | 0 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | 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. | 983 | 0 | 225 | 2 | @@ -81,13 +84,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Index pattern fields and ambiguous values formatters | 288 | 5 | 249 | 3 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | 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 | | | [@elastic/kibana-app-services](https://github.com/orgs/elastic/teams/team:AppServicesUx) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 263 | 0 | 14 | 2 | -| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 997 | 3 | 893 | 17 | +| | [Fleet](https://github.com/orgs/elastic/teams/fleet) | - | 998 | 3 | 894 | 17 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 68 | 0 | 14 | 5 | | globalSearchBar | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | globalSearchProviders | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | graph | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 0 | 0 | 0 | 0 | | grokdebugger | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Guided onboarding framework | 12 | 0 | 12 | 1 | +| | [Journey Onboarding](https://github.com/orgs/elastic/teams/platform-onboarding) | Guided onboarding framework | 19 | 0 | 19 | 3 | | | [Kibana Core](https://github.com/orgs/elastic/teams/kibana-core) | - | 143 | 0 | 104 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 4 | 0 | 4 | 0 | | | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 177 | 0 | 172 | 3 | @@ -108,7 +111,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Security detections response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 204 | 0 | 92 | 50 | | logstash | [Logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 41 | 0 | 41 | 6 | -| | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 256 | 0 | 255 | 25 | +| | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 263 | 0 | 262 | 26 | | | [GIS](https://github.com/orgs/elastic/teams/kibana-gis) | - | 67 | 0 | 67 | 0 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 251 | 9 | 78 | 39 | | | [Stack Monitoring](https://github.com/orgs/elastic/teams/stack-monitoring-ui) | - | 11 | 0 | 9 | 1 | @@ -134,7 +137,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | - | 32 | 0 | 13 | 0 | | | [Kibana Reporting Services](https://github.com/orgs/elastic/teams/kibana-reporting-services) | Kibana Screenshotting Plugin | 27 | 0 | 8 | 4 | | searchprofiler | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | -| | [Platform 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. | 247 | 0 | 90 | 0 | +| | [Platform 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. | 249 | 0 | 90 | 0 | | | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 55 | 0 | 54 | 23 | | | [Security Team](https://github.com/orgs/elastic/teams/security-team) | - | 3 | 0 | 3 | 1 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds URL Service and sharing capabilities to Kibana | 114 | 0 | 55 | 10 | @@ -148,15 +151,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 31 | 0 | 26 | 6 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 1 | 0 | 1 | 0 | | | [Kibana Telemetry](https://github.com/orgs/elastic/teams/kibana-telemetry) | - | 11 | 0 | 10 | 0 | -| | [Protections Experience Team](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 | 20 | 0 | 4 | 3 | +| | [Protections Experience Team](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 | 26 | 0 | 8 | 3 | | | [Security solution](https://github.com/orgs/elastic/teams/security-solution) | - | 452 | 1 | 346 | 33 | | | [Machine Learning UI](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [Kibana Localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | -| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 512 | 1 | 485 | 48 | +| | [Response Ops](https://github.com/orgs/elastic/teams/response-ops) | - | 514 | 1 | 487 | 49 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds UI Actions service to Kibana | 133 | 0 | 92 | 11 | | | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Extends UI Actions plugin with more functionality | 206 | 0 | 142 | 9 | | | [Data Discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list which can be integrated into apps | 61 | 0 | 59 | 2 | -| | [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-services) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 128 | 2 | 102 | 17 | +| | [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-services) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 131 | 2 | 104 | 17 | | upgradeAssistant | [Stack Management](https://github.com/orgs/elastic/teams/kibana-stack-management) | - | 0 | 0 | 0 | 0 | | urlDrilldown | [App Services](https://github.com/orgs/elastic/teams/kibana-app-services) | Adds drilldown implementations to Kibana | 0 | 0 | 0 | 0 | | | [Vis Editors](https://github.com/orgs/elastic/teams/kibana-vis-editors) | - | 12 | 0 | 12 | 0 | @@ -240,8 +243,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 4 | 0 | 4 | 0 | | | Kibana Core | - | 5 | 0 | 2 | 0 | | | Kibana Core | - | 4 | 0 | 4 | 0 | -| | Kibana Core | - | 13 | 0 | 11 | 1 | -| | Kibana Core | - | 36 | 1 | 32 | 0 | +| | Kibana Core | - | 15 | 0 | 13 | 2 | +| | Kibana Core | - | 38 | 1 | 34 | 0 | | | Kibana Core | - | 99 | 0 | 51 | 0 | | | Kibana Core | - | 33 | 0 | 29 | 0 | | | Kibana Core | - | 15 | 1 | 15 | 0 | @@ -262,6 +265,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 4 | 0 | 0 | 0 | | | Kibana Core | - | 10 | 1 | 10 | 0 | | | Kibana Core | - | 14 | 0 | 11 | 0 | +| | [Owner missing] | - | 20 | 0 | 6 | 0 | +| | [Owner missing] | - | 9 | 0 | 9 | 3 | +| | Kibana Core | - | 7 | 0 | 7 | 0 | | | Kibana Core | - | 25 | 5 | 25 | 1 | | | Kibana Core | - | 7 | 0 | 7 | 1 | | | Kibana Core | - | 392 | 1 | 154 | 0 | @@ -281,11 +287,11 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 56 | 0 | 30 | 0 | | | Kibana Core | - | 9 | 0 | 5 | 1 | | | Kibana Core | - | 13 | 0 | 12 | 0 | -| | Kibana Core | - | 24 | 0 | 20 | 0 | +| | Kibana Core | - | 29 | 0 | 25 | 0 | | | Kibana Core | - | 11 | 1 | 11 | 0 | -| | Kibana Core | - | 48 | 0 | 8 | 0 | -| | Kibana Core | - | 5 | 0 | 5 | 0 | -| | Kibana Core | - | 7 | 0 | 7 | 0 | +| | Kibana Core | - | 62 | 0 | 8 | 0 | +| | Kibana Core | - | 6 | 0 | 6 | 0 | +| | Kibana Core | - | 19 | 0 | 19 | 0 | | | Kibana Core | - | 6 | 0 | 0 | 0 | | | Kibana Core | - | 5 | 0 | 0 | 0 | | | Kibana Core | - | 3 | 0 | 3 | 0 | @@ -301,8 +307,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | Kibana Core | - | 5 | 0 | 0 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | | | Kibana Core | - | 2 | 0 | 2 | 0 | +| | Kibana Core | - | 2 | 0 | 2 | 0 | +| | Kibana Core | - | 4 | 0 | 4 | 1 | | | Kibana Core | - | 106 | 1 | 75 | 0 | -| | Kibana Core | - | 308 | 1 | 137 | 0 | +| | Kibana Core | - | 310 | 1 | 137 | 0 | | | Kibana Core | - | 71 | 0 | 51 | 0 | | | Kibana Core | - | 6 | 0 | 6 | 0 | | | Kibana Core | - | 37 | 0 | 31 | 1 | @@ -351,7 +359,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | - | 19 | 0 | 11 | 0 | | | [Owner missing] | - | 27 | 0 | 14 | 1 | | | Kibana Core | - | 7 | 0 | 3 | 0 | -| | [Owner missing] | - | 222 | 1 | 168 | 12 | +| | [Owner missing] | - | 226 | 1 | 170 | 14 | | | Kibana Core | - | 11 | 0 | 11 | 0 | | | [Owner missing] | - | 2 | 0 | 1 | 0 | | | [Owner missing] | - | 20 | 0 | 16 | 0 | @@ -386,7 +394,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | Just some helpers for kibana plugin devs. | 1 | 0 | 1 | 0 | | | [Owner missing] | - | 21 | 0 | 10 | 0 | | | [Owner missing] | - | 6 | 0 | 6 | 1 | -| | [Owner missing] | - | 74 | 0 | 71 | 0 | +| | [Owner missing] | - | 75 | 0 | 72 | 0 | | | [Owner missing] | Security Solution auto complete | 56 | 1 | 41 | 1 | | | [Owner missing] | security solution elastic search utilities to use across plugins such lists, security_solution, cases, etc... | 67 | 0 | 61 | 1 | | | [Owner missing] | - | 76 | 0 | 67 | 1 | @@ -398,7 +406,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | security solution list REST API | 67 | 0 | 64 | 0 | | | [Owner missing] | security solution list constants to use across plugins such lists, security_solution, cases, etc... | 33 | 0 | 17 | 0 | | | [Owner missing] | Security solution list ReactJS hooks | 58 | 0 | 47 | 0 | -| | [Owner missing] | security solution list utilities | 191 | 0 | 149 | 0 | +| | [Owner missing] | security solution list utilities | 192 | 0 | 150 | 0 | | | [Owner missing] | security solution rule utilities to use across plugins | 26 | 0 | 23 | 0 | | | [Owner missing] | security solution t-grid packages will allow sharing components between timelines and security_solution plugin until we transfer all functionality to timelines plugin | 120 | 0 | 116 | 0 | | | [Owner missing] | security solution utilities to use across plugins such lists, security_solution, cases, etc... | 31 | 0 | 29 | 0 | @@ -443,7 +451,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [Owner missing] | - | 113 | 1 | 65 | 0 | | | [Owner missing] | - | 83 | 0 | 83 | 1 | | | [Owner missing] | - | 7 | 0 | 6 | 0 | -| | [Owner missing] | - | 48 | 0 | 3 | 0 | +| | [Owner missing] | - | 55 | 0 | 5 | 0 | | | [Owner missing] | - | 34 | 0 | 14 | 1 | | | [Owner missing] | - | 2 | 0 | 2 | 0 | | | [Owner missing] | - | 30 | 0 | 20 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index f9b349676713b..9bc47b3c02bfc 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: 2022-10-03 +date: 2022-10-06 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 1b5e38396b43d..59280e0c4a8ac 100644 --- a/api_docs/profiling.devdocs.json +++ b/api_docs/profiling.devdocs.json @@ -88,7 +88,7 @@ "label": "getRoutePaths", "description": [], "signature": [ - "() => { TopN: string; TopNContainers: string; TopNDeployments: string; TopNFunctions: string; TopNHosts: string; TopNThreads: string; TopNTraces: string; Flamechart: string; FrameInformation: string; }" + "() => { TopN: string; TopNContainers: string; TopNDeployments: string; TopNFunctions: string; TopNHosts: string; TopNThreads: string; TopNTraces: string; Flamechart: string; }" ], "path": "x-pack/plugins/profiling/common/index.ts", "deprecated": false, diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 489f7c32b600e..a6a6cb32f36ee 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index 6a8252bfebe78..8cd446176d3d8 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: 2022-10-03 +date: 2022-10-06 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 fbdfd3cb5bd01..a1caaaad0e96d 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: 2022-10-03 +date: 2022-10-06 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 11313a6dc5f24..646302af04ddb 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.devdocs.json b/api_docs/rule_registry.devdocs.json index 089f973bc0bf0..37e78ced1236a 100644 --- a/api_docs/rule_registry.devdocs.json +++ b/api_docs/rule_registry.devdocs.json @@ -63,7 +63,7 @@ "label": "get", "description": [], "signature": [ - "({ id, index }: GetAlertParams) => Promise> | undefined>" + "({ id, index }: GetAlertParams) => Promise> | undefined>" ], "path": "x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts", "deprecated": false, @@ -203,7 +203,7 @@ "SortOptions", "[] | undefined; search_after?: (string | number)[] | undefined; }) => Promise<", "SearchResponse", - ">, unknown>>" + ">, unknown>>" ], "path": "x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts", "deprecated": false, @@ -2319,7 +2319,7 @@ "SearchRequest", ">(request: TSearchRequest) => Promise<", "ESSearchResponse", - "> & OutputOf>>, TSearchRequest, { restTotalHitsAsInt: false; }>>" + "> & OutputOf>>, TSearchRequest, { restTotalHitsAsInt: false; }>>" ], "path": "x-pack/plugins/rule_registry/server/rule_data_client/types.ts", "deprecated": false, @@ -3949,7 +3949,7 @@ "label": "parseTechnicalFields", "description": [], "signature": [ - "(input: unknown, partial?: boolean) => OutputOf>" + "(input: unknown, partial?: boolean) => OutputOf>" ], "path": "x-pack/plugins/rule_registry/common/parse_technical_fields.ts", "deprecated": false, @@ -4270,7 +4270,7 @@ "label": "ParsedTechnicalFields", "description": [], "signature": [ - "{ readonly '@timestamp': string; readonly \"kibana.alert.rule.rule_type_id\": string; readonly \"kibana.alert.rule.consumer\": string; readonly \"kibana.alert.rule.producer\": string; readonly \"kibana.space_ids\": string[]; readonly \"kibana.alert.uuid\": string; readonly \"kibana.alert.instance.id\": string; readonly \"kibana.alert.status\": string; readonly \"kibana.alert.rule.category\": string; readonly \"kibana.alert.rule.uuid\": string; readonly \"kibana.alert.rule.name\": string; readonly tags?: string[] | undefined; readonly 'event.action'?: string | undefined; readonly \"kibana.alert.rule.execution.uuid\"?: string | undefined; readonly \"kibana.alert.rule.parameters\"?: { [key: string]: unknown; } | undefined; readonly \"kibana.alert.start\"?: string | undefined; readonly \"kibana.alert.end\"?: string | undefined; readonly \"kibana.alert.duration.us\"?: number | undefined; readonly \"kibana.alert.severity\"?: string | undefined; readonly \"kibana.version\"?: string | undefined; readonly \"ecs.version\"?: string | undefined; readonly \"kibana.alert.risk_score\"?: number | undefined; readonly \"kibana.alert.workflow_status\"?: string | undefined; readonly \"kibana.alert.workflow_user\"?: string | undefined; readonly \"kibana.alert.workflow_reason\"?: string | undefined; readonly \"kibana.alert.system_status\"?: string | undefined; readonly \"kibana.alert.action_group\"?: string | undefined; readonly \"kibana.alert.reason\"?: string | undefined; readonly \"kibana.alert.rule.author\"?: string | undefined; readonly \"kibana.alert.rule.created_at\"?: string | undefined; readonly \"kibana.alert.rule.created_by\"?: string | undefined; readonly \"kibana.alert.rule.description\"?: string | undefined; readonly \"kibana.alert.rule.enabled\"?: string | undefined; readonly \"kibana.alert.rule.from\"?: string | undefined; readonly \"kibana.alert.rule.interval\"?: string | undefined; readonly \"kibana.alert.rule.license\"?: string | undefined; readonly \"kibana.alert.rule.note\"?: string | undefined; readonly \"kibana.alert.rule.references\"?: string[] | undefined; readonly \"kibana.alert.rule.rule_id\"?: string | undefined; readonly \"kibana.alert.rule.rule_name_override\"?: string | undefined; readonly \"kibana.alert.rule.tags\"?: string[] | undefined; readonly \"kibana.alert.rule.to\"?: string | undefined; readonly \"kibana.alert.rule.type\"?: string | undefined; readonly \"kibana.alert.rule.updated_at\"?: string | undefined; readonly \"kibana.alert.rule.updated_by\"?: string | undefined; readonly \"kibana.alert.rule.version\"?: string | undefined; readonly 'event.kind'?: string | undefined; }" + "{ readonly '@timestamp': string; readonly \"kibana.alert.rule.rule_type_id\": string; readonly \"kibana.alert.rule.consumer\": string; readonly \"kibana.alert.rule.producer\": string; readonly \"kibana.space_ids\": string[]; readonly \"kibana.alert.uuid\": string; readonly \"kibana.alert.instance.id\": string; readonly \"kibana.alert.status\": string; readonly \"kibana.alert.rule.category\": string; readonly \"kibana.alert.rule.uuid\": string; readonly \"kibana.alert.rule.name\": string; readonly tags?: string[] | undefined; readonly 'event.action'?: string | undefined; readonly \"kibana.alert.rule.execution.uuid\"?: string | undefined; readonly \"kibana.alert.rule.parameters\"?: { [key: string]: unknown; } | undefined; readonly \"kibana.alert.start\"?: string | undefined; readonly \"kibana.alert.time_range\"?: unknown; readonly \"kibana.alert.end\"?: string | undefined; readonly \"kibana.alert.duration.us\"?: number | undefined; readonly \"kibana.alert.severity\"?: string | undefined; readonly \"kibana.version\"?: string | undefined; readonly \"ecs.version\"?: string | undefined; readonly \"kibana.alert.risk_score\"?: number | undefined; readonly \"kibana.alert.workflow_status\"?: string | undefined; readonly \"kibana.alert.workflow_user\"?: string | undefined; readonly \"kibana.alert.workflow_reason\"?: string | undefined; readonly \"kibana.alert.system_status\"?: string | undefined; readonly \"kibana.alert.action_group\"?: string | undefined; readonly \"kibana.alert.reason\"?: string | undefined; readonly \"kibana.alert.rule.author\"?: string | undefined; readonly \"kibana.alert.rule.created_at\"?: string | undefined; readonly \"kibana.alert.rule.created_by\"?: string | undefined; readonly \"kibana.alert.rule.description\"?: string | undefined; readonly \"kibana.alert.rule.enabled\"?: string | undefined; readonly \"kibana.alert.rule.from\"?: string | undefined; readonly \"kibana.alert.rule.interval\"?: string | undefined; readonly \"kibana.alert.rule.license\"?: string | undefined; readonly \"kibana.alert.rule.note\"?: string | undefined; readonly \"kibana.alert.rule.references\"?: string[] | undefined; readonly \"kibana.alert.rule.rule_id\"?: string | undefined; readonly \"kibana.alert.rule.rule_name_override\"?: string | undefined; readonly \"kibana.alert.rule.tags\"?: string[] | undefined; readonly \"kibana.alert.rule.to\"?: string | undefined; readonly \"kibana.alert.rule.type\"?: string | undefined; readonly \"kibana.alert.rule.updated_at\"?: string | undefined; readonly \"kibana.alert.rule.updated_by\"?: string | undefined; readonly \"kibana.alert.rule.version\"?: string | undefined; readonly 'event.kind'?: string | undefined; }" ], "path": "x-pack/plugins/rule_registry/common/parse_technical_fields.ts", "deprecated": false, diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 3ac4843ea4176..8ee1694bc58ce 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: 2022-10-03 +date: 2022-10-06 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 17f5b0c7f230d..59fd615fb3a4b 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: 2022-10-03 +date: 2022-10-06 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 5063707c3abd9..2b7c4c60248f1 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: 2022-10-03 +date: 2022-10-06 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 53186cbce4362..5464cc8db2630 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: 2022-10-03 +date: 2022-10-06 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 0032f71ba6484..e0b5d9503784e 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: 2022-10-03 +date: 2022-10-06 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 b3c954d358cb1..ed7e95fe0e92d 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: 2022-10-03 +date: 2022-10-06 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 280c60872da7d..5f0468a0de970 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: 2022-10-03 +date: 2022-10-06 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 eac6e8187a83f..7bf07eb018ac7 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: 2022-10-03 +date: 2022-10-06 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 50deed0a47fdd..597fd54b3dec8 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: 2022-10-03 +date: 2022-10-06 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 64b2f1e872dd9..3e9f91503875a 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.devdocs.json b/api_docs/security.devdocs.json index d400f91576d7d..b913d81e4e55a 100644 --- a/api_docs/security.devdocs.json +++ b/api_docs/security.devdocs.json @@ -125,6 +125,22 @@ "path": "x-pack/plugins/security/common/model/authenticated_user.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-public.AuthenticatedUser.profile_uid", + "type": "string", + "tags": [], + "label": "profile_uid", + "description": [ + "\nUser profile ID of this user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1522,6 +1538,22 @@ "path": "x-pack/plugins/security/common/model/authenticated_user.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-server.AuthenticatedUser.profile_uid", + "type": "string", + "tags": [], + "label": "profile_uid", + "description": [ + "\nUser profile ID of this user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -2517,10 +2549,6 @@ "plugin": "data", "path": "src/plugins/data/server/search/session/session_service.ts" }, - { - "plugin": "cloud", - "path": "x-pack/plugins/cloud/server/routes/chat.ts" - }, { "plugin": "ml", "path": "x-pack/plugins/ml/server/routes/annotations.ts" @@ -2557,6 +2585,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts" }, + { + "plugin": "cloudChat", + "path": "x-pack/plugins/cloud_integrations/cloud_chat/server/routes/chat.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/timeline/utils/common.ts" @@ -2688,24 +2720,6 @@ "path": "x-pack/plugins/security/server/plugin.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "security", - "id": "def-server.SecurityPluginSetup.setIsElasticCloudDeployment", - "type": "Function", - "tags": [], - "label": "setIsElasticCloudDeployment", - "description": [ - "\nSets the flag to indicate that Kibana is running inside an Elastic Cloud deployment. This flag is supposed to be\nset by the Cloud plugin and can be only once." - ], - "signature": [ - "() => void" - ], - "path": "x-pack/plugins/security/server/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] } ], "lifecycle": "setup", @@ -3077,6 +3091,22 @@ "path": "x-pack/plugins/security/common/model/authenticated_user.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "security", + "id": "def-common.AuthenticatedUser.profile_uid", + "type": "string", + "tags": [], + "label": "profile_uid", + "description": [ + "\nUser profile ID of this user." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/security/common/model/authenticated_user.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/security.mdx b/api_docs/security.mdx index b62b787d9d0e4..f940b54c45b18 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Platform Security](https://github.com/orgs/elastic/teams/kibana-securit | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 247 | 0 | 90 | 0 | +| 249 | 0 | 90 | 0 | ## Client diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 088b9d7a12e2b..3c11615878b52 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index eaddd45f9b778..a225d173ca6b8 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: 2022-10-03 +date: 2022-10-06 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 c6ba8145d4c64..9a8e85d0820fa 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: 2022-10-03 +date: 2022-10-06 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 daaaceba668b4..73c5b3f07a22d 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: 2022-10-03 +date: 2022-10-06 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 1196b40d5c3bf..32b4747415dea 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: 2022-10-03 +date: 2022-10-06 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 fdd5dfbc025b1..eb9d2bd017aaf 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: 2022-10-03 +date: 2022-10-06 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 89056c9ebd088..ba5acea2b2d08 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: 2022-10-03 +date: 2022-10-06 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 1b7e13dd4d650..cf9bb2e32ea0c 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: 2022-10-03 +date: 2022-10-06 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 8e865875b83fe..f83770436f045 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: 2022-10-03 +date: 2022-10-06 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 e5cbc94c567a3..bf8d0f7a6f946 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: 2022-10-03 +date: 2022-10-06 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 7b775d1ce3bce..2d6b0cc3acc76 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: 2022-10-03 +date: 2022-10-06 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 7312616ea8a6e..9e82ce2d35784 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.devdocs.json b/api_docs/threat_intelligence.devdocs.json index a29de53bf77a5..d5d35c60068c4 100644 --- a/api_docs/threat_intelligence.devdocs.json +++ b/api_docs/threat_intelligence.devdocs.json @@ -274,6 +274,103 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.useQuery", + "type": "Function", + "tags": [], + "label": "useQuery", + "description": [], + "signature": [ + "() => ", + "Query" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.useFilters", + "type": "Function", + "tags": [], + "label": "useFilters", + "description": [], + "signature": [ + "() => ", + "Filter", + "[]" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.useGlobalTime", + "type": "Function", + "tags": [], + "label": "useGlobalTime", + "description": [], + "signature": [ + "() => ", + "TimeRange" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.SiemSearchBar", + "type": "Function", + "tags": [], + "label": "SiemSearchBar", + "description": [], + "signature": [ + "React.VoidFunctionComponent" + ], + "path": "x-pack/plugins/threat_intelligence/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.SiemSearchBar.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "threatIntelligence", + "id": "def-public.SecuritySolutionPluginContext.SiemSearchBar.$2", + "type": "Any", + "tags": [], + "label": "context", + "description": [], + "signature": [ + "any" + ], + "path": "node_modules/@types/react/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ] } ], "initialIsOpen": false diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 4abe6fedf3bf3..ae68ef29be000 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Protections Experience Team](https://github.com/orgs/elastic/teams/prot | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 20 | 0 | 4 | 3 | +| 26 | 0 | 8 | 3 | ## Client diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 692501acd7de0..260389adca054 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: 2022-10-03 +date: 2022-10-06 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 9603096cd2b99..b973897f80fbb 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.devdocs.json b/api_docs/triggers_actions_ui.devdocs.json index d6351e414ae46..e7e28e5d542df 100644 --- a/api_docs/triggers_actions_ui.devdocs.json +++ b/api_docs/triggers_actions_ui.devdocs.json @@ -3139,7 +3139,7 @@ "description": [], "signature": [ "BasicFields", - " & { tags?: string[] | undefined; kibana?: string[] | undefined; \"@timestamp\"?: string[] | undefined; \"kibana.alert.rule.rule_type_id\"?: string[] | undefined; \"kibana.alert.rule.consumer\"?: string[] | undefined; \"event.action\"?: string[] | undefined; \"kibana.alert.rule.execution.uuid\"?: string[] | undefined; \"kibana.alert.rule.parameters\"?: string[] | undefined; \"kibana.alert.rule.producer\"?: string[] | undefined; \"kibana.space_ids\"?: string[] | undefined; \"kibana.alert.uuid\"?: string[] | undefined; \"kibana.alert.instance.id\"?: string[] | undefined; \"kibana.alert.start\"?: string[] | undefined; \"kibana.alert.end\"?: string[] | undefined; \"kibana.alert.duration.us\"?: string[] | undefined; \"kibana.alert.severity\"?: string[] | undefined; \"kibana.alert.status\"?: string[] | undefined; \"kibana.version\"?: string[] | undefined; \"ecs.version\"?: string[] | undefined; \"kibana.alert.risk_score\"?: string[] | undefined; \"kibana.alert.workflow_status\"?: string[] | undefined; \"kibana.alert.workflow_user\"?: string[] | undefined; \"kibana.alert.workflow_reason\"?: string[] | undefined; \"kibana.alert.system_status\"?: string[] | undefined; \"kibana.alert.action_group\"?: string[] | undefined; \"kibana.alert.reason\"?: string[] | undefined; \"kibana.alert.rule.author\"?: string[] | undefined; \"kibana.alert.rule.category\"?: string[] | undefined; \"kibana.alert.rule.uuid\"?: string[] | undefined; \"kibana.alert.rule.created_at\"?: string[] | undefined; \"kibana.alert.rule.created_by\"?: string[] | undefined; \"kibana.alert.rule.description\"?: string[] | undefined; \"kibana.alert.rule.enabled\"?: string[] | undefined; \"kibana.alert.rule.from\"?: string[] | undefined; \"kibana.alert.rule.interval\"?: string[] | undefined; \"kibana.alert.rule.license\"?: string[] | undefined; \"kibana.alert.rule.name\"?: string[] | undefined; \"kibana.alert.rule.note\"?: string[] | undefined; \"kibana.alert.rule.references\"?: string[] | undefined; \"kibana.alert.rule.rule_id\"?: string[] | undefined; \"kibana.alert.rule.rule_name_override\"?: string[] | undefined; \"kibana.alert.rule.tags\"?: string[] | undefined; \"kibana.alert.rule.to\"?: string[] | undefined; \"kibana.alert.rule.type\"?: string[] | undefined; \"kibana.alert.rule.updated_at\"?: string[] | undefined; \"kibana.alert.rule.updated_by\"?: string[] | undefined; \"kibana.alert.rule.version\"?: string[] | undefined; \"event.kind\"?: string[] | undefined; \"event.module\"?: string[] | undefined; \"kibana.alert.evaluation.threshold\"?: string[] | undefined; \"kibana.alert.evaluation.value\"?: string[] | undefined; \"kibana.alert.building_block_type\"?: string[] | undefined; \"kibana.alert.rule.exceptions_list\"?: string[] | undefined; \"kibana.alert.rule.namespace\"?: string[] | undefined; \"kibana.alert\"?: string[] | undefined; \"kibana.alert.rule\"?: string[] | undefined; } & { [x: string]: unknown[]; }" + " & { tags?: string[] | undefined; kibana?: string[] | undefined; \"@timestamp\"?: string[] | undefined; \"kibana.alert.rule.rule_type_id\"?: string[] | undefined; \"kibana.alert.rule.consumer\"?: string[] | undefined; \"event.action\"?: string[] | undefined; \"kibana.alert.rule.execution.uuid\"?: string[] | undefined; \"kibana.alert.rule.parameters\"?: string[] | undefined; \"kibana.alert.rule.producer\"?: string[] | undefined; \"kibana.space_ids\"?: string[] | undefined; \"kibana.alert.uuid\"?: string[] | undefined; \"kibana.alert.instance.id\"?: string[] | undefined; \"kibana.alert.start\"?: string[] | undefined; \"kibana.alert.time_range\"?: string[] | undefined; \"kibana.alert.end\"?: string[] | undefined; \"kibana.alert.duration.us\"?: string[] | undefined; \"kibana.alert.severity\"?: string[] | undefined; \"kibana.alert.status\"?: string[] | undefined; \"kibana.version\"?: string[] | undefined; \"ecs.version\"?: string[] | undefined; \"kibana.alert.risk_score\"?: string[] | undefined; \"kibana.alert.workflow_status\"?: string[] | undefined; \"kibana.alert.workflow_user\"?: string[] | undefined; \"kibana.alert.workflow_reason\"?: string[] | undefined; \"kibana.alert.system_status\"?: string[] | undefined; \"kibana.alert.action_group\"?: string[] | undefined; \"kibana.alert.reason\"?: string[] | undefined; \"kibana.alert.rule.author\"?: string[] | undefined; \"kibana.alert.rule.category\"?: string[] | undefined; \"kibana.alert.rule.uuid\"?: string[] | undefined; \"kibana.alert.rule.created_at\"?: string[] | undefined; \"kibana.alert.rule.created_by\"?: string[] | undefined; \"kibana.alert.rule.description\"?: string[] | undefined; \"kibana.alert.rule.enabled\"?: string[] | undefined; \"kibana.alert.rule.from\"?: string[] | undefined; \"kibana.alert.rule.interval\"?: string[] | undefined; \"kibana.alert.rule.license\"?: string[] | undefined; \"kibana.alert.rule.name\"?: string[] | undefined; \"kibana.alert.rule.note\"?: string[] | undefined; \"kibana.alert.rule.references\"?: string[] | undefined; \"kibana.alert.rule.rule_id\"?: string[] | undefined; \"kibana.alert.rule.rule_name_override\"?: string[] | undefined; \"kibana.alert.rule.tags\"?: string[] | undefined; \"kibana.alert.rule.to\"?: string[] | undefined; \"kibana.alert.rule.type\"?: string[] | undefined; \"kibana.alert.rule.updated_at\"?: string[] | undefined; \"kibana.alert.rule.updated_by\"?: string[] | undefined; \"kibana.alert.rule.version\"?: string[] | undefined; \"event.kind\"?: string[] | undefined; \"event.module\"?: string[] | undefined; \"kibana.alert.evaluation.threshold\"?: string[] | undefined; \"kibana.alert.evaluation.value\"?: string[] | undefined; \"kibana.alert.building_block_type\"?: string[] | undefined; \"kibana.alert.rule.exceptions_list\"?: string[] | undefined; \"kibana.alert.rule.namespace\"?: string[] | undefined; \"kibana.alert\"?: string[] | undefined; \"kibana.alert.rule\"?: string[] | undefined; } & { [x: string]: unknown[]; }" ], "path": "x-pack/plugins/triggers_actions_ui/public/types.ts", "deprecated": false, @@ -8025,6 +8025,42 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.TriggersAndActionsUIPublicPluginStart.getRuleSnoozeModal", + "type": "Function", + "tags": [], + "label": "getRuleSnoozeModal", + "description": [], + "signature": [ + "(props: ", + "RuleSnoozeModalProps", + ") => React.ReactElement<", + "RuleSnoozeModalProps", + ", string | React.JSXElementConstructor>" + ], + "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "triggersActionsUi", + "id": "def-public.TriggersAndActionsUIPublicPluginStart.getRuleSnoozeModal.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "RuleSnoozeModalProps" + ], + "path": "x-pack/plugins/triggers_actions_ui/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "lifecycle": "start", diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index a9c60110ba139..d0d49f39223d6 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Response Ops](https://github.com/orgs/elastic/teams/response-ops) for q | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 512 | 1 | 485 | 48 | +| 514 | 1 | 487 | 49 | ## Client diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 734e896cbdf27..1b0567664a9fc 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: 2022-10-03 +date: 2022-10-06 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 5ac50aa29c085..99549d8c1e530 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_field_list.mdx b/api_docs/unified_field_list.mdx index 2818641379fb7..245e4c107d5b9 100644 --- a/api_docs/unified_field_list.mdx +++ b/api_docs/unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedFieldList title: "unifiedFieldList" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedFieldList plugin -date: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedFieldList'] --- import unifiedFieldListObj from './unified_field_list.devdocs.json'; diff --git a/api_docs/unified_search.devdocs.json b/api_docs/unified_search.devdocs.json index 5678db92f00cd..69a6b1dece26f 100644 --- a/api_docs/unified_search.devdocs.json +++ b/api_docs/unified_search.devdocs.json @@ -11,7 +11,7 @@ "label": "DataViewPicker", "description": [], "signature": [ - "({ isMissingCurrent, currentDataViewId, adHocDataViews, onChangeDataView, onAddField, onDataViewCreated, trigger, selectableProps, textBasedLanguages, onSaveTextLanguageQuery, onTextLangQuerySubmit, textBasedLanguage, onCreateDefaultAdHocDataView, isDisabled, }: ", + "({ isMissingCurrent, currentDataViewId, adHocDataViews, onChangeDataView, onEditDataView, onAddField, onDataViewCreated, trigger, selectableProps, textBasedLanguages, onSaveTextLanguageQuery, onTextLangQuerySubmit, textBasedLanguage, onCreateDefaultAdHocDataView, isDisabled, }: ", "DataViewPickerPropsExtended", ") => JSX.Element" ], @@ -24,7 +24,7 @@ "id": "def-public.DataViewPicker.$1", "type": "Object", "tags": [], - "label": "{\n isMissingCurrent,\n currentDataViewId,\n adHocDataViews,\n onChangeDataView,\n onAddField,\n onDataViewCreated,\n trigger,\n selectableProps,\n textBasedLanguages,\n onSaveTextLanguageQuery,\n onTextLangQuerySubmit,\n textBasedLanguage,\n onCreateDefaultAdHocDataView,\n isDisabled,\n}", + "label": "{\n isMissingCurrent,\n currentDataViewId,\n adHocDataViews,\n onChangeDataView,\n onEditDataView,\n onAddField,\n onDataViewCreated,\n trigger,\n selectableProps,\n textBasedLanguages,\n onSaveTextLanguageQuery,\n onTextLangQuerySubmit,\n textBasedLanguage,\n onCreateDefaultAdHocDataView,\n isDisabled,\n}", "description": [], "signature": [ "DataViewPickerPropsExtended" @@ -553,6 +553,54 @@ ], "returnComment": [] }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.DataViewPickerProps.onEditDataView", + "type": "Function", + "tags": [], + "label": "onEditDataView", + "description": [ + "\nCallback that is called when the user edits the current data view via flyout.\nThe first parameter is the updated data view stub without fetched fields" + ], + "signature": [ + "((updatedDataViewStub: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ") => void) | undefined" + ], + "path": "src/plugins/unified_search/public/dataview_picker/index.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "unifiedSearch", + "id": "def-public.DataViewPickerProps.onEditDataView.$1", + "type": "Object", + "tags": [], + "label": "updatedDataViewStub", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "src/plugins/unified_search/public/dataview_picker/index.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "unifiedSearch", "id": "def-public.DataViewPickerProps.currentDataViewId", @@ -1110,6 +1158,26 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "unifiedSearch", + "id": "def-public.IUnifiedSearchPluginServices.dataViewEditor", + "type": "Object", + "tags": [], + "label": "dataViewEditor", + "description": [], + "signature": [ + { + "pluginId": "dataViewEditor", + "scope": "public", + "docId": "kibDataViewEditorPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + } + ], + "path": "src/plugins/unified_search/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "unifiedSearch", "id": "def-public.IUnifiedSearchPluginServices.usageCollection", diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index ed31e74c5d7eb..7ab3c665f986f 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-servic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 128 | 2 | 102 | 17 | +| 131 | 2 | 104 | 17 | ## Client diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index e75d86bbab218..a34f0ec3eda4b 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; @@ -21,7 +21,7 @@ Contact [Unified Search](https://github.com/orgs/elastic/teams/kibana-app-servic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 128 | 2 | 102 | 17 | +| 131 | 2 | 104 | 17 | ## Client diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 0ac5762c42af3..ac0bdd4b2b004 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: 2022-10-03 +date: 2022-10-06 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 b493774dc1eb3..d48cba9114566 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: 2022-10-03 +date: 2022-10-06 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 f3c60dc8b7b43..c305ed9b2bf0a 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: 2022-10-03 +date: 2022-10-06 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 ec4208a4a06da..295bab786c7d5 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: 2022-10-03 +date: 2022-10-06 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 43f73daa08070..84e7e03c74643 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: 2022-10-03 +date: 2022-10-06 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 d537797699cab..0dc49ef6c3392 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: 2022-10-03 +date: 2022-10-06 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 08324c72b813f..37c247520e550 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: 2022-10-03 +date: 2022-10-06 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 7d052e7dd40fb..52857476db6e0 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: 2022-10-03 +date: 2022-10-06 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 696edbd5d321e..dff81b44b8dd1 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: 2022-10-03 +date: 2022-10-06 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 ef87c344661e6..a16d5ea13e4bf 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: 2022-10-03 +date: 2022-10-06 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 1a5a44160bf46..249b503d192aa 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: 2022-10-03 +date: 2022-10-06 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 8651bb82ad813..246443fccfef5 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: 2022-10-03 +date: 2022-10-06 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 440839b51793a..0ac6f081a6579 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 2edc6b736c5b6..194f3ebf958f5 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: 2022-10-03 +date: 2022-10-06 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/docs/api-generated/README.md b/docs/api-generated/README.md new file mode 100644 index 0000000000000..4ce033e47ea0b --- /dev/null +++ b/docs/api-generated/README.md @@ -0,0 +1,36 @@ +# OpenAPI (Experimental) + +Open API specifications (OAS) exist in JSON or YAML format for some Kibana features, +though they are experimental and may be incomplete or change later. + +A preview of the API specifications can be added to the Kibana Guide by using +the following process: + +. Install [OpenAPI Generator](https://openapi-generator.tech/docs/installation), +or a similar tool that can generate HTML output from OAS. + +. Optionally validate the specifications by using the commands listed in the appropriate readmes. + +. Generate HTML output. For example: + + ``` + openapi-generator-cli generate -g html -i ~/kibana/x-pack/plugins/cases/docs/openapi/entrypoint.yaml -o ~/kibana/docs/api-generated/cases -t ~/kibana/docs/api-generated/template + + openapi-generator-cli generate -g html -i ~/kibana/x-pack/plugins/ml/common/openapi/ml_apis_v3.yaml -o ~/kibana/docs/api-generated/machine-learning -t ~/kibana/docs/api-generated/template + ``` + +. Rename the output files. For example: + ``` + mv ~/kibana/docs/api-generated/cases/index.html case-apis-passthru.asciidoc + mv ~/kibana/docs/api-generated/machine-learning/index.html ml-apis-passthru.adoc + ``` + +. If you're creating a new set of API output, you will need to have a page that incorporates the output by using passthrough blocks. For more information, refer to [Asciidoctor docs](https://docs.asciidoctor.org/asciidoc/latest/pass/pass-block/) + +. Verify the output by building the Kibana documentation. At this time, the output is added as a technical preview in the appendix. + +## Known issues + +- Some OAS 3.0 features such as `anyOf`, `oneOf`, and `allOf` might not display properly in the preview. These are on the [Short-term roadmap](https://openapi-generator.tech/docs/roadmap/) at this time. + + diff --git a/docs/api-generated/cases/case-apis-passthru.asciidoc b/docs/api-generated/cases/case-apis-passthru.asciidoc new file mode 100644 index 0000000000000..2a07283aa98e0 --- /dev/null +++ b/docs/api-generated/cases/case-apis-passthru.asciidoc @@ -0,0 +1,827 @@ +//// +This content is generated from the open API specification. +Any modifications made to this file will be overwritten. +//// + +++++ +
+

Access

+
    +
  1. APIKey KeyParamName:ApiKey KeyInQuery:false KeyInHeader:true
  2. +
  3. HTTP Basic Authentication
  4. +
+ +

Methods

+ [ Jump to Models ] + +

Table of Contents

+
+

Cases

+ + +

Cases

+
+
+ Up +
post /s/{spaceId}/api/cases/{caseId}/comments
+
Adds a comment or alert to a case. (addCaseComment)
+
You must have all privileges for the Cases feature in the Management, Observability, or Security section of the Kibana feature privileges, depending on the owner of the case you're creating.
+ +

Path parameters

+
+
caseId (required)
+ +
Path Parameter — The identifier for the case. To retrieve case IDs, use the find cases API. All non-ASCII characters must be URL encoded. default: null
spaceId (required)
+ +
Path Parameter — An identifier for the space. If /s/ and the identifier are omitted from the path, the default space is used. default: null
+
+ +

Consumes

+ This API call consumes the following media types via the Content-Type request header: +
    +
  • application/json
  • +
+ +

Request body

+
+
add_case_comment_request add_case_comment_request (required)
+ +
Body Parameter
+ +
+ +

Request headers

+
+
kbn-xsrf (required)
+ +
Header Parameter — default: null
+ +
+ + + +

Return type

+ + + + +

Example data

+
Content-Type: application/json
+
{
+  "owner" : "cases",
+  "totalComment" : 0,
+  "settings" : {
+    "syncAlerts" : true
+  },
+  "totalAlerts" : 0,
+  "closed_at" : "2000-01-23T04:56:07.000+00:00",
+  "comments" : [ null, null ],
+  "created_at" : "2022-05-13T09:16:17.416Z",
+  "description" : "A case description.",
+  "title" : "Case title 1",
+  "created_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "version" : "WzUzMiwxXQ==",
+  "closed_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "tags" : [ "tag-1" ],
+  "duration" : 120,
+  "connector" : {
+    "name" : "none",
+    "id" : "none",
+    "fields" : {
+      "destIp" : "destIp",
+      "severity" : "severity",
+      "parent" : "parent",
+      "impact" : "impact",
+      "malwareUrl" : "malwareUrl",
+      "priority" : "priority",
+      "issueTypes" : [ 0.8008281904610115, 0.8008281904610115 ],
+      "issueType" : "issueType",
+      "sourceIp" : "sourceIp",
+      "urgency" : "urgency",
+      "malwareHash" : "malwareHash",
+      "caseId" : "caseId",
+      "severityCode" : 6.027456183070403,
+      "category" : "category",
+      "subcategory" : "subcategory"
+    },
+    "type" : ".none"
+  },
+  "updated_at" : "2000-01-23T04:56:07.000+00:00",
+  "updated_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "id" : "66b9aa00-94fa-11ea-9f74-e7e108796192",
+  "external_service" : {
+    "external_title" : "external_title",
+    "pushed_by" : {
+      "full_name" : "full_name",
+      "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+      "email" : "email",
+      "username" : "elastic"
+    },
+    "external_url" : "external_url",
+    "pushed_at" : "2000-01-23T04:56:07.000+00:00",
+    "connector_id" : "connector_id",
+    "external_id" : "external_id",
+    "connector_name" : "connector_name"
+  }
+}
+ +

Produces

+ This API call produces the following media types according to the Accept request header; + the media type will be conveyed by the Content-Type response header. +
    +
  • application/json
  • +
+ +

Responses

+

200

+ Indicates a successful call. + case_response_properties +
+
+
+
+ Up +
delete /s/{spaceId}/api/cases/{caseId}/comments
+
Deletes all comments and alerts from a case. (deleteCaseComments)
+
You must have all privileges for the Cases feature in the Management, Observability, or Security section of the Kibana feature privileges, depending on the owner of the cases you're deleting.
+ +

Path parameters

+
+
caseId (required)
+ +
Path Parameter — The identifier for the case. To retrieve case IDs, use the find cases API. All non-ASCII characters must be URL encoded. default: null
spaceId (required)
+ +
Path Parameter — An identifier for the space. If /s/ and the identifier are omitted from the path, the default space is used. default: null
+
+ + + +

Request headers

+
+
kbn-xsrf (required)
+ +
Header Parameter — default: null
+ +
+ + + + + + + + +

Responses

+

204

+ Indicates a successful call. + +
+
+
+
+ Up +
get /s/{spaceId}/api/cases/{caseId}/comments
+
Retrieves all the comments from a case. (getAllCaseComments)
+
You must have read privileges for the Cases feature in the Management, Observability, or Security section of the Kibana feature privileges, depending on the owner of the cases with the comments you're seeking.
+ +

Path parameters

+
+
caseId (required)
+ +
Path Parameter — The identifier for the case. To retrieve case IDs, use the find cases API. All non-ASCII characters must be URL encoded. default: null
spaceId (required)
+ +
Path Parameter — An identifier for the space. If /s/ and the identifier are omitted from the path, the default space is used. default: null
+
+ + + + + + +

Return type

+ + + + +

Example data

+
Content-Type: application/json
+
{
+  "owner" : "cases",
+  "totalComment" : 0,
+  "settings" : {
+    "syncAlerts" : true
+  },
+  "totalAlerts" : 0,
+  "closed_at" : "2000-01-23T04:56:07.000+00:00",
+  "comments" : [ null, null ],
+  "created_at" : "2022-05-13T09:16:17.416Z",
+  "description" : "A case description.",
+  "title" : "Case title 1",
+  "created_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "version" : "WzUzMiwxXQ==",
+  "closed_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "tags" : [ "tag-1" ],
+  "duration" : 120,
+  "connector" : {
+    "name" : "none",
+    "id" : "none",
+    "fields" : {
+      "destIp" : "destIp",
+      "severity" : "severity",
+      "parent" : "parent",
+      "impact" : "impact",
+      "malwareUrl" : "malwareUrl",
+      "priority" : "priority",
+      "issueTypes" : [ 0.8008281904610115, 0.8008281904610115 ],
+      "issueType" : "issueType",
+      "sourceIp" : "sourceIp",
+      "urgency" : "urgency",
+      "malwareHash" : "malwareHash",
+      "caseId" : "caseId",
+      "severityCode" : 6.027456183070403,
+      "category" : "category",
+      "subcategory" : "subcategory"
+    },
+    "type" : ".none"
+  },
+  "updated_at" : "2000-01-23T04:56:07.000+00:00",
+  "updated_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "id" : "66b9aa00-94fa-11ea-9f74-e7e108796192",
+  "external_service" : {
+    "external_title" : "external_title",
+    "pushed_by" : {
+      "full_name" : "full_name",
+      "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+      "email" : "email",
+      "username" : "elastic"
+    },
+    "external_url" : "external_url",
+    "pushed_at" : "2000-01-23T04:56:07.000+00:00",
+    "connector_id" : "connector_id",
+    "external_id" : "external_id",
+    "connector_name" : "connector_name"
+  }
+}
+ +

Produces

+ This API call produces the following media types according to the Accept request header; + the media type will be conveyed by the Content-Type response header. +
    +
  • application/json
  • +
+ +

Responses

+

200

+ Indicates a successful call. + case_response_properties +
+
+
+
+ Up +
patch /s/{spaceId}/api/cases/{caseId}/comments
+
Updates a comment or alert in a case. (updateCaseComment)
+
You must have all privileges for the Cases feature in the Management, Observability, or Security section of the Kibana feature privileges, depending on the owner of the case you're updating. NOTE: You cannot change the comment type or the owner of a comment.
+ +

Path parameters

+
+
caseId (required)
+ +
Path Parameter — The identifier for the case. To retrieve case IDs, use the find cases API. All non-ASCII characters must be URL encoded. default: null
spaceId (required)
+ +
Path Parameter — An identifier for the space. If /s/ and the identifier are omitted from the path, the default space is used. default: null
+
+ +

Consumes

+ This API call consumes the following media types via the Content-Type request header: +
    +
  • application/json
  • +
+ +

Request body

+
+
update_case_comment_request update_case_comment_request (required)
+ +
Body Parameter
+ +
+ +

Request headers

+
+
kbn-xsrf (required)
+ +
Header Parameter — default: null
+ +
+ + + +

Return type

+ + + + +

Example data

+
Content-Type: application/json
+
{
+  "owner" : "cases",
+  "totalComment" : 0,
+  "settings" : {
+    "syncAlerts" : true
+  },
+  "totalAlerts" : 0,
+  "closed_at" : "2000-01-23T04:56:07.000+00:00",
+  "comments" : [ null, null ],
+  "created_at" : "2022-05-13T09:16:17.416Z",
+  "description" : "A case description.",
+  "title" : "Case title 1",
+  "created_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "version" : "WzUzMiwxXQ==",
+  "closed_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "tags" : [ "tag-1" ],
+  "duration" : 120,
+  "connector" : {
+    "name" : "none",
+    "id" : "none",
+    "fields" : {
+      "destIp" : "destIp",
+      "severity" : "severity",
+      "parent" : "parent",
+      "impact" : "impact",
+      "malwareUrl" : "malwareUrl",
+      "priority" : "priority",
+      "issueTypes" : [ 0.8008281904610115, 0.8008281904610115 ],
+      "issueType" : "issueType",
+      "sourceIp" : "sourceIp",
+      "urgency" : "urgency",
+      "malwareHash" : "malwareHash",
+      "caseId" : "caseId",
+      "severityCode" : 6.027456183070403,
+      "category" : "category",
+      "subcategory" : "subcategory"
+    },
+    "type" : ".none"
+  },
+  "updated_at" : "2000-01-23T04:56:07.000+00:00",
+  "updated_by" : {
+    "full_name" : "full_name",
+    "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+    "email" : "email",
+    "username" : "elastic"
+  },
+  "id" : "66b9aa00-94fa-11ea-9f74-e7e108796192",
+  "external_service" : {
+    "external_title" : "external_title",
+    "pushed_by" : {
+      "full_name" : "full_name",
+      "profile_uid" : "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0",
+      "email" : "email",
+      "username" : "elastic"
+    },
+    "external_url" : "external_url",
+    "pushed_at" : "2000-01-23T04:56:07.000+00:00",
+    "connector_id" : "connector_id",
+    "external_id" : "external_id",
+    "connector_name" : "connector_name"
+  }
+}
+ +

Produces

+ This API call produces the following media types according to the Accept request header; + the media type will be conveyed by the Content-Type response header. +
    +
  • application/json
  • +
+ +

Responses

+

200

+ Indicates a successful call. + case_response_properties +
+
+ +

Models

+ [ Jump to Methods ] + +

Table of Contents

+
    +
  1. Case_response_properties_for_comments_inner -
  2. +
  3. Case_response_properties_for_connectors - Case response properties for connectors
  4. +
  5. add_alert_comment_request_properties - Add case comment request properties for alerts
  6. +
  7. add_case_comment_request - Add case comment request
  8. +
  9. add_user_comment_request_properties - Add case comment request properties for user comments
  10. +
  11. alert_comment_response_properties - Add case comment response properties for alerts
  12. +
  13. alert_comment_response_properties_created_by -
  14. +
  15. alert_comment_response_properties_pushed_by -
  16. +
  17. alert_comment_response_properties_rule -
  18. +
  19. alert_identifiers - Alert identifiers
  20. +
  21. alert_indices - Alert indices
  22. +
  23. case_response_closed_by_properties - Case response properties for closed_by
  24. +
  25. case_response_connector_field_properties - Case response properties for connector fields
  26. +
  27. case_response_created_by_properties - Case response properties for created_by
  28. +
  29. case_response_properties - Case response properties
  30. +
  31. case_response_pushed_by_properties - Case response properties for pushed_by
  32. +
  33. case_response_updated_by_properties - Case response properties for updated_by
  34. +
  35. connector_types -
  36. +
  37. external_service -
  38. +
  39. owners -
  40. +
  41. rule - Alerting rule
  42. +
  43. settings -
  44. +
  45. severity_property -
  46. +
  47. status -
  48. +
  49. update_alert_comment_request_properties - Update case comment request properties for alerts
  50. +
  51. update_case_comment_request - Update case comment request
  52. +
  53. update_user_comment_request_properties - Update case comment request properties for user comments
  54. +
  55. user_comment_response_properties - Case response properties for user comments
  56. +
+ +
+

Case_response_properties_for_comments_inner - Up

+
+
+
alertId (optional)
+
created_at (optional)
Date format: date-time
+
created_by (optional)
+
id (optional)
+
index (optional)
+
owner (optional)
+
pushed_at (optional)
Date format: date-time
+
pushed_by (optional)
+
rule (optional)
+
type
+
Enum:
+
user
+
updated_at (optional)
Date format: date-time
+
updated_by (optional)
+
version (optional)
+
comment (optional)
+
+
+
+

Case_response_properties_for_connectors - Case response properties for connectors Up

+
+
+
fields (optional)
+
id (optional)
String The identifier for the connector. To create a case without a connector, use none.
+
name (optional)
String The name of the connector. To create a case without a connector, use none.
+
type (optional)
+
+
+
+

add_alert_comment_request_properties - Add case comment request properties for alerts Up

+
Defines properties for case comment requests when type is alert.
+
+
alertId
+
index
+
owner
+
rule
+
type
String The type of comment.
+
Enum:
+
alert
+
+
+
+

add_case_comment_request - Add case comment request Up

+
The add comment to case API request body varies depending on whether you are adding an alert or a comment.
+
+
alertId
+
index
+
owner
+
rule
+
type
String The type of comment.
+
Enum:
+
user
+
comment
String The new comment. It is required only when type is user.
+
+
+
+

add_user_comment_request_properties - Add case comment request properties for user comments Up

+
Defines properties for case comment requests when type is user.
+
+
comment
String The new comment. It is required only when type is user.
+
owner
+
type
String The type of comment.
+
Enum:
+
user
+
+
+
+

alert_comment_response_properties - Add case comment response properties for alerts Up

+
+
+
alertId (optional)
+
created_at (optional)
Date format: date-time
+
created_by (optional)
+
id (optional)
+
index (optional)
+
owner (optional)
+
pushed_at (optional)
Date format: date-time
+
pushed_by (optional)
+
rule (optional)
+
type
+
Enum:
+
alert
+
updated_at (optional)
Date format: date-time
+
updated_by (optional)
+
version (optional)
+
+
+
+

alert_comment_response_properties_created_by - Up

+
+
+
email (optional)
+
full_name (optional)
+
username (optional)
+
profile_uid (optional)
+
+
+
+

alert_comment_response_properties_pushed_by - Up

+
+
+
email (optional)
+
full_name (optional)
+
username (optional)
+
profile_uid (optional)
+
+
+
+

alert_comment_response_properties_rule - Up

+
+
+
id (optional)
String The rule identifier.
+
name (optional)
String The rule name.
+
+
+
+

alert_identifiers - Alert identifiers Up

+
The alert identifier. It is required only when type is alert. If it is an array, index must also be an array with the same length or number of elements. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.
+
+
+
+
+

alert_indices - Alert indices Up

+
The alert index. It is required only when type is alert. If it is an array, alertId must also be an array with the same length or number of elements. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.
+
+
+
+
+

case_response_closed_by_properties - Case response properties for closed_by Up

+
+
+
email
+
full_name
+
username
+
profile_uid (optional)
+
+
+
+

case_response_connector_field_properties - Case response properties for connector fields Up

+
An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value.
+
+
caseId (optional)
String The case identifier for Swimlane connectors.
+
category (optional)
String The category of the incident for ServiceNow ITSM and ServiceNow SecOps connectors.
+
destIp (optional)
String A comma-separated list of destination IPs for ServiceNow SecOps connectors.
+
impact (optional)
String The effect an incident had on business for ServiceNow ITSM connectors.
+
issueType (optional)
String The type of issue for Jira connectors.
+
issueTypes (optional)
array[BigDecimal] The type of incident for IBM Resilient connectors.
+
malwareHash (optional)
String A comma-separated list of malware hashes for ServiceNow SecOps connectors.
+
malwareUrl (optional)
String A comma-separated list of malware URLs for ServiceNow SecOps connectors.
+
parent (optional)
String The key of the parent issue, when the issue type is sub-task for Jira connectors.
+
priority (optional)
String The priority of the issue for Jira and ServiceNow SecOps connectors.
+
severity (optional)
String The severity of the incident for ServiceNow ITSM connectors.
+
severityCode (optional)
BigDecimal The severity code of the incident for IBM Resilient connectors.
+
sourceIp (optional)
String A comma-separated list of source IPs for ServiceNow SecOps connectors.
+
subcategory (optional)
String The subcategory of the incident for ServiceNow ITSM connectors.
+
urgency (optional)
String The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors.
+
+
+
+

case_response_created_by_properties - Case response properties for created_by Up

+
+
+
email
+
full_name
+
username
+
profile_uid (optional)
+
+
+
+

case_response_properties - Case response properties Up

+
+
+
closed_at
Date format: date-time
+
closed_by
+
comments
array[Case_response_properties_for_comments_inner] An array of comment objects for the case.
+
connector
+
created_at
Date format: date-time
+
created_by
+
description
+
duration
Integer The elapsed time from the creation of the case to its closure (in seconds). If the case has not been closed, the duration is set to null. If the case was closed after less than half a second, the duration is rounded down to zero.
+
external_service
+
id
+
owner
+
settings
+
severity
+
status
+
tags
+
title
+
totalAlerts
+
totalComment
+
updated_at
Date format: date-time
+
updated_by
+
version
+
+
+
+

case_response_pushed_by_properties - Case response properties for pushed_by Up

+
+
+
email
+
full_name
+
username
+
profile_uid (optional)
+
+
+
+

case_response_updated_by_properties - Case response properties for updated_by Up

+
+
+
email
+
full_name
+
username
+
profile_uid (optional)
+
+
+
+

connector_types - Up

+
The type of connector.
+
+
+
+
+

external_service - Up

+
+
+
connector_id (optional)
+
connector_name (optional)
+
external_id (optional)
+
external_title (optional)
+
external_url (optional)
+
pushed_at (optional)
Date format: date-time
+
pushed_by (optional)
+
+
+
+

owners - Up

+
The application that owns the cases: Stack Management, Observability, or Elastic Security.
+
+
+
+
+

rule - Alerting rule Up

+
The rule that is associated with the alert. It is required only when type is alert. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.
+
+
id (optional)
String The rule identifier.
+
name (optional)
String The rule name.
+
+
+
+

settings - Up

+
An object that contains the case settings.
+
+
syncAlerts (optional)
Boolean Turns alert syncing on or off.
+
+
+
+

severity_property - Up

+
The severity of the case.
+
+
+
+
+

status - Up

+
The status of the case.
+
+
+
+
+

update_alert_comment_request_properties - Update case comment request properties for alerts Up

+
Defines properties for case comment requests when type is alert.
+
+
alertId
+
id
String The identifier for the comment. To retrieve comment IDs, use the get comments API.
+
index
+
owner
+
rule
+
type
String The type of comment.
+
Enum:
+
alert
+
version
String The current comment version. To retrieve version values, use the get comments API.
+
+
+
+

update_case_comment_request - Update case comment request Up

+
The update case comment API request body varies depending on whether you are updating an alert or a comment.
+
+
alertId
+
id
String The identifier for the comment. To retrieve comment IDs, use the get comments API.
+
index
+
owner
+
rule
+
type
String The type of comment.
+
Enum:
+
user
+
version
String The current comment version. To retrieve version values, use the get comments API.
+
comment
String The new comment. It is required only when type is user.
+
+
+
+

update_user_comment_request_properties - Update case comment request properties for user comments Up

+
Defines properties for case comment requests when type is user.
+
+
comment
String The new comment. It is required only when type is user.
+
id
String The identifier for the comment. To retrieve comment IDs, use the get comments API.
+
owner
+
type
String The type of comment.
+
Enum:
+
user
+
version
String The current comment version. To retrieve version values, use the get comments API.
+
+
+
+

user_comment_response_properties - Case response properties for user comments Up

+
+
+
comment (optional)
+
created_at (optional)
Date format: date-time
+
created_by (optional)
+
id (optional)
+
owner (optional)
+
pushed_at (optional)
Date format: date-time
+
pushed_by (optional)
+
type
+
Enum:
+
user
+
updated_at (optional)
Date format: date-time
+
updated_by (optional)
+
version (optional)
+
+
+
+++++ diff --git a/docs/api-generated/cases/case-apis.asciidoc b/docs/api-generated/cases/case-apis.asciidoc new file mode 100644 index 0000000000000..fdd9a941a58e6 --- /dev/null +++ b/docs/api-generated/cases/case-apis.asciidoc @@ -0,0 +1,10 @@ +[[case-apis]] +== Case APIs + +preview::[] + +//// +This file includes content that has been generated from https://github.com/elastic/kibana/tree/main/x-pack/plugins/cases/docs/openapi. Any modifications required must be done in that open API specification. +//// + +include::case-apis-passthru.asciidoc[] \ No newline at end of file diff --git a/docs/api/cases/cases-api-add-comment.asciidoc b/docs/api/cases/cases-api-add-comment.asciidoc index 618f4a5de8842..918f579f1c0de 100644 --- a/docs/api/cases/cases-api-add-comment.asciidoc +++ b/docs/api/cases/cases-api-add-comment.asciidoc @@ -6,6 +6,12 @@ Adds a comment or alert to a case. +[NOTE] +==== +For the most up-to-date API details, refer to the +{kib-repo}/tree/{branch}/x-pack/plugins/cases/docs/openapi[open API specification]. For a preview, check out <>. +==== + === {api-request-title} `POST :/api/cases//comments` diff --git a/docs/api/cases/cases-api-delete-comments.asciidoc b/docs/api/cases/cases-api-delete-comments.asciidoc index 50866cfbe85fd..130158bd021c2 100644 --- a/docs/api/cases/cases-api-delete-comments.asciidoc +++ b/docs/api/cases/cases-api-delete-comments.asciidoc @@ -6,6 +6,12 @@ Deletes one or all comments and alerts from a case. +[NOTE] +==== +For the most up-to-date API details, refer to the +{kib-repo}/tree/{branch}/x-pack/plugins/cases/docs/openapi[open API specification]. For a preview, check out <>. +==== + === {api-request-title} `DELETE :/api/cases//comments` diff --git a/docs/api/cases/cases-api-get-comments.asciidoc b/docs/api/cases/cases-api-get-comments.asciidoc index 58c4c32acfa15..5f7bb938f588a 100644 --- a/docs/api/cases/cases-api-get-comments.asciidoc +++ b/docs/api/cases/cases-api-get-comments.asciidoc @@ -6,6 +6,12 @@ Gets a comment or all comments for a case. +[NOTE] +==== +For the most up-to-date API details, refer to the +{kib-repo}/tree/{branch}/x-pack/plugins/cases/docs/openapi[open API specification]. For a preview, check out <>. +==== + === {api-request-title} `GET :/api/cases//comments/` diff --git a/docs/api/cases/cases-api-update-comment.asciidoc b/docs/api/cases/cases-api-update-comment.asciidoc index 127d434602f84..4f2e89a7997ea 100644 --- a/docs/api/cases/cases-api-update-comment.asciidoc +++ b/docs/api/cases/cases-api-update-comment.asciidoc @@ -6,6 +6,12 @@ Updates a comment or alert in a case. +[NOTE] +==== +For the most up-to-date API details, refer to the +{kib-repo}/tree/{branch}/x-pack/plugins/cases/docs/openapi[open API specification]. For a preview, check out <>. +==== + === {api-request-title} `PATCH :/api/cases//comments` diff --git a/docs/api/saved-objects/find.asciidoc b/docs/api/saved-objects/find.asciidoc index 43c7f4cde8fa8..275bd1c21f9ed 100644 --- a/docs/api/saved-objects/find.asciidoc +++ b/docs/api/saved-objects/find.asciidoc @@ -52,6 +52,15 @@ experimental[] Retrieve a paginated set of {kib} saved objects by various condit `has_reference`:: (Optional, object) Filters to objects that have a relationship with the type and ID combination. +`has_reference_operator`:: + (Optional, string) The operator to use for the `has_reference` parameter. Either `OR` or `AND`. Defaults to `OR`. + +`has_no_reference`:: + (Optional, object) Filters to objects that do not have a relationship with the type and ID combination. + +`has_no_reference_operator`:: + (Optional, string) The operator to use for the `has_no_reference` parameter. Either `OR` or `AND`. Defaults to `OR`. + `filter`:: (Optional, string) The filter is a KQL string with the caveat that if you filter with an attribute from your saved object type, it should look like that: `savedObjectType.attributes.title: "myTitle"`. However, If you use a root attribute of a saved diff --git a/docs/apis.asciidoc b/docs/apis.asciidoc index 8fb4caa7d3fca..8b07e58d4f8aa 100644 --- a/docs/apis.asciidoc +++ b/docs/apis.asciidoc @@ -11,4 +11,5 @@ version of the specification is 3.0. For more information, go to https://openapi -- +include::api-generated/cases/case-apis.asciidoc[] include::api-generated/machine-learning/ml-apis.asciidoc[] \ No newline at end of file diff --git a/docs/apm/api.asciidoc b/docs/apm/api.asciidoc index ce8c7fb2011b2..1e0788cb56768 100644 --- a/docs/apm/api.asciidoc +++ b/docs/apm/api.asciidoc @@ -762,7 +762,7 @@ POST /_security/role/apm_agent_key_user "cluster": ["manage_own_api_key"], "applications": [{ "application": "apm", - "privileges": ["event:write", "sourcemap:write", "config_agent:read"], + "privileges": ["event:write", "config_agent:read"], "resources": ["*"] }] } @@ -785,7 +785,6 @@ POST /_security/role/apm_agent_key_user - `event:write`. Required for ingesting agent events. - `config_agent:read`. Required for agents to read agent configuration remotely. - - `sourcemap:write`. Required for uploading sourcemaps. [[apm-agent-key-create-example]] ===== Example @@ -795,7 +794,7 @@ POST /_security/role/apm_agent_key_user POST /api/apm/agent_keys { "name": "apm-key", - "privileges": ["event:write", "config_agent:read", "sourcemap:write"] + "privileges": ["event:write", "config_agent:read"] } -------------------------------------------------- diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index f4fc9c67508ef..4853d859b371a 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -71,7 +71,7 @@ as uiSettings within the code. |{kib-repo}blob/{branch}/src/plugins/data_views/README.mdx[dataViews] |The data views API provides a consistent method of structuring and formatting documents -and field lists across the various Kibana apps. Its typically used in conjunction with +and field lists across the various Kibana apps. It's typically used in conjunction with for composing queries. @@ -424,10 +424,22 @@ The plugin exposes the static DefaultEditorController class to consume. |The cloud plugin adds Cloud-specific features to Kibana. +|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_chat/README.md[cloudChat] +|Integrates with DriftChat in order to provide live support to our Elastic Cloud users. This plugin should only run on Elastic Cloud. + + |{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_experiments/README.mdx[cloudExperiments] |The Cloud Experiments Service provides the necessary APIs to implement A/B testing scenarios, fetching the variations in configuration and reporting back metrics to track conversion rates of the experiments. +|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_full_story/README.md[cloudFullStory] +|Integrates with FullStory in order to provide better product analytics, so we can understand how our users make use of Kibana. This plugin should only run on Elastic Cloud. + + +|{kib-repo}blob/{branch}/x-pack/plugins/cloud_integrations/cloud_links/README.md[cloudLinks] +|Adds all the links to the Elastic Cloud console. + + |{kib-repo}blob/{branch}/x-pack/plugins/cloud_security_posture/README.md[cloudSecurityPosture] |Cloud Posture automates the identification and remediation of risks across cloud infrastructures diff --git a/docs/settings/search-sessions-settings.asciidoc b/docs/settings/search-sessions-settings.asciidoc index 7628ecfb397e1..7a51c23c9a1cc 100644 --- a/docs/settings/search-sessions-settings.asciidoc +++ b/docs/settings/search-sessions-settings.asciidoc @@ -10,9 +10,6 @@ Configure the search session settings in your `kibana.yml` configuration file. `data.search.sessions.enabled` {ess-icon}:: Set to `true` (default) to enable search sessions. -`data.search.sessions.trackingInterval` {ess-icon}:: -The frequency for updating the state of a search session. The default is `10s`. - `data.search.sessions.pageSize` {ess-icon}:: How many search sessions {kib} processes at once while monitoring session progress. The default is `100`. @@ -21,9 +18,6 @@ session progress. The default is `100`. How long {kib} stores search results from unsaved sessions, after the last search in the session completes. The default is `5m`. -`data.search.sessions.notTouchedInProgressTimeout` {ess-icon}:: -How long a search session can run after a user navigates away without saving a session. The default is `1m`. - `data.search.sessions.maxUpdateRetries` {ess-icon}:: How many retries {kib} can perform while attempting to save a search session. The default is `3`. diff --git a/docs/user/alerting/rule-types/es-query.asciidoc b/docs/user/alerting/rule-types/es-query.asciidoc index 715fabc6fdc38..c838200e637e1 100644 --- a/docs/user/alerting/rule-types/es-query.asciidoc +++ b/docs/user/alerting/rule-types/es-query.asciidoc @@ -26,7 +26,7 @@ the *time window*. Size:: Specifies the number of documents to pass to the configured actions when the threshold condition is met. {es} query:: Specifies the ES DSL query. The number of documents that -match this query is evaluated against the threshold condition. Only the `query`, `fields` and `runtime_mappings` +match this query is evaluated against the threshold condition. Only the `query`, `fields`, `_source` and `runtime_mappings` fields are used, other DSL fields are not considered. Threshold:: Defines a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The diff --git a/examples/guided_onboarding_example/public/components/app.tsx b/examples/guided_onboarding_example/public/components/app.tsx index dc8cbbdcfac83..a5252920c27fa 100755 --- a/examples/guided_onboarding_example/public/components/app.tsx +++ b/examples/guided_onboarding_example/public/components/app.tsx @@ -23,6 +23,7 @@ import { CoreStart, ScopedHistory } from '@kbn/core/public'; import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types'; import { StepTwo } from './step_two'; import { StepOne } from './step_one'; +import { StepThree } from './step_three'; import { Main } from './main'; interface GuidedOnboardingExampleAppDeps { @@ -60,6 +61,9 @@ export const GuidedOnboardingExampleApp = (props: GuidedOnboardingExampleAppDeps + + + diff --git a/examples/guided_onboarding_example/public/components/main.tsx b/examples/guided_onboarding_example/public/components/main.tsx index 157b13f1276c0..59e6fa3192402 100644 --- a/examples/guided_onboarding_example/public/components/main.tsx +++ b/examples/guided_onboarding_example/public/components/main.tsx @@ -25,45 +25,50 @@ import { EuiText, EuiTitle, } from '@elastic/eui'; -import { +import type { GuidedOnboardingPluginStart, - GuidedOnboardingState, - UseCase, + GuideState, + GuideStepIds, + GuideId, + GuideStep, } from '@kbn/guided-onboarding-plugin/public'; +import { guidesConfig } from '@kbn/guided-onboarding-plugin/public'; interface MainProps { guidedOnboarding: GuidedOnboardingPluginStart; notifications: CoreStart['notifications']; } + export const Main = (props: MainProps) => { const { guidedOnboarding: { guidedOnboardingApi }, notifications, } = props; const history = useHistory(); - const [guideState, setGuideState] = useState(undefined); + const [guidesState, setGuidesState] = useState(undefined); + const [activeGuide, setActiveGuide] = useState(undefined); - const [selectedGuide, setSelectedGuide] = useState< - GuidedOnboardingState['activeGuide'] | undefined - >(undefined); - const [selectedStep, setSelectedStep] = useState( - undefined - ); + const [selectedGuide, setSelectedGuide] = useState(undefined); + const [selectedStep, setSelectedStep] = useState(undefined); useEffect(() => { - const subscription = guidedOnboardingApi - ?.fetchGuideState$() - .subscribe((newState: GuidedOnboardingState) => { - setGuideState(newState); - }); - return () => subscription?.unsubscribe(); + const fetchGuidesState = async () => { + const newGuidesState = await guidedOnboardingApi?.fetchAllGuidesState(); + setGuidesState(newGuidesState ? newGuidesState.state : []); + }; + + fetchGuidesState(); }, [guidedOnboardingApi]); - const startGuide = async (guide: UseCase) => { - const response = await guidedOnboardingApi?.updateGuideState({ - activeGuide: guide, - activeStep: 'add_data', - }); + useEffect(() => { + const newActiveGuide = guidesState?.find((guide) => guide.isActive === true); + if (newActiveGuide) { + setActiveGuide(newActiveGuide); + } + }, [guidesState, setActiveGuide]); + + const activateGuide = async (guideId: GuideId, guideState?: GuideState) => { + const response = await guidedOnboardingApi?.activateGuide(guideId, guideState); if (response) { notifications.toasts.addSuccess( @@ -75,11 +80,45 @@ export const Main = (props: MainProps) => { }; const updateGuideState = async () => { - const response = await guidedOnboardingApi?.updateGuideState({ - activeGuide: selectedGuide!, - activeStep: selectedStep!, + const selectedGuideConfig = guidesConfig[selectedGuide!]; + const selectedStepIndex = selectedGuideConfig.steps.findIndex( + (step) => step.id === selectedStep! + ); + + // Noop if the selected step is invalid + if (selectedStepIndex === -1) { + return; + } + + const updatedSteps: GuideStep[] = selectedGuideConfig.steps.map((step, stepIndex) => { + if (selectedStepIndex > stepIndex) { + return { + id: step.id, + status: 'complete', + }; + } + + if (selectedStepIndex < stepIndex) { + return { + id: step.id, + status: 'inactive', + }; + } + + return { + id: step.id, + status: 'active', + }; }); + const updatedGuideState: GuideState = { + isActive: true, + status: 'in_progress', + steps: updatedSteps, + guideId: selectedGuide!, + }; + + const response = await guidedOnboardingApi?.updateGuideState(updatedGuideState, true); if (response) { notifications.toasts.addSuccess( i18n.translate('guidedOnboardingExample.updateGuideState.toastLabel', { @@ -116,7 +155,7 @@ export const Main = (props: MainProps) => { so there is no need to 'load' the state from the server." />

- {guideState ? ( + {activeGuide ? (
{ defaultMessage="Active guide" />
-
{guideState.activeGuide ?? 'undefined'}
+
{activeGuide.guideId}
-
{guideState.activeStep ?? 'undefined'}
+
+ {activeGuide.steps.map((step) => { + return ( + <> + {`Step "${step.id}": ${step.status}`}
+ + ); + })} +
- ) : undefined} + ) : ( +

+ +

+ )}

- - startGuide('search')} fill> - - - - - startGuide('observability')} fill> - - - - - startGuide('security')} fill> - - - + {(Object.keys(guidesConfig) as GuideId[]).map((guideId) => { + const guideState = guidesState?.find((guide) => guide.guideId === guideId); + return ( + + activateGuide(guideId, guideState)} + fill + disabled={guideState?.status === 'complete'} + > + {guideState === undefined && ( + + )} + {(guideState?.isActive === true || + guideState?.status === 'in_progress' || + guideState?.status === 'ready_to_complete') && ( + + )} + {guideState?.status === 'complete' && ( + + )} + + + ); + })} @@ -187,16 +259,15 @@ export const Main = (props: MainProps) => { { - const value = e.target.value as UseCase; + const value = e.target.value as GuideId; const shouldResetState = value.trim().length === 0; if (shouldResetState) { setSelectedGuide(undefined); @@ -209,10 +280,10 @@ export const Main = (props: MainProps) => { - + setSelectedStep(e.target.value)} + onChange={(e) => setSelectedStep(e.target.value as GuideStepIds)} /> diff --git a/examples/guided_onboarding_example/public/components/step_three.tsx b/examples/guided_onboarding_example/public/components/step_three.tsx new file mode 100644 index 0000000000000..ffe9d87993611 --- /dev/null +++ b/examples/guided_onboarding_example/public/components/step_three.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React, { useEffect, useState } from 'react'; + +import { EuiButton, EuiSpacer, EuiText, EuiTitle, EuiTourStep } from '@elastic/eui'; + +import { GuidedOnboardingPluginStart } from '@kbn/guided-onboarding-plugin/public/types'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EuiPageContentHeader_Deprecated as EuiPageContentHeader, + EuiPageContentBody_Deprecated as EuiPageContentBody, +} from '@elastic/eui'; + +interface StepThreeProps { + guidedOnboarding: GuidedOnboardingPluginStart; +} + +export const StepThree = (props: StepThreeProps) => { + const { + guidedOnboarding: { guidedOnboardingApi }, + } = props; + + const [isTourStepOpen, setIsTourStepOpen] = useState(false); + + useEffect(() => { + const subscription = guidedOnboardingApi + ?.isGuideStepActive$('search', 'search_experience') + .subscribe((isStepActive) => { + setIsTourStepOpen(isStepActive); + }); + return () => subscription?.unsubscribe(); + }, [guidedOnboardingApi]); + + return ( + <> + + +

+ +

+
+
+ + +

+ +

+
+ + +

Click this button to complete step 3.

+ + } + isStepOpen={isTourStepOpen} + minWidth={300} + onFinish={() => { + setIsTourStepOpen(false); + }} + step={1} + stepsTotal={1} + title="Step Build search experience" + anchorPosition="rightUp" + > + { + await guidedOnboardingApi?.completeGuideStep('search', 'search_experience'); + }} + > + Complete step 3 + +
+
+ + ); +}; diff --git a/examples/guided_onboarding_example/public/components/step_two.tsx b/examples/guided_onboarding_example/public/components/step_two.tsx index a79ce2329351e..07f4fd7e63e0c 100644 --- a/examples/guided_onboarding_example/public/components/step_two.tsx +++ b/examples/guided_onboarding_example/public/components/step_two.tsx @@ -55,7 +55,7 @@ export const StepTwo = (props: StepTwoProps) => {

@@ -73,7 +73,7 @@ export const StepTwo = (props: StepTwoProps) => { }} step={1} stepsTotal={1} - title="Step Search experience" + title="Step Browse documents" anchorPosition="rightUp" > { const agentFactory = agentManager.getAgentFactory(); const agent = agentFactory({ url: new URL('http://elastic-node-1:9200') }); // eslint-disable-next-line dot-notation - expect(agentManager['httpStore'].has(agent)).toEqual(true); + expect(agentManager['agents'].has(agent)).toEqual(true); agent.destroy(); // eslint-disable-next-line dot-notation - expect(agentManager['httpStore'].has(agent)).toEqual(false); + expect(agentManager['agents'].has(agent)).toEqual(false); }); }); @@ -122,4 +122,21 @@ describe('AgentManager', () => { }); }); }); + + describe('#getAgents()', () => { + it('returns the created HTTP and HTTPs Agent instances', () => { + const agentManager = new AgentManager(); + const agentFactory1 = agentManager.getAgentFactory(); + const agentFactory2 = agentManager.getAgentFactory(); + const agent1 = agentFactory1({ url: new URL('http://elastic-node-1:9200') }); + const agent2 = agentFactory2({ url: new URL('http://elastic-node-1:9200') }); + const agent3 = agentFactory1({ url: new URL('https://elastic-node-1:9200') }); + const agent4 = agentFactory2({ url: new URL('https://elastic-node-1:9200') }); + + const agents = agentManager.getAgents(); + + expect(agents.size).toEqual(4); + expect([...agents]).toEqual(expect.arrayContaining([agent1, agent2, agent3, agent4])); + }); + }); }); diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/agent_manager.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/agent_manager.ts index eb68014561d77..9a57cc44e04ad 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/agent_manager.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/agent_manager.ts @@ -8,7 +8,7 @@ import { Agent as HttpAgent } from 'http'; import { Agent as HttpsAgent } from 'https'; -import { ConnectionOptions, HttpAgentOptions } from '@elastic/elasticsearch'; +import type { ConnectionOptions, HttpAgentOptions } from '@elastic/elasticsearch'; const HTTPS = 'https:'; const DEFAULT_CONFIG: HttpAgentOptions = { @@ -22,6 +22,14 @@ const DEFAULT_CONFIG: HttpAgentOptions = { export type NetworkAgent = HttpAgent | HttpsAgent; export type AgentFactory = (connectionOpts: ConnectionOptions) => NetworkAgent; +export interface AgentFactoryProvider { + getAgentFactory(agentOptions?: HttpAgentOptions): AgentFactory; +} + +export interface AgentStore { + getAgents(): Set; +} + /** * Allows obtaining Agent factories, which can then be fed into elasticsearch-js's Client class. * Ideally, we should obtain one Agent factory for each ES Client class. @@ -33,15 +41,11 @@ export type AgentFactory = (connectionOpts: ConnectionOptions) => NetworkAgent; * exposes methods that can modify the underlying pools, effectively impacting the connections of other Clients. * @internal **/ -export class AgentManager { - // Stores Https Agent instances - private httpsStore: Set; - // Stores Http Agent instances - private httpStore: Set; +export class AgentManager implements AgentFactoryProvider, AgentStore { + private agents: Set; constructor(private agentOptions: HttpAgentOptions = DEFAULT_CONFIG) { - this.httpsStore = new Set(); - this.httpStore = new Set(); + this.agents = new Set(); } public getAgentFactory(agentOptions?: HttpAgentOptions): AgentFactory { @@ -61,8 +65,8 @@ export class AgentManager { connectionOpts.tls ); httpsAgent = new HttpsAgent(config); - this.httpsStore.add(httpsAgent); - dereferenceOnDestroy(this.httpsStore, httpsAgent); + this.agents.add(httpsAgent); + dereferenceOnDestroy(this.agents, httpsAgent); } return httpsAgent; @@ -71,19 +75,23 @@ export class AgentManager { if (!httpAgent) { const config = Object.assign({}, DEFAULT_CONFIG, this.agentOptions, agentOptions); httpAgent = new HttpAgent(config); - this.httpStore.add(httpAgent); - dereferenceOnDestroy(this.httpStore, httpAgent); + this.agents.add(httpAgent); + dereferenceOnDestroy(this.agents, httpAgent); } return httpAgent; }; } + + public getAgents(): Set { + return this.agents; + } } -const dereferenceOnDestroy = (protocolStore: Set, agent: NetworkAgent) => { +const dereferenceOnDestroy = (store: Set, agent: NetworkAgent) => { const doDestroy = agent.destroy.bind(agent); agent.destroy = () => { - protocolStore.delete(agent); + store.delete(agent); doDestroy(); }; }; diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts index e5be9fc0ab718..f371e3425b0c7 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts @@ -46,7 +46,7 @@ describe('ClusterClient', () => { let authHeaders: ReturnType; let internalClient: jest.Mocked; let scopedClient: jest.Mocked; - let agentManager: AgentManager; + let agentFactoryProvider: AgentManager; const mockTransport = { mockTransport: true }; @@ -54,7 +54,7 @@ describe('ClusterClient', () => { logger = loggingSystemMock.createLogger(); internalClient = createClient(); scopedClient = createClient(); - agentManager = new AgentManager(); + agentFactoryProvider = new AgentManager(); authHeaders = httpServiceMock.createAuthHeaderStorage(); authHeaders.get.mockImplementation(() => ({ @@ -84,21 +84,21 @@ describe('ClusterClient', () => { authHeaders, type: 'custom-type', getExecutionContext: getExecutionContextMock, - agentManager, + agentFactoryProvider, kibanaVersion, }); expect(configureClientMock).toHaveBeenCalledTimes(2); expect(configureClientMock).toHaveBeenCalledWith(config, { logger, - agentManager, + agentFactoryProvider, kibanaVersion, type: 'custom-type', getExecutionContext: getExecutionContextMock, }); expect(configureClientMock).toHaveBeenCalledWith(config, { logger, - agentManager, + agentFactoryProvider, kibanaVersion, type: 'custom-type', getExecutionContext: getExecutionContextMock, @@ -113,7 +113,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -128,7 +128,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest(); @@ -155,7 +155,7 @@ describe('ClusterClient', () => { authHeaders, getExecutionContext, getUnauthorizedErrorHandler, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest(); @@ -179,7 +179,7 @@ describe('ClusterClient', () => { authHeaders, getExecutionContext, getUnauthorizedErrorHandler, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest(); @@ -212,7 +212,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest(); @@ -237,7 +237,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({ @@ -271,7 +271,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({}); @@ -305,7 +305,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({ @@ -344,7 +344,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({}); @@ -373,7 +373,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({ @@ -410,7 +410,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({}); @@ -445,7 +445,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({ @@ -482,7 +482,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest(); @@ -513,7 +513,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({ @@ -547,7 +547,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = httpServerMock.createKibanaRequest({ @@ -579,7 +579,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = { @@ -612,7 +612,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); const request = { @@ -640,7 +640,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -658,7 +658,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -703,7 +703,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -720,7 +720,7 @@ describe('ClusterClient', () => { logger, type: 'custom-type', authHeaders, - agentManager, + agentFactoryProvider, kibanaVersion, }); diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts index f243c98ecf798..2a2f6ef1334a2 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts @@ -24,9 +24,12 @@ import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server'; import { configureClient } from './configure_client'; import { ScopedClusterClient } from './scoped_cluster_client'; import { getDefaultHeaders } from './headers'; -import { createInternalErrorHandler, InternalUnauthorizedErrorHandler } from './retry_unauthorized'; +import { + createInternalErrorHandler, + type InternalUnauthorizedErrorHandler, +} from './retry_unauthorized'; import { createTransport } from './create_transport'; -import { AgentManager } from './agent_manager'; +import type { AgentFactoryProvider } from './agent_manager'; const noop = () => undefined; @@ -49,7 +52,7 @@ export class ClusterClient implements ICustomClusterClient { authHeaders, getExecutionContext = noop, getUnauthorizedErrorHandler = noop, - agentManager, + agentFactoryProvider, kibanaVersion, }: { config: ElasticsearchClientConfig; @@ -58,7 +61,7 @@ export class ClusterClient implements ICustomClusterClient { authHeaders?: IAuthHeadersStorage; getExecutionContext?: () => string | undefined; getUnauthorizedErrorHandler?: () => UnauthorizedErrorHandler | undefined; - agentManager: AgentManager; + agentFactoryProvider: AgentFactoryProvider; kibanaVersion: string; }) { this.config = config; @@ -71,7 +74,7 @@ export class ClusterClient implements ICustomClusterClient { logger, type, getExecutionContext, - agentManager, + agentFactoryProvider, kibanaVersion, }); this.rootScopedClient = configureClient(config, { @@ -79,7 +82,7 @@ export class ClusterClient implements ICustomClusterClient { type, getExecutionContext, scoped: true, - agentManager, + agentFactoryProvider, kibanaVersion, }); } diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.test.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.test.ts index 40824d306ac48..fe511f46278d9 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.test.ts @@ -10,7 +10,6 @@ jest.mock('./log_query_and_deprecation', () => ({ __esModule: true, instrumentEsQueryAndDeprecationLogger: jest.fn(), })); -jest.mock('./agent_manager'); import { Agent } from 'http'; import { @@ -24,9 +23,8 @@ import { ClusterConnectionPool } from '@elastic/elasticsearch'; import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server'; import { configureClient } from './configure_client'; import { instrumentEsQueryAndDeprecationLogger } from './log_query_and_deprecation'; -import { AgentManager } from './agent_manager'; +import { type AgentFactoryProvider, AgentManager } from './agent_manager'; -const AgentManagerMock = AgentManager as jest.Mock; const kibanaVersion = '1.0.0'; const createFakeConfig = ( @@ -46,31 +44,17 @@ const createFakeClient = () => { return client; }; -const createFakeAgentFactory = (logger: MockedLogger) => { - const agentFactory = () => new Agent(); - - AgentManagerMock.mockImplementationOnce(() => { - const agentManager = new AgentManager(); - agentManager.getAgentFactory = () => agentFactory; - return agentManager; - }); - - const agentManager = new AgentManager(); - - return { agentManager, agentFactory }; -}; - describe('configureClient', () => { let logger: MockedLogger; let config: ElasticsearchClientConfig; - let agentManager: AgentManager; + let agentFactoryProvider: AgentFactoryProvider; beforeEach(() => { logger = loggingSystemMock.createLogger(); config = createFakeConfig(); parseClientOptionsMock.mockReturnValue({}); ClientMock.mockImplementation(() => createFakeClient()); - agentManager = new AgentManager(); + agentFactoryProvider = new AgentManager(); }); afterEach(() => { @@ -80,14 +64,26 @@ describe('configureClient', () => { }); it('calls `parseClientOptions` with the correct parameters', () => { - configureClient(config, { logger, type: 'test', scoped: false, agentManager, kibanaVersion }); + configureClient(config, { + logger, + type: 'test', + scoped: false, + agentFactoryProvider, + kibanaVersion, + }); expect(parseClientOptionsMock).toHaveBeenCalledTimes(1); expect(parseClientOptionsMock).toHaveBeenCalledWith(config, false, kibanaVersion); parseClientOptionsMock.mockClear(); - configureClient(config, { logger, type: 'test', scoped: true, agentManager, kibanaVersion }); + configureClient(config, { + logger, + type: 'test', + scoped: true, + agentFactoryProvider, + kibanaVersion, + }); expect(parseClientOptionsMock).toHaveBeenCalledTimes(1); expect(parseClientOptionsMock).toHaveBeenCalledWith(config, true, kibanaVersion); @@ -103,7 +99,7 @@ describe('configureClient', () => { logger, type: 'test', scoped: false, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -112,13 +108,17 @@ describe('configureClient', () => { expect(client).toBe(ClientMock.mock.results[0].value); }); - it('constructs a client using the provided `agentManager`', () => { - const { agentManager: customAgentManager, agentFactory } = createFakeAgentFactory(logger); + it('constructs a client using the provided `agentFactoryProvider`', () => { + const agentFactory = () => new Agent(); + const customAgentFactoryProvider = { + getAgentFactory: () => agentFactory, + }; + const client = configureClient(config, { logger, type: 'test', scoped: false, - agentManager: customAgentManager, + agentFactoryProvider: customAgentFactoryProvider, kibanaVersion, }); @@ -134,7 +134,7 @@ describe('configureClient', () => { type: 'test', scoped: false, getExecutionContext, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -148,7 +148,7 @@ describe('configureClient', () => { type: 'test', scoped: true, getExecutionContext, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -164,7 +164,7 @@ describe('configureClient', () => { logger, type: 'test', scoped: false, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -185,7 +185,7 @@ describe('configureClient', () => { logger, type: 'test', scoped: false, - agentManager, + agentFactoryProvider, kibanaVersion, }); @@ -203,7 +203,7 @@ describe('configureClient', () => { logger, type: 'test', scoped: false, - agentManager, + agentFactoryProvider, kibanaVersion, }); diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.ts index e1c8048c6a89e..2fd7a4d4a74bb 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/configure_client.ts @@ -12,7 +12,7 @@ import type { ElasticsearchClientConfig } from '@kbn/core-elasticsearch-server'; import { parseClientOptions } from './client_config'; import { instrumentEsQueryAndDeprecationLogger } from './log_query_and_deprecation'; import { createTransport } from './create_transport'; -import { AgentManager } from './agent_manager'; +import type { AgentFactoryProvider } from './agent_manager'; const noop = () => undefined; @@ -23,14 +23,14 @@ export const configureClient = ( type, scoped = false, getExecutionContext = noop, - agentManager, + agentFactoryProvider, kibanaVersion, }: { logger: Logger; type: string; scoped?: boolean; getExecutionContext?: () => string | undefined; - agentManager: AgentManager; + agentFactoryProvider: AgentFactoryProvider; kibanaVersion: string; } ): Client => { @@ -38,7 +38,7 @@ export const configureClient = ( const KibanaTransport = createTransport({ getExecutionContext }); const client = new Client({ ...clientOptions, - agent: agentManager.getAgentFactory(clientOptions.agent), + agent: agentFactoryProvider.getAgentFactory(clientOptions.agent), Transport: KibanaTransport, Connection: HttpConnection, // using ClusterConnectionPool until https://github.com/elastic/elasticsearch-js/issues/1714 is addressed diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/index.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/index.ts index c46381d57a7b6..0b66d449df013 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/index.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/index.ts @@ -15,3 +15,4 @@ export type { DeeplyMockedApi, ElasticsearchClientMock, } from './src/mocks'; +export { createAgentStoreMock } from './src/agent_manager.mocks'; diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/src/agent_manager.mocks.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/src/agent_manager.mocks.ts new file mode 100644 index 0000000000000..2fd8812b3aae0 --- /dev/null +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-mocks/src/agent_manager.mocks.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 type { AgentStore, NetworkAgent } from '@kbn/core-elasticsearch-client-server-internal'; + +export const createAgentStoreMock = (agents: Set = new Set()): AgentStore => ({ + getAgents: jest.fn(() => agents), +}); diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.mocks.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.mocks.ts index cd6d36f0cb111..68a56ff28bc8d 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.mocks.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.mocks.ts @@ -6,8 +6,14 @@ * Side Public License, v 1. */ +import type { AgentManager } from '@kbn/core-elasticsearch-client-server-internal'; + export const MockClusterClient = jest.fn(); -export const MockAgentManager = jest.fn(); +export const MockAgentManager: jest.MockedClass = jest.fn().mockReturnValue({ + getAgents: jest.fn(), + getAgentFactory: jest.fn(), +}); + jest.mock('@kbn/core-elasticsearch-client-server-internal', () => ({ ClusterClient: MockClusterClient, AgentManager: MockAgentManager, diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.ts index 5b54a2c35683e..ecd364b4283cf 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.test.ts @@ -135,7 +135,7 @@ describe('#preboot', () => { ); }); - it('creates a ClusterClient using the internal AgentManager', async () => { + it('creates a ClusterClient using the internal AgentManager as AgentFactoryProvider ', async () => { const prebootContract = await elasticsearchService.preboot(); const customConfig = { keepAlive: true }; const clusterClient = prebootContract.createClient('custom-type', customConfig); @@ -145,7 +145,7 @@ describe('#preboot', () => { expect(MockClusterClient).toHaveBeenCalledTimes(1); expect(MockClusterClient.mock.calls[0][0]).toEqual( // eslint-disable-next-line dot-notation - expect.objectContaining({ agentManager: elasticsearchService['agentManager'] }) + expect.objectContaining({ agentFactoryProvider: elasticsearchService['agentManager'] }) ); }); @@ -201,6 +201,11 @@ describe('#setup', () => { ); }); + it('returns an AgentStore as part of the contract', async () => { + const setupContract = await elasticsearchService.setup(setupDeps); + expect(typeof setupContract.agentStore.getAgents).toEqual('function'); + }); + it('esNodeVersionCompatibility$ only starts polling when subscribed to', async () => { const mockedClient = mockClusterClientInstance.asInternalUser; mockedClient.nodes.info.mockImplementation(() => diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.ts index f345732c7a7c4..fddff84293140 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/elasticsearch_service.ts @@ -120,6 +120,7 @@ export class ElasticsearchService } this.unauthorizedErrorHandler = handler; }, + agentStore: this.agentManager, }; } @@ -182,7 +183,7 @@ export class ElasticsearchService authHeaders: this.authHeaders, getExecutionContext: () => this.executionContextClient?.getAsHeader(), getUnauthorizedErrorHandler: () => this.unauthorizedErrorHandler, - agentManager: this.agentManager, + agentFactoryProvider: this.agentManager, kibanaVersion: this.kibanaVersion, }); } diff --git a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/types.ts b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/types.ts index 8d05ad0c4cd0a..b03b86c7bdd1c 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-internal/src/types.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-internal/src/types.ts @@ -12,6 +12,7 @@ import type { ElasticsearchServiceStart, ElasticsearchServiceSetup, } from '@kbn/core-elasticsearch-server'; +import type { AgentStore } from '@kbn/core-elasticsearch-client-server-internal'; import type { ServiceStatus } from '@kbn/core-status-common'; import type { NodesVersionCompatibility, NodeInfo } from './version_check/ensure_es_version'; import type { ClusterInfo } from './get_cluster_info'; @@ -21,6 +22,7 @@ export type InternalElasticsearchServicePreboot = ElasticsearchServicePreboot; /** @internal */ export interface InternalElasticsearchServiceSetup extends ElasticsearchServiceSetup { + agentStore: AgentStore; clusterInfo$: Observable; esNodesCompatibility$: Observable; status$: Observable>; diff --git a/packages/core/elasticsearch/core-elasticsearch-server-mocks/src/elasticsearch_service.mock.ts b/packages/core/elasticsearch/core-elasticsearch-server-mocks/src/elasticsearch_service.mock.ts index a1323be0ea71b..26d81da24318c 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server-mocks/src/elasticsearch_service.mock.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server-mocks/src/elasticsearch_service.mock.ts @@ -13,6 +13,7 @@ import { elasticsearchClientMock, type ClusterClientMock, type CustomClusterClientMock, + createAgentStoreMock, } from '@kbn/core-elasticsearch-client-server-mocks'; import type { ElasticsearchClientConfig, @@ -94,6 +95,7 @@ const createInternalSetupContractMock = () => { level: ServiceStatusLevels.available, summary: 'Elasticsearch is available', }), + agentStore: createAgentStoreMock(), }; return internalSetupContract; }; diff --git a/packages/core/elasticsearch/core-elasticsearch-server/src/client/cluster_client.ts b/packages/core/elasticsearch/core-elasticsearch-server/src/client/cluster_client.ts index 57eadf70ef68a..a8e065d357ee1 100644 --- a/packages/core/elasticsearch/core-elasticsearch-server/src/client/cluster_client.ts +++ b/packages/core/elasticsearch/core-elasticsearch-server/src/client/cluster_client.ts @@ -7,8 +7,8 @@ */ import type { ElasticsearchClient } from './client'; -import { ScopeableRequest } from './scopeable_request'; -import { IScopedClusterClient } from './scoped_cluster_client'; +import type { ScopeableRequest } from './scopeable_request'; +import type { IScopedClusterClient } from './scoped_cluster_client'; /** * Represents an Elasticsearch cluster API client created by the platform. diff --git a/packages/core/http/core-http-resources-server-internal/BUILD.bazel b/packages/core/http/core-http-resources-server-internal/BUILD.bazel new file mode 100644 index 0000000000000..8c286485efafb --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/BUILD.bazel @@ -0,0 +1,115 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-http-resources-server-internal" +PKG_REQUIRE_NAME = "@kbn/core-http-resources-server-internal" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//elastic-apm-node", + "//packages/kbn-logging", + "//packages/kbn-apm-config-loader", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//elastic-apm-node", + "//packages/kbn-apm-config-loader:npm_module_types", + "//packages/kbn-logging:npm_module_types", + "//packages/core/http/core-http-server:npm_module_types", + "//packages/core/http/core-http-resources-server:npm_module_types", + "//packages/core/rendering/core-rendering-server-internal:npm_module_types", + "//packages/core/http/core-http-request-handler-context-server:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/http/core-http-resources-server-internal/README.md b/packages/core/http/core-http-resources-server-internal/README.md new file mode 100644 index 0000000000000..e1fa72ba6a294 --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/README.md @@ -0,0 +1,3 @@ +# @kbn/core-http-resources-server-internal + +This package contains the internal types and implementation for Core's internal `http` resources service. diff --git a/packages/core/http/core-http-resources-server-internal/index.ts b/packages/core/http/core-http-resources-server-internal/index.ts new file mode 100644 index 0000000000000..270425ba81f27 --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { HttpResourcesService } from './src'; + +export type { InternalHttpResourcesPreboot, InternalHttpResourcesSetup } from './src'; diff --git a/packages/core/http/core-http-resources-server-internal/jest.config.js b/packages/core/http/core-http-resources-server-internal/jest.config.js new file mode 100644 index 0000000000000..2b328b864899a --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/http/core-http-resources-server-internal'], +}; diff --git a/packages/core/http/core-http-resources-server-internal/kibana.jsonc b/packages/core/http/core-http-resources-server-internal/kibana.jsonc new file mode 100644 index 0000000000000..bea96a4a60844 --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-http-resources-server-internal", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/http/core-http-resources-server-internal/package.json b/packages/core/http/core-http-resources-server-internal/package.json new file mode 100644 index 0000000000000..71e4a44a35504 --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/core-http-resources-server-internal", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/http_resources/get_apm_config.test.mocks.ts b/packages/core/http/core-http-resources-server-internal/src/get_apm_config.test.mocks.ts similarity index 100% rename from src/core/server/http_resources/get_apm_config.test.mocks.ts rename to packages/core/http/core-http-resources-server-internal/src/get_apm_config.test.mocks.ts diff --git a/src/core/server/http_resources/get_apm_config.test.ts b/packages/core/http/core-http-resources-server-internal/src/get_apm_config.test.ts similarity index 100% rename from src/core/server/http_resources/get_apm_config.test.ts rename to packages/core/http/core-http-resources-server-internal/src/get_apm_config.test.ts diff --git a/src/core/server/http_resources/get_apm_config.ts b/packages/core/http/core-http-resources-server-internal/src/get_apm_config.ts similarity index 100% rename from src/core/server/http_resources/get_apm_config.ts rename to packages/core/http/core-http-resources-server-internal/src/get_apm_config.ts diff --git a/src/core/server/http_resources/http_resources_service.test.mocks.ts b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.mocks.ts similarity index 100% rename from src/core/server/http_resources/http_resources_service.test.mocks.ts rename to packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.mocks.ts diff --git a/src/core/server/http_resources/http_resources_service.test.ts b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts similarity index 91% rename from src/core/server/http_resources/http_resources_service.test.ts rename to packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts index ea04f30847508..9bf0de0eca829 100644 --- a/src/core/server/http_resources/http_resources_service.test.ts +++ b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.test.ts @@ -12,11 +12,13 @@ import type { RouteConfig } from '@kbn/core-http-server'; import { mockCoreContext } from '@kbn/core-base-server-mocks'; import { httpServiceMock, httpServerMock } from '@kbn/core-http-server-mocks'; -import { coreMock } from '../mocks'; import { renderingServiceMock } from '@kbn/core-rendering-server-mocks'; import { HttpResourcesService, PrebootDeps, SetupDeps } from './http_resources_service'; -import { httpResourcesMock } from './http_resources_service.mock'; -import { HttpResources } from '..'; +import type { HttpResources } from '@kbn/core-http-resources-server'; +import { + createCoreRequestHandlerContextMock, + createHttpResourcesResponseFactory, +} from './test_helpers/http_resources_service_test_mocks'; const coreContext = mockCoreContext.create(); @@ -26,7 +28,7 @@ describe('HttpResources service', () => { let setupDeps: SetupDeps; let router: ReturnType; const kibanaRequest = httpServerMock.createKibanaRequest(); - const context = coreMock.createCustomRequestHandlerContext({}); + const context = createCoreRequestHandlerContextMock(); const apmConfig = { mockApmConfig: true }; beforeEach(() => { @@ -66,7 +68,7 @@ describe('HttpResources service', () => { }); const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(getDeps().rendering.render).toHaveBeenCalledWith( kibanaRequest, @@ -92,7 +94,7 @@ describe('HttpResources service', () => { const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(responseFactory.ok).toHaveBeenCalledWith({ @@ -112,7 +114,7 @@ describe('HttpResources service', () => { }); const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(getDeps().rendering.render).toHaveBeenCalledWith( kibanaRequest, @@ -138,7 +140,7 @@ describe('HttpResources service', () => { const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(responseFactory.ok).toHaveBeenCalledWith({ @@ -159,7 +161,7 @@ describe('HttpResources service', () => { }); const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(responseFactory.ok).toHaveBeenCalledWith({ body: htmlBody, @@ -186,7 +188,7 @@ describe('HttpResources service', () => { const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(responseFactory.ok).toHaveBeenCalledWith({ @@ -208,7 +210,7 @@ describe('HttpResources service', () => { }); const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(responseFactory.ok).toHaveBeenCalledWith({ body: jsBody, @@ -235,7 +237,7 @@ describe('HttpResources service', () => { const [[, routeHandler]] = router.get.mock.calls; - const responseFactory = httpResourcesMock.createResponseFactory(); + const responseFactory = createHttpResourcesResponseFactory(); await routeHandler(context, kibanaRequest, responseFactory); expect(responseFactory.ok).toHaveBeenCalledWith({ diff --git a/src/core/server/http_resources/http_resources_service.ts b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts similarity index 96% rename from src/core/server/http_resources/http_resources_service.ts rename to packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts index 7cc88699ea7ba..1032611748d36 100644 --- a/src/core/server/http_resources/http_resources_service.ts +++ b/packages/core/http/core-http-resources-server-internal/src/http_resources_service.ts @@ -23,21 +23,29 @@ import type { InternalRenderingServiceSetup, } from '@kbn/core-rendering-server-internal'; import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; -import { - InternalHttpResourcesSetup, +import type { HttpResources, HttpResourcesResponseOptions, HttpResourcesRenderOptions, HttpResourcesRequestHandler, HttpResourcesServiceToolkit, -} from './types'; +} from '@kbn/core-http-resources-server'; + +import type { InternalHttpResourcesSetup } from './types'; + import { getApmConfig } from './get_apm_config'; +/** + * @internal + */ export interface PrebootDeps { http: InternalHttpServicePreboot; rendering: InternalRenderingServicePreboot; } +/** + * @internal + */ export interface SetupDeps { http: InternalHttpServiceSetup; rendering: InternalRenderingServiceSetup; diff --git a/packages/core/http/core-http-resources-server-internal/src/index.ts b/packages/core/http/core-http-resources-server-internal/src/index.ts new file mode 100644 index 0000000000000..b4c1502a92cab --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/src/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { HttpResourcesService } from './http_resources_service'; + +export type { InternalHttpResourcesPreboot, InternalHttpResourcesSetup } from './types'; diff --git a/packages/core/http/core-http-resources-server-internal/src/test_helpers/http_resources_service_test_mocks.ts b/packages/core/http/core-http-resources-server-internal/src/test_helpers/http_resources_service_test_mocks.ts new file mode 100644 index 0000000000000..c9c0251355012 --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/src/test_helpers/http_resources_service_test_mocks.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { HttpResourcesServiceToolkit } from '@kbn/core-http-resources-server'; +import { httpServerMock } from '@kbn/core-http-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; + +// partial duplicate of coreMock +export function createCoreRequestHandlerContextMock() { + return { + core: { + uiSettings: { client: uiSettingsServiceMock.createClient() }, + }, + }; +} + +// duplicate of public mock for internal testing only +export function createHttpResourcesResponseFactory() { + const mocked: jest.Mocked = { + renderCoreApp: jest.fn(), + renderAnonymousCoreApp: jest.fn(), + renderHtml: jest.fn(), + renderJs: jest.fn(), + }; + + return { + ...httpServerMock.createResponseFactory(), + ...mocked, + }; +} diff --git a/packages/core/http/core-http-resources-server-internal/src/types.ts b/packages/core/http/core-http-resources-server-internal/src/types.ts new file mode 100644 index 0000000000000..f68520a6387bb --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/src/types.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { IRouter } from '@kbn/core-http-server'; +import type { HttpResources } from '@kbn/core-http-resources-server'; + +/** + * Allows to configure HTTP response parameters + * @internal + */ +export interface InternalHttpResourcesPreboot { + createRegistrar(router: IRouter): HttpResources; +} + +/** + * Allows to configure HTTP response parameters + * @internal + */ +export type InternalHttpResourcesSetup = InternalHttpResourcesPreboot; diff --git a/packages/core/http/core-http-resources-server-internal/tsconfig.json b/packages/core/http/core-http-resources-server-internal/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/http/core-http-resources-server-internal/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/http/core-http-resources-server-mocks/BUILD.bazel b/packages/core/http/core-http-resources-server-mocks/BUILD.bazel new file mode 100644 index 0000000000000..81eefd0db2ee2 --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/BUILD.bazel @@ -0,0 +1,110 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-http-resources-server-mocks" +PKG_REQUIRE_NAME = "@kbn/core-http-resources-server-mocks" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "//packages/core/http/core-http-server-mocks", + "//packages/core/http/core-http-resources-server-internal", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/kbn-utility-types:npm_module_types", + "//packages/core/http/core-http-server-mocks:npm_module_types", + "//packages/core/http/core-http-resources-server:npm_module_types", + "//packages/core/http/core-http-resources-server-internal:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/http/core-http-resources-server-mocks/README.md b/packages/core/http/core-http-resources-server-mocks/README.md new file mode 100644 index 0000000000000..6d9bd3de0dad2 --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/README.md @@ -0,0 +1,3 @@ +# @kbn/core-http-resources-server-mocks + +This package contains the mocks for Core's internal `http` resources service. diff --git a/packages/core/http/core-http-resources-server-mocks/index.ts b/packages/core/http/core-http-resources-server-mocks/index.ts new file mode 100644 index 0000000000000..9b848c2bd32a1 --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { httpResourcesMock } from './src/http_resources_server.mock'; +export type { HttpResourcesMock } from './src/http_resources_server.mock'; diff --git a/packages/core/http/core-http-resources-server-mocks/jest.config.js b/packages/core/http/core-http-resources-server-mocks/jest.config.js new file mode 100644 index 0000000000000..7241454e43f5a --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/http/core-http-resources-server-mocks'], +}; diff --git a/packages/core/http/core-http-resources-server-mocks/kibana.jsonc b/packages/core/http/core-http-resources-server-mocks/kibana.jsonc new file mode 100644 index 0000000000000..e8703bdd42aa3 --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-http-resources-server-mocks", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/http/core-http-resources-server-mocks/package.json b/packages/core/http/core-http-resources-server-mocks/package.json new file mode 100644 index 0000000000000..47247cd2abaf5 --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-http-resources-server-mocks", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/http_resources/http_resources_service.mock.ts b/packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts similarity index 65% rename from src/core/server/http_resources/http_resources_service.mock.ts rename to packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts index 6c50d720ceab2..aec435e650893 100644 --- a/src/core/server/http_resources/http_resources_service.mock.ts +++ b/packages/core/http/core-http-resources-server-mocks/src/http_resources_server.mock.ts @@ -7,7 +7,25 @@ */ import { httpServerMock } from '@kbn/core-http-server-mocks'; -import { HttpResources, HttpResourcesServiceToolkit } from './types'; +import type { PublicMethodsOf } from '@kbn/utility-types'; +import { HttpResourcesService } from '@kbn/core-http-resources-server-internal'; +import type { HttpResources, HttpResourcesServiceToolkit } from '@kbn/core-http-resources-server'; + +export type HttpResourcesMock = jest.Mocked>; + +function createHttpResourcesService() { + const mock: HttpResourcesMock = { + preboot: jest.fn(), + setup: jest.fn(), + start: jest.fn(), + stop: jest.fn(), + }; + + mock.preboot.mockReturnValue(createInternalHttpResourcesPreboot()); + mock.setup.mockReturnValue(createInternalHttpResourcesSetup()); + + return mock; +} const createHttpResourcesMock = (): jest.Mocked => ({ register: jest.fn(), @@ -38,6 +56,7 @@ function createHttpResourcesResponseFactory() { } export const httpResourcesMock = { + create: createHttpResourcesService, createRegistrar: createHttpResourcesMock, createPrebootContract: createInternalHttpResourcesPreboot, createSetupContract: createInternalHttpResourcesSetup, diff --git a/packages/core/http/core-http-resources-server-mocks/tsconfig.json b/packages/core/http/core-http-resources-server-mocks/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/http/core-http-resources-server-mocks/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/http/core-http-resources-server/BUILD.bazel b/packages/core/http/core-http-resources-server/BUILD.bazel new file mode 100644 index 0000000000000..16583b6801b4a --- /dev/null +++ b/packages/core/http/core-http-resources-server/BUILD.bazel @@ -0,0 +1,107 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-http-resources-server" +PKG_REQUIRE_NAME = "@kbn/core-http-resources-server" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "//packages/core/http/core-http-server:npm_module_types", + "//packages/core/http/core-http-request-handler-context-server:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/http/core-http-resources-server/README.md b/packages/core/http/core-http-resources-server/README.md new file mode 100644 index 0000000000000..a2f4321f19214 --- /dev/null +++ b/packages/core/http/core-http-resources-server/README.md @@ -0,0 +1,3 @@ +# @kbn/core-http-resources-server + +This package contains the public types for Core's HTTP resources service. diff --git a/packages/core/http/core-http-resources-server/index.ts b/packages/core/http/core-http-resources-server/index.ts new file mode 100644 index 0000000000000..c4dbd3842b2ee --- /dev/null +++ b/packages/core/http/core-http-resources-server/index.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { + HttpResourcesRenderOptions, + HttpResourcesResponseOptions, + HttpResourcesServiceToolkit, + HttpResourcesRequestHandler, + HttpResources, +} from './src'; diff --git a/packages/core/http/core-http-resources-server/jest.config.js b/packages/core/http/core-http-resources-server/jest.config.js new file mode 100644 index 0000000000000..bfa504fb873d5 --- /dev/null +++ b/packages/core/http/core-http-resources-server/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/http/core-http-resources-server'], +}; diff --git a/packages/core/http/core-http-resources-server/kibana.jsonc b/packages/core/http/core-http-resources-server/kibana.jsonc new file mode 100644 index 0000000000000..a05c1223a7817 --- /dev/null +++ b/packages/core/http/core-http-resources-server/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-http-resources-server", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/http/core-http-resources-server/package.json b/packages/core/http/core-http-resources-server/package.json new file mode 100644 index 0000000000000..156bc4c8948b4 --- /dev/null +++ b/packages/core/http/core-http-resources-server/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/core-http-resources-server", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/src/core/server/http_resources/index.ts b/packages/core/http/core-http-resources-server/src/index.ts similarity index 80% rename from src/core/server/http_resources/index.ts rename to packages/core/http/core-http-resources-server/src/index.ts index 9148c08a922e9..8fbe0e3c1a5e2 100644 --- a/src/core/server/http_resources/index.ts +++ b/packages/core/http/core-http-resources-server/src/index.ts @@ -6,14 +6,10 @@ * Side Public License, v 1. */ -export { HttpResourcesService } from './http_resources_service'; - export type { HttpResourcesRenderOptions, HttpResourcesResponseOptions, HttpResourcesServiceToolkit, HttpResourcesRequestHandler, HttpResources, - InternalHttpResourcesPreboot, - InternalHttpResourcesSetup, } from './types'; diff --git a/src/core/server/http_resources/types.ts b/packages/core/http/core-http-resources-server/src/types.ts similarity index 91% rename from src/core/server/http_resources/types.ts rename to packages/core/http/core-http-resources-server/src/types.ts index 246a7394c3ade..6d2e6728e28f6 100644 --- a/src/core/server/http_resources/types.ts +++ b/packages/core/http/core-http-resources-server/src/types.ts @@ -7,7 +7,6 @@ */ import type { - IRouter, RouteConfig, IKibanaResponse, ResponseHeaders, @@ -85,20 +84,6 @@ export type HttpResourcesRequestHandler< Context extends RequestHandlerContext = RequestHandlerContext > = RequestHandler; -/** - * Allows to configure HTTP response parameters - * @internal - */ -export interface InternalHttpResourcesPreboot { - createRegistrar(router: IRouter): HttpResources; -} - -/** - * Allows to configure HTTP response parameters - * @internal - */ -export type InternalHttpResourcesSetup = InternalHttpResourcesPreboot; - /** * HttpResources service is responsible for serving static & dynamic assets for Kibana application via HTTP. * Provides API allowing plug-ins to respond with: diff --git a/packages/core/http/core-http-resources-server/tsconfig.json b/packages/core/http/core-http-resources-server/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/http/core-http-resources-server/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/BUILD.bazel b/packages/core/metrics/core-metrics-collectors-server-internal/BUILD.bazel index 2b789e97cbe69..9761bcbf1cefb 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/BUILD.bazel +++ b/packages/core/metrics/core-metrics-collectors-server-internal/BUILD.bazel @@ -39,6 +39,8 @@ RUNTIME_DEPS = [ "//packages/kbn-logging", "@npm//moment", "@npm//getos", + ### test dependencies + "//packages/core/elasticsearch/core-elasticsearch-client-server-mocks", ] TYPES_DEPS = [ @@ -50,6 +52,7 @@ TYPES_DEPS = [ "@npm//@types/hapi__hapi", "//packages/kbn-logging:npm_module_types", "//packages/core/metrics/core-metrics-server:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-client-server-internal:npm_module_types", ] jsts_transpiler( diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/index.ts b/packages/core/metrics/core-metrics-collectors-server-internal/index.ts index a4639202353e1..351129cdc8ba3 100644 --- a/packages/core/metrics/core-metrics-collectors-server-internal/index.ts +++ b/packages/core/metrics/core-metrics-collectors-server-internal/index.ts @@ -11,3 +11,4 @@ export type { OpsMetricsCollectorOptions } from './src/os'; export { ProcessMetricsCollector } from './src/process'; export { ServerMetricsCollector } from './src/server'; export { EventLoopDelaysMonitor } from './src/event_loop_delays_monitor'; +export { ElasticsearchClientsMetricsCollector } from './src/elasticsearch_client'; diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.test.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.test.ts new file mode 100644 index 0000000000000..363fca6430dbe --- /dev/null +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Agent as HttpAgent } from 'http'; +import { Agent as HttpsAgent } from 'https'; +import { sampleEsClientMetrics } from '@kbn/core-metrics-server-mocks'; +import { createAgentStoreMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { getAgentsSocketsStatsMock } from './get_agents_sockets_stats.test.mocks'; +import { ElasticsearchClientsMetricsCollector } from './elasticsearch_client'; +import { getAgentsSocketsStats } from './get_agents_sockets_stats'; + +jest.mock('@kbn/core-elasticsearch-client-server-internal'); + +describe('ElasticsearchClientsMetricsCollector', () => { + test('#collect calls getAgentsSocketsStats with the Agents managed by the provided AgentManager', async () => { + const agents = new Set([new HttpAgent(), new HttpsAgent()]); + const agentStore = createAgentStoreMock(agents); + getAgentsSocketsStatsMock.mockReturnValueOnce(sampleEsClientMetrics); + + const esClientsMetricsCollector = new ElasticsearchClientsMetricsCollector(agentStore); + const metrics = await esClientsMetricsCollector.collect(); + + expect(agentStore.getAgents).toHaveBeenCalledTimes(1); + expect(getAgentsSocketsStats).toHaveBeenCalledTimes(1); + expect(getAgentsSocketsStats).toHaveBeenNthCalledWith(1, agents); + expect(metrics).toEqual(sampleEsClientMetrics); + }); +}); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.ts new file mode 100644 index 0000000000000..278fd0218f8c0 --- /dev/null +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/elasticsearch_client.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. + */ + +import type { ElasticsearchClientsMetrics, MetricsCollector } from '@kbn/core-metrics-server'; +import type { AgentStore } from '@kbn/core-elasticsearch-client-server-internal'; +import { getAgentsSocketsStats } from './get_agents_sockets_stats'; + +export class ElasticsearchClientsMetricsCollector + implements MetricsCollector +{ + constructor(private readonly agentStore: AgentStore) {} + + public async collect(): Promise { + return await getAgentsSocketsStats(this.agentStore.getAgents()); + } + + public reset() { + // we do not have a state in this Collector, aka metrics are not accumulated over time. + // Thus, we don't need to perform any cleanup to reset the collected metrics + } +} diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.test.mocks.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.test.mocks.ts new file mode 100644 index 0000000000000..4e9688ccc91b9 --- /dev/null +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.test.mocks.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 { Agent as HttpAgent } from 'http'; +import { Agent as HttpsAgent } from 'https'; + +import { getAgentsSocketsStats } from './get_agents_sockets_stats'; + +export const getHttpAgentMock = (overrides: Partial) => { + return Object.assign(new HttpAgent(), overrides); +}; + +export const getHttpsAgentMock = (overrides: Partial) => { + return Object.assign(new HttpsAgent(), overrides); +}; + +export const getAgentsSocketsStatsMock: jest.MockedFunction = + jest.fn(); + +jest.doMock('./get_agents_sockets_stats', () => { + return { + getAgentsSocketsStats: getAgentsSocketsStatsMock, + }; +}); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.test.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.test.ts new file mode 100644 index 0000000000000..513bf2caa8545 --- /dev/null +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.test.ts @@ -0,0 +1,147 @@ +/* + * Copyright 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 { Socket } from 'net'; +import { Agent, IncomingMessage } from 'http'; +import { getAgentsSocketsStats } from './get_agents_sockets_stats'; +import { getHttpAgentMock, getHttpsAgentMock } from './get_agents_sockets_stats.test.mocks'; + +jest.mock('net'); + +const mockSocket = new Socket(); +const mockIncomingMessage = new IncomingMessage(mockSocket); + +describe('getAgentsSocketsStats()', () => { + it('extracts aggregated stats from the specified agents', () => { + const agent1 = getHttpAgentMock({ + sockets: { + node1: [mockSocket, mockSocket, mockSocket], + node2: [mockSocket], + }, + freeSockets: { + node1: [mockSocket], + node3: [mockSocket, mockSocket, mockSocket, mockSocket], + }, + requests: { + node1: [mockIncomingMessage, mockIncomingMessage], + }, + }); + + const agent2 = getHttpAgentMock({ + sockets: { + node1: [mockSocket, mockSocket, mockSocket], + node4: [mockSocket], + }, + freeSockets: { + node3: [mockSocket, mockSocket, mockSocket, mockSocket], + }, + requests: { + node4: [mockIncomingMessage, mockIncomingMessage, mockIncomingMessage, mockIncomingMessage], + }, + }); + + const stats = getAgentsSocketsStats(new Set([agent1, agent2])); + expect(stats).toEqual({ + averageActiveSocketsPerNode: 2.6666666666666665, + averageIdleSocketsPerNode: 4.5, + connectedNodes: 4, + mostActiveNodeSockets: 6, + mostIdleNodeSockets: 8, + nodesWithActiveSockets: 3, + nodesWithIdleSockets: 2, + protocol: 'http', + totalActiveSockets: 8, + totalIdleSockets: 9, + totalQueuedRequests: 6, + }); + }); + + it('takes into account Agent types to determine the `protocol`', () => { + const httpAgent = getHttpAgentMock({ + sockets: { node1: [mockSocket] }, + freeSockets: {}, + requests: {}, + }); + + const httpsAgent = getHttpsAgentMock({ + sockets: { node1: [mockSocket] }, + freeSockets: {}, + requests: {}, + }); + + const noAgents = new Set(); + const httpAgents = new Set([httpAgent, httpAgent]); + const httpsAgents = new Set([httpsAgent, httpsAgent]); + const mixedAgents = new Set([httpAgent, httpsAgent]); + + expect(getAgentsSocketsStats(noAgents).protocol).toEqual('none'); + expect(getAgentsSocketsStats(httpAgents).protocol).toEqual('http'); + expect(getAgentsSocketsStats(httpsAgents).protocol).toEqual('https'); + expect(getAgentsSocketsStats(mixedAgents).protocol).toEqual('mixed'); + }); + + it('does not take into account those Agents that have not had any connection to any node', () => { + const pristineAgentProps = { + sockets: {}, + freeSockets: {}, + requests: {}, + }; + const agent1 = getHttpAgentMock(pristineAgentProps); + const agent2 = getHttpAgentMock(pristineAgentProps); + const agent3 = getHttpAgentMock(pristineAgentProps); + + const stats = getAgentsSocketsStats(new Set([agent1, agent2, agent3])); + + expect(stats).toEqual({ + averageActiveSocketsPerNode: 0, + averageIdleSocketsPerNode: 0, + connectedNodes: 0, + mostActiveNodeSockets: 0, + mostIdleNodeSockets: 0, + nodesWithActiveSockets: 0, + nodesWithIdleSockets: 0, + protocol: 'none', + totalActiveSockets: 0, + totalIdleSockets: 0, + totalQueuedRequests: 0, + }); + }); + + it('takes into account those Agents that have hold mappings to one or more nodes, but that do not currently have any pending requests, active connections or idle connections', () => { + const emptyAgentProps = { + sockets: { + node1: [], + }, + freeSockets: { + node2: [], + }, + requests: { + node3: [], + }, + }; + + const agent1 = getHttpAgentMock(emptyAgentProps); + const agent2 = getHttpAgentMock(emptyAgentProps); + + const stats = getAgentsSocketsStats(new Set([agent1, agent2])); + + expect(stats).toEqual({ + averageActiveSocketsPerNode: 0, + averageIdleSocketsPerNode: 0, + connectedNodes: 3, + mostActiveNodeSockets: 0, + mostIdleNodeSockets: 0, + nodesWithActiveSockets: 0, + nodesWithIdleSockets: 0, + protocol: 'http', + totalActiveSockets: 0, + totalIdleSockets: 0, + totalQueuedRequests: 0, + }); + }); +}); diff --git a/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.ts b/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.ts new file mode 100644 index 0000000000000..e28c92a56a8a4 --- /dev/null +++ b/packages/core/metrics/core-metrics-collectors-server-internal/src/get_agents_sockets_stats.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { NetworkAgent } from '@kbn/core-elasticsearch-client-server-internal'; +import { Agent as HttpsAgent } from 'https'; +import { mean } from 'lodash'; +import type { + ElasticsearchClientProtocol, + ElasticsearchClientsMetrics, +} from '@kbn/core-metrics-server'; + +export const getAgentsSocketsStats = (agents: Set): ElasticsearchClientsMetrics => { + const nodes = new Set(); + let totalActiveSockets = 0; + let totalIdleSockets = 0; + let totalQueuedRequests = 0; + let http: boolean = false; + let https: boolean = false; + + const nodesWithActiveSockets: Record = {}; + const nodesWithIdleSockets: Record = {}; + + agents.forEach((agent) => { + const agentRequests = Object.entries(agent.requests) ?? []; + const agentSockets = Object.entries(agent.sockets) ?? []; + const agentFreeSockets = Object.entries(agent.freeSockets) ?? []; + + if (agentRequests.length || agentSockets.length || agentFreeSockets.length) { + if (agent instanceof HttpsAgent) https = true; + else http = true; + + agentRequests.forEach(([node, queue]) => { + nodes.add(node); + totalQueuedRequests += queue?.length ?? 0; + }); + + agentSockets.forEach(([node, sockets]) => { + nodes.add(node); + const activeSockets = sockets?.length ?? 0; + totalActiveSockets += activeSockets; + nodesWithActiveSockets[node] = (nodesWithActiveSockets[node] ?? 0) + activeSockets; + }); + + agentFreeSockets.forEach(([node, freeSockets]) => { + nodes.add(node); + const idleSockets = freeSockets?.length ?? 0; + totalIdleSockets += idleSockets; + nodesWithIdleSockets[node] = (nodesWithIdleSockets[node] ?? 0) + idleSockets; + }); + } + }); + + const activeSocketCounters = Object.values(nodesWithActiveSockets); + const idleSocketCounters = Object.values(nodesWithIdleSockets); + const protocol: ElasticsearchClientProtocol = http + ? https + ? 'mixed' + : 'http' + : https + ? 'https' + : 'none'; + + return { + protocol, + connectedNodes: nodes.size, + nodesWithActiveSockets: activeSocketCounters.filter(Boolean).length, + nodesWithIdleSockets: idleSocketCounters.filter(Boolean).length, + totalActiveSockets, + totalIdleSockets, + totalQueuedRequests, + mostActiveNodeSockets: activeSocketCounters.length ? Math.max(...activeSocketCounters) : 0, + averageActiveSocketsPerNode: activeSocketCounters.length ? mean(activeSocketCounters) : 0, + mostIdleNodeSockets: idleSocketCounters.length ? Math.max(...idleSocketCounters) : 0, + averageIdleSocketsPerNode: idleSocketCounters.length ? mean(idleSocketCounters) : 0, + }; +}; diff --git a/packages/core/metrics/core-metrics-server-internal/BUILD.bazel b/packages/core/metrics/core-metrics-server-internal/BUILD.bazel index da7883016afd2..0a7f393ec0b31 100644 --- a/packages/core/metrics/core-metrics-server-internal/BUILD.bazel +++ b/packages/core/metrics/core-metrics-server-internal/BUILD.bazel @@ -37,11 +37,15 @@ NPM_MODULE_EXTRA_FILES = [ RUNTIME_DEPS = [ "@npm//rxjs", "@npm//moment", - "//packages/kbn-logging-mocks", "//packages/kbn-config-schema", - "//packages/core/http/core-http-server-mocks", "//packages/core/metrics/core-metrics-collectors-server-internal", + "//packages/core/elasticsearch/core-elasticsearch-server-internal", + ### test dependencies + "//packages/kbn-logging-mocks", + "//packages/core/http/core-http-server-mocks", + "//packages/core/metrics/core-metrics-server-mocks", "//packages/core/metrics/core-metrics-collectors-server-mocks", + "//packages/core/elasticsearch/core-elasticsearch-server-mocks", ] @@ -57,6 +61,7 @@ TYPES_DEPS = [ "//packages/core/http/core-http-server-internal:npm_module_types", "//packages/core/metrics/core-metrics-server:npm_module_types", "//packages/core/metrics/core-metrics-collectors-server-internal:npm_module_types", + "//packages/core/elasticsearch/core-elasticsearch-server-internal:npm_module_types", ] diff --git a/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.test.ts b/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.test.ts index 8de7a5fa5dadf..d997433667e27 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.test.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/logging/get_ops_metrics_log.test.ts @@ -8,6 +8,7 @@ import type { OpsMetrics } from '@kbn/core-metrics-server'; import { getEcsOpsMetricsLog } from './get_ops_metrics_log'; +import { sampleEsClientMetrics } from '@kbn/core-metrics-server-mocks'; import { collectorMock } from '@kbn/core-metrics-collectors-server-mocks'; function createBaseOpsMetrics(): OpsMetrics { @@ -24,6 +25,7 @@ function createBaseOpsMetrics(): OpsMetrics { memory: { total_in_bytes: 1, free_in_bytes: 1, used_in_bytes: 1 }, uptime_in_millis: 1, }, + elasticsearch_client: sampleEsClientMetrics, response_times: { avg_in_millis: 1, max_in_millis: 1 }, requests: { disconnects: 1, total: 1, statusCodes: { '200': 1 } }, concurrent_connections: 1, diff --git a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts index de78b534b2dc7..351e2aca43f56 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.test.ts @@ -8,13 +8,15 @@ import moment from 'moment'; +import { take } from 'rxjs/operators'; import { configServiceMock } from '@kbn/config-mocks'; import { mockCoreContext } from '@kbn/core-base-server-mocks'; import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; import { mockOpsCollector } from './metrics_service.test.mocks'; import { MetricsService } from './metrics_service'; -import { take } from 'rxjs/operators'; +import { OpsMetricsCollector } from './ops_metrics_collector'; const testInterval = 100; @@ -24,6 +26,7 @@ const logger = loggingSystemMock.create(); describe('MetricsService', () => { const httpMock = httpServiceMock.createInternalSetupContract(); + const esServiceMock = elasticsearchServiceMock.createInternalSetup(); let metricsService: MetricsService; beforeEach(() => { @@ -43,9 +46,16 @@ describe('MetricsService', () => { describe('#start', () => { it('invokes setInterval with the configured interval', async () => { - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); await metricsService.start(); + expect(OpsMetricsCollector).toHaveBeenCalledTimes(1); + expect(OpsMetricsCollector).toHaveBeenCalledWith( + httpMock.server, + esServiceMock.agentStore, + expect.objectContaining({ logger: logger.get('metrics') }) + ); + expect(setInterval).toHaveBeenCalledTimes(1); expect(setInterval).toHaveBeenCalledWith(expect.any(Function), testInterval); }); @@ -53,7 +63,7 @@ describe('MetricsService', () => { it('collects the metrics at every interval', async () => { mockOpsCollector.collect.mockResolvedValue(dummyMetrics); - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); await metricsService.start(); expect(mockOpsCollector.collect).toHaveBeenCalledTimes(1); @@ -68,7 +78,7 @@ describe('MetricsService', () => { it('resets the collector after each collection', async () => { mockOpsCollector.collect.mockResolvedValue(dummyMetrics); - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); const { getOpsMetrics$ } = await metricsService.start(); // `advanceTimersByTime` only ensure the interval handler is executed @@ -108,7 +118,7 @@ describe('MetricsService', () => { .mockResolvedValueOnce(firstMetrics) .mockResolvedValueOnce(secondMetrics); - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); const { getOpsMetrics$ } = await metricsService.start(); const nextEmission = async () => { @@ -157,7 +167,7 @@ describe('MetricsService', () => { mockOpsCollector.collect .mockResolvedValueOnce(firstMetrics) .mockResolvedValueOnce(secondMetrics); - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); const { getOpsMetrics$ } = await metricsService.start(); const nextEmission = async () => { @@ -176,7 +186,7 @@ describe('MetricsService', () => { it('omits metrics from log message if they are missing or malformed', async () => { const opsLogger = logger.get('metrics', 'ops'); mockOpsCollector.collect.mockResolvedValueOnce({ secondMetrics: 'metrics' }); - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); await metricsService.start(); expect(loggingSystemMock.collect(opsLogger).debug[0]).toMatchInlineSnapshot(` Array [ @@ -219,7 +229,7 @@ describe('MetricsService', () => { describe('#stop', () => { it('stops the metrics interval', async () => { - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); const { getOpsMetrics$ } = await metricsService.start(); expect(mockOpsCollector.collect).toHaveBeenCalledTimes(1); @@ -235,7 +245,7 @@ describe('MetricsService', () => { }); it('completes the metrics observable', async () => { - await metricsService.setup({ http: httpMock }); + await metricsService.setup({ http: httpMock, elasticsearchService: esServiceMock }); const { getOpsMetrics$ } = await metricsService.start(); let completed = false; diff --git a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.ts b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.ts index 8a05b4b57843c..95a9dc09bba57 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/metrics_service.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/metrics_service.ts @@ -10,6 +10,7 @@ import { firstValueFrom, ReplaySubject } from 'rxjs'; import type { CoreContext, CoreService } from '@kbn/core-base-server-internal'; import type { Logger } from '@kbn/logging'; import type { InternalHttpServiceSetup } from '@kbn/core-http-server-internal'; +import type { InternalElasticsearchServiceSetup } from '@kbn/core-elasticsearch-server-internal'; import type { OpsMetrics, MetricsServiceSetup, @@ -21,6 +22,7 @@ import { getEcsOpsMetricsLog } from './logging'; export interface MetricsServiceSetupDeps { http: InternalHttpServiceSetup; + elasticsearchService: InternalElasticsearchServiceSetup; } /** @internal */ @@ -45,12 +47,15 @@ export class MetricsService this.opsMetricsLogger = coreContext.logger.get('metrics', 'ops'); } - public async setup({ http }: MetricsServiceSetupDeps): Promise { + public async setup({ + http, + elasticsearchService, + }: MetricsServiceSetupDeps): Promise { const config = await firstValueFrom( this.coreContext.configService.atPath(OPS_CONFIG_PATH) ); - this.metricsCollector = new OpsMetricsCollector(http.server, { + this.metricsCollector = new OpsMetricsCollector(http.server, elasticsearchService.agentStore, { logger: this.logger, ...config.cGroupOverrides, }); diff --git a/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.mocks.ts b/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.mocks.ts index b96449fdc2f64..d70753b9f4644 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.mocks.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.mocks.ts @@ -11,11 +11,13 @@ import { collectorMock } from '@kbn/core-metrics-collectors-server-mocks'; export const mockOsCollector = collectorMock.create(); export const mockProcessCollector = collectorMock.create(); export const mockServerCollector = collectorMock.create(); +export const mockEsClientCollector = collectorMock.create(); jest.doMock('@kbn/core-metrics-collectors-server-internal', () => { return { OsMetricsCollector: jest.fn().mockImplementation(() => mockOsCollector), ProcessMetricsCollector: jest.fn().mockImplementation(() => mockProcessCollector), ServerMetricsCollector: jest.fn().mockImplementation(() => mockServerCollector), + ElasticsearchClientsMetricsCollector: jest.fn().mockImplementation(() => mockEsClientCollector), }; }); diff --git a/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.ts b/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.ts index cd80c35b37f86..87011a663404f 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.test.ts @@ -8,7 +8,10 @@ import { loggerMock } from '@kbn/logging-mocks'; import { httpServiceMock } from '@kbn/core-http-server-mocks'; +import { sampleEsClientMetrics } from '@kbn/core-metrics-server-mocks'; +import { AgentManager } from '@kbn/core-elasticsearch-client-server-internal'; import { + mockEsClientCollector, mockOsCollector, mockProcessCollector, mockServerCollector, @@ -20,7 +23,8 @@ describe('OpsMetricsCollector', () => { beforeEach(() => { const hapiServer = httpServiceMock.createInternalSetupContract().server; - collector = new OpsMetricsCollector(hapiServer, { logger: loggerMock.create() }); + const agentManager = new AgentManager(); + collector = new OpsMetricsCollector(hapiServer, agentManager, { logger: loggerMock.create() }); mockOsCollector.collect.mockResolvedValue('osMetrics'); }); @@ -33,12 +37,14 @@ describe('OpsMetricsCollector', () => { requests: 'serverRequestsMetrics', response_times: 'serverTimingMetrics', }); + mockEsClientCollector.collect.mockResolvedValue(sampleEsClientMetrics); const metrics = await collector.collect(); expect(mockOsCollector.collect).toHaveBeenCalledTimes(1); expect(mockProcessCollector.collect).toHaveBeenCalledTimes(1); expect(mockServerCollector.collect).toHaveBeenCalledTimes(1); + expect(mockEsClientCollector.collect).toHaveBeenCalledTimes(1); expect(metrics).toEqual({ collected_at: expect.any(Date), @@ -47,6 +53,7 @@ describe('OpsMetricsCollector', () => { os: 'osMetrics', requests: 'serverRequestsMetrics', response_times: 'serverTimingMetrics', + elasticsearch_client: sampleEsClientMetrics, }); }); }); diff --git a/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.ts b/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.ts index 10958d93c2562..8a10f4071b11b 100644 --- a/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.ts +++ b/packages/core/metrics/core-metrics-server-internal/src/ops_metrics_collector.ts @@ -8,28 +8,33 @@ import { Server as HapiServer } from '@hapi/hapi'; import type { OpsMetrics, MetricsCollector } from '@kbn/core-metrics-server'; +import type { AgentStore } from '@kbn/core-elasticsearch-client-server-internal'; import { ProcessMetricsCollector, OsMetricsCollector, type OpsMetricsCollectorOptions, ServerMetricsCollector, + ElasticsearchClientsMetricsCollector, } from '@kbn/core-metrics-collectors-server-internal'; export class OpsMetricsCollector implements MetricsCollector { private readonly processCollector: ProcessMetricsCollector; private readonly osCollector: OsMetricsCollector; private readonly serverCollector: ServerMetricsCollector; + private readonly esClientCollector: ElasticsearchClientsMetricsCollector; - constructor(server: HapiServer, opsOptions: OpsMetricsCollectorOptions) { + constructor(server: HapiServer, agentStore: AgentStore, opsOptions: OpsMetricsCollectorOptions) { this.processCollector = new ProcessMetricsCollector(); this.osCollector = new OsMetricsCollector(opsOptions); this.serverCollector = new ServerMetricsCollector(server); + this.esClientCollector = new ElasticsearchClientsMetricsCollector(agentStore); } public async collect(): Promise { - const [processes, os, server] = await Promise.all([ + const [processes, os, esClient, server] = await Promise.all([ this.processCollector.collect(), this.osCollector.collect(), + this.esClientCollector.collect(), this.serverCollector.collect(), ]); @@ -43,6 +48,7 @@ export class OpsMetricsCollector implements MetricsCollector { process: processes[0], processes, os, + elasticsearch_client: esClient, ...server, }; } diff --git a/packages/core/metrics/core-metrics-server-mocks/index.ts b/packages/core/metrics/core-metrics-server-mocks/index.ts index d252b2253243e..02d13b8ed5ad8 100644 --- a/packages/core/metrics/core-metrics-server-mocks/index.ts +++ b/packages/core/metrics/core-metrics-server-mocks/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { metricsServiceMock } from './src/metrics_service.mock'; +export { metricsServiceMock, sampleEsClientMetrics } from './src/metrics_service.mock'; diff --git a/packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts b/packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts index 6bbe176ce37e8..44601caeaa85c 100644 --- a/packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts +++ b/packages/core/metrics/core-metrics-server-mocks/src/metrics_service.mock.ts @@ -17,7 +17,25 @@ import { mocked as eventLoopDelaysMonitorMock, collectorMock, } from '@kbn/core-metrics-collectors-server-mocks'; -import type { MetricsServiceSetup, MetricsServiceStart } from '@kbn/core-metrics-server'; +import type { + ElasticsearchClientsMetrics, + MetricsServiceSetup, + MetricsServiceStart, +} from '@kbn/core-metrics-server'; + +export const sampleEsClientMetrics: ElasticsearchClientsMetrics = { + protocol: 'https', + connectedNodes: 3, + nodesWithActiveSockets: 3, + nodesWithIdleSockets: 1, + totalActiveSockets: 25, + totalIdleSockets: 2, + totalQueuedRequests: 0, + mostActiveNodeSockets: 15, + averageActiveSocketsPerNode: 8, + mostIdleNodeSockets: 2, + averageIdleSocketsPerNode: 0.5, +}; const createInternalSetupContractMock = () => { const setupContract: jest.Mocked = { @@ -39,6 +57,7 @@ const createInternalSetupContractMock = () => { memory: { total_in_bytes: 1, free_in_bytes: 1, used_in_bytes: 1 }, uptime_in_millis: 1, }, + elasticsearch_client: sampleEsClientMetrics, response_times: { avg_in_millis: 1, max_in_millis: 1 }, requests: { disconnects: 1, total: 1, statusCodes: { '200': 1 } }, concurrent_connections: 1, diff --git a/packages/core/metrics/core-metrics-server/index.ts b/packages/core/metrics/core-metrics-server/index.ts index 51e0b7fe3d95d..49bd2a4251623 100644 --- a/packages/core/metrics/core-metrics-server/index.ts +++ b/packages/core/metrics/core-metrics-server/index.ts @@ -14,4 +14,6 @@ export type { OpsProcessMetrics, OpsOsMetrics, OpsServerMetrics, + ElasticsearchClientProtocol, + ElasticsearchClientsMetrics, } from './src/metrics'; diff --git a/packages/core/metrics/core-metrics-server/src/metrics.ts b/packages/core/metrics/core-metrics-server/src/metrics.ts index dbfa643c8eccc..958f6b75f55e4 100644 --- a/packages/core/metrics/core-metrics-server/src/metrics.ts +++ b/packages/core/metrics/core-metrics-server/src/metrics.ts @@ -40,6 +40,44 @@ export interface IntervalHistogram { }; } +/** + * Protocol(s) used by the Elasticsearch Client + * @public + */ + +export type ElasticsearchClientProtocol = 'none' | 'http' | 'https' | 'mixed'; + +/** + * Metrics related to the elasticsearch clients + * @public + */ +export interface ElasticsearchClientsMetrics { + /** The protocol (or protocols) that these Agents are using */ + protocol: ElasticsearchClientProtocol; + /** Number of ES nodes that ES-js client is connecting to */ + connectedNodes: number; + /** Number of nodes with active connections */ + nodesWithActiveSockets: number; + /** Number of nodes with available connections (alive but idle). + * Note that a node can have both active and idle connections at the same time + */ + nodesWithIdleSockets: number; + /** Total number of active sockets (all nodes, all connections) */ + totalActiveSockets: number; + /** Total number of available sockets (alive but idle, all nodes, all connections) */ + totalIdleSockets: number; + /** Total number of queued requests (all nodes, all connections) */ + totalQueuedRequests: number; + /** Number of active connections of the node with most active connections */ + mostActiveNodeSockets: number; + /** Average of active sockets per node (all connections) */ + averageActiveSocketsPerNode: number; + /** Number of idle connections of the node with most idle connections */ + mostIdleNodeSockets: number; + /** Average of available (idle) sockets per node (all connections) */ + averageIdleSocketsPerNode: number; +} + /** * Process related metrics * @public @@ -165,6 +203,10 @@ export interface OpsServerMetrics { export interface OpsMetrics { /** Time metrics were recorded at. */ collected_at: Date; + /** + * Metrics related to the elasticsearch client + */ + elasticsearch_client: ElasticsearchClientsMetrics; /** * Process related metrics. * @deprecated use the processes field instead. 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 0739c9acab8f5..d9a65f984c222 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 @@ -4182,6 +4182,10 @@ describe('SavedObjectsRepository', () => { type: 'foo', id: '1', }, + hasNoReference: { + type: 'bar', + id: '1', + }, }; it(`passes mappings, registry, and search options to getSearchDsl`, async () => { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts index 5569141c7fa0e..f48e031bd23c4 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/repository.ts @@ -1129,6 +1129,8 @@ export class SavedObjectsRepository implements ISavedObjectsRepository { rootSearchFields, hasReference, hasReferenceOperator, + hasNoReference, + hasNoReferenceOperator, page = FIND_DEFAULT_PAGE, perPage = FIND_DEFAULT_PER_PAGE, pit, @@ -1235,6 +1237,8 @@ export class SavedObjectsRepository implements ISavedObjectsRepository { typeToNamespacesMap, hasReference, hasReferenceOperator, + hasNoReference, + hasNoReferenceOperator, kueryNode, }), }, diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.test.ts index c502665468e6c..20ce3a2f46b2e 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.test.ts @@ -195,17 +195,18 @@ describe('#getQueryParams', () => { }); }); - describe('reference filter clause', () => { - describe('`hasReference` parameter', () => { - it('does not call `getReferencesFilter` when `hasReference` is not specified', () => { - getQueryParams({ - registry, - hasReference: undefined, - }); - - expect(getReferencesFilterMock).not.toHaveBeenCalled(); + describe('reference/noreference filter clause', () => { + it('does not call `getReferencesFilter` when neither `hasReference` nor `hasNoReference` are specified', () => { + getQueryParams({ + registry, + hasReference: undefined, + hasNoReference: undefined, }); + expect(getReferencesFilterMock).not.toHaveBeenCalled(); + }); + + describe('`hasReference` parameter', () => { it('calls `getReferencesFilter` with the correct parameters', () => { const hasReference = { id: 'foo', type: 'bar' }; getQueryParams({ @@ -235,6 +236,38 @@ describe('#getQueryParams', () => { expect(filters.some((filter) => filter.references_filter === true)).toBeDefined(); }); }); + + describe('`hasNoReference` parameter', () => { + it('calls `getReferencesFilter` with the correct parameters', () => { + const hasNoReference = { id: 'noFoo', type: 'bar' }; + getQueryParams({ + registry, + hasNoReference, + hasNoReferenceOperator: 'AND', + }); + + expect(getReferencesFilterMock).toHaveBeenCalledTimes(1); + expect(getReferencesFilterMock).toHaveBeenCalledWith({ + must: false, + references: [hasNoReference], + operator: 'AND', + }); + }); + + it('includes the return of `getReferencesFilter` in the `filter` clause', () => { + getReferencesFilterMock.mockReturnValue({ references_filter: true }); + + const hasNoReference = { id: 'noFoo', type: 'bar' }; + const result = getQueryParams({ + registry, + hasNoReference, + hasReferenceOperator: 'AND', + }); + + const filters: any[] = result.query.bool.filter; + expect(filters.some((filter) => filter.references_filter === true)).toBeDefined(); + }); + }); }); describe('type filter clauses', () => { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.ts index 669f2a273569b..896b934c90b80 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/query_params.ts @@ -7,6 +7,7 @@ */ import * as esKuery from '@kbn/es-query'; +import type { SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common'; type KueryNode = any; @@ -123,11 +124,6 @@ function getClauseForType( }; } -export interface HasReferenceQueryParams { - type: string; - id: string; -} - export type SearchOperator = 'AND' | 'OR'; interface QueryParams { @@ -139,8 +135,10 @@ interface QueryParams { defaultSearchOperator?: SearchOperator; searchFields?: string[]; rootSearchFields?: string[]; - hasReference?: HasReferenceQueryParams | HasReferenceQueryParams[]; + hasReference?: SavedObjectTypeIdTuple | SavedObjectTypeIdTuple[]; hasReferenceOperator?: SearchOperator; + hasNoReference?: SavedObjectTypeIdTuple | SavedObjectTypeIdTuple[]; + hasNoReferenceOperator?: SearchOperator; kueryNode?: KueryNode; } @@ -148,6 +146,13 @@ interface QueryParams { const uniqNamespaces = (namespacesToNormalize?: string[]) => namespacesToNormalize ? Array.from(new Set(namespacesToNormalize)) : undefined; +const toArray = (val: unknown) => { + if (typeof val === 'undefined') { + return val; + } + return !Array.isArray(val) ? [val] : val; +}; + /** * Get the "query" related keys for the search body */ @@ -162,6 +167,8 @@ export function getQueryParams({ defaultSearchOperator, hasReference, hasReferenceOperator, + hasNoReference, + hasNoReferenceOperator, kueryNode, }: QueryParams) { const types = getTypes( @@ -169,9 +176,8 @@ export function getQueryParams({ typeToNamespacesMap ? Array.from(typeToNamespacesMap.keys()) : type ); - if (hasReference && !Array.isArray(hasReference)) { - hasReference = [hasReference]; - } + hasReference = toArray(hasReference); + hasNoReference = toArray(hasNoReference); const bool: any = { filter: [ @@ -184,6 +190,15 @@ export function getQueryParams({ }), ] : []), + ...(hasNoReference?.length + ? [ + getReferencesFilter({ + references: hasNoReference, + operator: hasNoReferenceOperator, + must: false, + }), + ] + : []), { bool: { should: types.map((shouldType) => { diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.test.ts index 9a042579c8e8f..127f3a94edd21 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.test.ts @@ -20,29 +20,141 @@ describe('getReferencesFilter', () => { }, }); - describe('when using the `OR` operator', () => { - it('generates one `should` clause per type of reference', () => { + describe('for "must" match clauses', () => { + describe('when using the `OR` operator', () => { + it('generates one `should` clause per type of reference', () => { + const references = [ + { type: 'foo', id: 'foo-1' }, + { type: 'foo', id: 'foo-2' }, + { type: 'foo', id: 'foo-3' }, + { type: 'bar', id: 'bar-1' }, + { type: 'bar', id: 'bar-2' }, + ]; + const clause = getReferencesFilter({ + references, + operator: 'OR', + }); + + expect(clause).toEqual({ + bool: { + should: [ + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-1', 'foo-2', 'foo-3'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['bar-1', 'bar-2'] } }, + { term: { 'references.type': 'bar' } }, + ]), + ], + minimum_should_match: 1, + }, + }); + }); + + it('does not include more than `maxTermsPerClause` per `terms` clauses', () => { + const references = [ + { type: 'foo', id: 'foo-1' }, + { type: 'foo', id: 'foo-2' }, + { type: 'foo', id: 'foo-3' }, + { type: 'foo', id: 'foo-4' }, + { type: 'foo', id: 'foo-5' }, + { type: 'bar', id: 'bar-1' }, + { type: 'bar', id: 'bar-2' }, + { type: 'bar', id: 'bar-3' }, + { type: 'dolly', id: 'dolly-1' }, + ]; + const clause = getReferencesFilter({ + references, + operator: 'OR', + maxTermsPerClause: 2, + }); + + expect(clause).toEqual({ + bool: { + should: [ + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-1', 'foo-2'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-3', 'foo-4'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-5'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['bar-1', 'bar-2'] } }, + { term: { 'references.type': 'bar' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['bar-3'] } }, + { term: { 'references.type': 'bar' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['dolly-1'] } }, + { term: { 'references.type': 'dolly' } }, + ]), + ], + minimum_should_match: 1, + }, + }); + }); + }); + + describe('when using the `AND` operator', () => { + it('generates one `must` clause per reference', () => { + const references = [ + { type: 'foo', id: 'foo-1' }, + { type: 'foo', id: 'foo-2' }, + { type: 'bar', id: 'bar-1' }, + ]; + + const clause = getReferencesFilter({ + references, + operator: 'AND', + }); + + expect(clause).toEqual({ + bool: { + must: references.map((ref) => ({ + nested: { + path: 'references', + query: { + bool: { + must: [ + { term: { 'references.id': ref.id } }, + { term: { 'references.type': ref.type } }, + ], + }, + }, + }, + })), + }, + }); + }); + }); + + it('defaults to using the `OR` operator', () => { const references = [ { type: 'foo', id: 'foo-1' }, - { type: 'foo', id: 'foo-2' }, - { type: 'foo', id: 'foo-3' }, { type: 'bar', id: 'bar-1' }, - { type: 'bar', id: 'bar-2' }, ]; const clause = getReferencesFilter({ references, - operator: 'OR', }); expect(clause).toEqual({ bool: { should: [ nestedRefMustClauses([ - { terms: { 'references.id': ['foo-1', 'foo-2', 'foo-3'] } }, + { terms: { 'references.id': ['foo-1'] } }, { term: { 'references.type': 'foo' } }, ]), nestedRefMustClauses([ - { terms: { 'references.id': ['bar-1', 'bar-2'] } }, + { terms: { 'references.id': ['bar-1'] } }, { term: { 'references.type': 'bar' } }, ]), ], @@ -50,115 +162,156 @@ describe('getReferencesFilter', () => { }, }); }); + }); + + describe('for "must_not" match clauses', () => { + describe('when using the `OR` operator', () => { + it('generates one `must_not` clause per type of reference', () => { + const references = [ + { type: 'foo', id: 'foo-1' }, + { type: 'foo', id: 'foo-2' }, + { type: 'foo', id: 'foo-3' }, + { type: 'bar', id: 'bar-1' }, + { type: 'bar', id: 'bar-2' }, + ]; + const clause = getReferencesFilter({ + references, + operator: 'OR', + must: false, + }); + + expect(clause).toEqual({ + bool: { + must_not: [ + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-1', 'foo-2', 'foo-3'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['bar-1', 'bar-2'] } }, + { term: { 'references.type': 'bar' } }, + ]), + ], + }, + }); + }); + + it('does not include more than `maxTermsPerClause` per `terms` clauses', () => { + const references = [ + { type: 'foo', id: 'foo-1' }, + { type: 'foo', id: 'foo-2' }, + { type: 'foo', id: 'foo-3' }, + { type: 'foo', id: 'foo-4' }, + { type: 'foo', id: 'foo-5' }, + { type: 'bar', id: 'bar-1' }, + { type: 'bar', id: 'bar-2' }, + { type: 'bar', id: 'bar-3' }, + { type: 'dolly', id: 'dolly-1' }, + ]; + const clause = getReferencesFilter({ + references, + operator: 'OR', + maxTermsPerClause: 2, + must: false, + }); + + expect(clause).toEqual({ + bool: { + must_not: [ + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-1', 'foo-2'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-3', 'foo-4'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['foo-5'] } }, + { term: { 'references.type': 'foo' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['bar-1', 'bar-2'] } }, + { term: { 'references.type': 'bar' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['bar-3'] } }, + { term: { 'references.type': 'bar' } }, + ]), + nestedRefMustClauses([ + { terms: { 'references.id': ['dolly-1'] } }, + { term: { 'references.type': 'dolly' } }, + ]), + ], + }, + }); + }); + }); - it('does not include mode than `maxTermsPerClause` per `terms` clauses', () => { + describe('when using the `AND` operator', () => { + it('generates one `must` clause per reference', () => { + const references = [ + { type: 'foo', id: 'foo-1' }, + { type: 'foo', id: 'foo-2' }, + { type: 'bar', id: 'bar-1' }, + ]; + + const clause = getReferencesFilter({ + references, + operator: 'AND', + must: false, + }); + + expect(clause).toEqual({ + bool: { + must_not: [ + { + bool: { + must: references.map((ref) => ({ + nested: { + path: 'references', + query: { + bool: { + must: [ + { term: { 'references.id': ref.id } }, + { term: { 'references.type': ref.type } }, + ], + }, + }, + }, + })), + }, + }, + ], + }, + }); + }); + }); + + it('defaults to using the `OR` operator', () => { const references = [ { type: 'foo', id: 'foo-1' }, - { type: 'foo', id: 'foo-2' }, - { type: 'foo', id: 'foo-3' }, - { type: 'foo', id: 'foo-4' }, - { type: 'foo', id: 'foo-5' }, { type: 'bar', id: 'bar-1' }, - { type: 'bar', id: 'bar-2' }, - { type: 'bar', id: 'bar-3' }, - { type: 'dolly', id: 'dolly-1' }, ]; const clause = getReferencesFilter({ references, - operator: 'OR', - maxTermsPerClause: 2, + must: false, }); expect(clause).toEqual({ bool: { - should: [ - nestedRefMustClauses([ - { terms: { 'references.id': ['foo-1', 'foo-2'] } }, - { term: { 'references.type': 'foo' } }, - ]), + must_not: [ nestedRefMustClauses([ - { terms: { 'references.id': ['foo-3', 'foo-4'] } }, + { terms: { 'references.id': ['foo-1'] } }, { term: { 'references.type': 'foo' } }, ]), nestedRefMustClauses([ - { terms: { 'references.id': ['foo-5'] } }, - { term: { 'references.type': 'foo' } }, - ]), - nestedRefMustClauses([ - { terms: { 'references.id': ['bar-1', 'bar-2'] } }, + { terms: { 'references.id': ['bar-1'] } }, { term: { 'references.type': 'bar' } }, ]), - nestedRefMustClauses([ - { terms: { 'references.id': ['bar-3'] } }, - { term: { 'references.type': 'bar' } }, - ]), - nestedRefMustClauses([ - { terms: { 'references.id': ['dolly-1'] } }, - { term: { 'references.type': 'dolly' } }, - ]), ], - minimum_should_match: 1, - }, - }); - }); - }); - - describe('when using the `AND` operator', () => { - it('generates one `must` clause per reference', () => { - const references = [ - { type: 'foo', id: 'foo-1' }, - { type: 'foo', id: 'foo-2' }, - { type: 'bar', id: 'bar-1' }, - ]; - - const clause = getReferencesFilter({ - references, - operator: 'AND', - }); - - expect(clause).toEqual({ - bool: { - must: references.map((ref) => ({ - nested: { - path: 'references', - query: { - bool: { - must: [ - { term: { 'references.id': ref.id } }, - { term: { 'references.type': ref.type } }, - ], - }, - }, - }, - })), }, }); }); }); - - it('defaults to using the `OR` operator', () => { - const references = [ - { type: 'foo', id: 'foo-1' }, - { type: 'bar', id: 'bar-1' }, - ]; - const clause = getReferencesFilter({ - references, - }); - - expect(clause).toEqual({ - bool: { - should: [ - nestedRefMustClauses([ - { terms: { 'references.id': ['foo-1'] } }, - { term: { 'references.type': 'foo' } }, - ]), - nestedRefMustClauses([ - { terms: { 'references.id': ['bar-1'] } }, - { term: { 'references.type': 'bar' } }, - ]), - ], - minimum_should_match: 1, - }, - }); - }); }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.ts index b0849560d2e43..4dd6bc640f174 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/references_filter.ts @@ -6,35 +6,61 @@ * Side Public License, v 1. */ -import type { HasReferenceQueryParams, SearchOperator } from './query_params'; +import type { SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common'; + +import type { SearchOperator } from './query_params'; export function getReferencesFilter({ references, operator = 'OR', maxTermsPerClause = 1000, + must = true, }: { - references: HasReferenceQueryParams[]; + references: SavedObjectTypeIdTuple[]; operator?: SearchOperator; maxTermsPerClause?: number; + must?: boolean; }) { if (operator === 'AND') { + if (must) { + return { + bool: { + must: references.map(getNestedTermClauseForReference), + }, + }; + } + return { bool: { - must: references.map(getNestedTermClauseForReference), + must_not: [ + { + bool: { + must: references.map(getNestedTermClauseForReference), + }, + }, + ], }, }; } else { + if (must) { + return { + bool: { + should: getAggregatedTermsClauses(references, maxTermsPerClause), + minimum_should_match: 1, + }, + }; + } + return { bool: { - should: getAggregatedTermsClauses(references, maxTermsPerClause), - minimum_should_match: 1, + must_not: getAggregatedTermsClauses(references, maxTermsPerClause), }, }; } } const getAggregatedTermsClauses = ( - references: HasReferenceQueryParams[], + references: SavedObjectTypeIdTuple[], maxTermsPerClause: number ) => { const refTypeToIds = references.reduce((map, { type, id }) => { @@ -58,7 +84,7 @@ const createChunks = (array: T[], chunkSize: number): T[][] => { return chunks; }; -export const getNestedTermClauseForReference = (reference: HasReferenceQueryParams) => { +export const getNestedTermClauseForReference = (reference: SavedObjectTypeIdTuple) => { return { nested: { path: 'references', diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.test.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.test.ts index d1ed7251b2414..84ef7c232d775 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.test.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.test.ts @@ -49,7 +49,7 @@ describe('getSearchDsl', () => { }); describe('passes control', () => { - it('passes (mappings, schema, namespaces, type, typeToNamespacesMap, search, searchFields, rootSearchFields, hasReference, hasReferenceOperator) to getQueryParams', () => { + it('passes (mappings, schema, namespaces, type, typeToNamespacesMap, search, searchFields, rootSearchFields, hasReference, hasReferenceOperator, hasNoReference, hasNoReferenceOperator) to getQueryParams', () => { const opts = { namespaces: ['foo-namespace'], type: 'foo', @@ -63,6 +63,11 @@ describe('getSearchDsl', () => { id: '1', }, hasReferenceOperator: 'AND' as queryParamsNS.SearchOperator, + hasNoReference: { + type: 'noBar', + id: '1', + }, + hasNoReferenceOperator: 'AND' as queryParamsNS.SearchOperator, }; getSearchDsl(mappings, registry, opts); @@ -78,6 +83,8 @@ describe('getSearchDsl', () => { defaultSearchOperator: opts.defaultSearchOperator, hasReference: opts.hasReference, hasReferenceOperator: opts.hasReferenceOperator, + hasNoReference: opts.hasNoReference, + hasNoReferenceOperator: opts.hasNoReferenceOperator, }); }); diff --git a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.ts b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.ts index 980bf800755b9..381f20069d25a 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server-internal/src/lib/search_dsl/search_dsl.ts @@ -12,7 +12,8 @@ import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { SavedObjectsPitParams } from '@kbn/core-saved-objects-api-server'; import type { ISavedObjectTypeRegistry } from '@kbn/core-saved-objects-server'; import type { IndexMapping } from '@kbn/core-saved-objects-base-server-internal'; -import { getQueryParams, HasReferenceQueryParams, SearchOperator } from './query_params'; +import type { SavedObjectTypeIdTuple } from '@kbn/core-saved-objects-common'; +import { getQueryParams, SearchOperator } from './query_params'; import { getPitParams } from './pit_params'; import { getSortingParams } from './sorting_params'; @@ -30,8 +31,10 @@ interface GetSearchDslOptions { namespaces?: string[]; pit?: SavedObjectsPitParams; typeToNamespacesMap?: Map; - hasReference?: HasReferenceQueryParams | HasReferenceQueryParams[]; + hasReference?: SavedObjectTypeIdTuple | SavedObjectTypeIdTuple[]; hasReferenceOperator?: SearchOperator; + hasNoReference?: SavedObjectTypeIdTuple | SavedObjectTypeIdTuple[]; + hasNoReferenceOperator?: SearchOperator; kueryNode?: KueryNode; } @@ -54,6 +57,8 @@ export function getSearchDsl( typeToNamespacesMap, hasReference, hasReferenceOperator, + hasNoReference, + hasNoReferenceOperator, kueryNode, } = options; @@ -77,6 +82,8 @@ export function getSearchDsl( defaultSearchOperator, hasReference, hasReferenceOperator, + hasNoReference, + hasNoReferenceOperator, kueryNode, }), ...getSortingParams(mappings, type, sortField, sortOrder), diff --git a/packages/core/saved-objects/core-saved-objects-api-server/src/apis/find.ts b/packages/core/saved-objects/core-saved-objects-api-server/src/apis/find.ts index 49042029f334b..a50506c96c8e5 100644 --- a/packages/core/saved-objects/core-saved-objects-api-server/src/apis/find.ts +++ b/packages/core/saved-objects/core-saved-objects-api-server/src/apis/find.ts @@ -66,11 +66,23 @@ export interface SavedObjectsFindOptions { * Use `hasReferenceOperator` to specify the operator to use when searching for multiple references. */ hasReference?: SavedObjectsFindOptionsReference | SavedObjectsFindOptionsReference[]; + /** * The operator to use when searching by multiple references using the `hasReference` option. Defaults to `OR` */ hasReferenceOperator?: 'AND' | 'OR'; + /** + * Search for documents *not* having a reference to the specified objects. + * Use `hasNoReferenceOperator` to specify the operator to use when searching for multiple references. + */ + hasNoReference?: SavedObjectsFindOptionsReference | SavedObjectsFindOptionsReference[]; + + /** + * The operator to use when searching by multiple references using the `hasNoReference` option. Defaults to `OR` + */ + hasNoReferenceOperator?: 'AND' | 'OR'; + /** * The search operator to use with the provided filter. Defaults to `OR` */ diff --git a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.test.ts b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.test.ts index 6c2966ee9775f..7825b09cf29bd 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.test.ts +++ b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.test.ts @@ -612,6 +612,7 @@ describe('SavedObjectsClient', () => { defaultSearchOperator: 'OR' as const, fields: ['title'], hasReference: { id: '1', type: 'reference' }, + hasNoReference: { id: '1', type: 'reference' }, page: 10, perPage: 100, search: 'what is the meaning of life?|life', @@ -633,6 +634,7 @@ describe('SavedObjectsClient', () => { "fields": Array [ "title", ], + "has_no_reference": "{\\"id\\":\\"1\\",\\"type\\":\\"reference\\"}", "has_reference": "{\\"id\\":\\"1\\",\\"type\\":\\"reference\\"}", "page": 10, "per_page": 100, diff --git a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts index dd2feed58123f..1fd111186f551 100644 --- a/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts +++ b/packages/core/saved-objects/core-saved-objects-browser-internal/src/saved_objects_client.ts @@ -292,6 +292,8 @@ export class SavedObjectsClient implements SavedObjectsClientContract { fields: 'fields', hasReference: 'has_reference', hasReferenceOperator: 'has_reference_operator', + hasNoReference: 'has_no_reference', + hasNoReferenceOperator: 'has_no_reference_operator', page: 'page', perPage: 'per_page', search: 'search', @@ -315,6 +317,9 @@ export class SavedObjectsClient implements SavedObjectsClientContract { if (query.has_reference) { query.has_reference = JSON.stringify(query.has_reference); } + if (query.has_no_reference) { + query.has_no_reference = JSON.stringify(query.has_no_reference); + } // `aggs` is a structured object. we need to stringify it before sending it, as `fetch` // is not doing it implicitly. diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap index 4c21ba704fe48..39ff3c4c5700a 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/__snapshots__/migrations_state_action_machine.test.ts.snap @@ -71,6 +71,11 @@ Object { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", @@ -246,6 +251,11 @@ Object { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", @@ -425,6 +435,11 @@ Object { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", @@ -608,6 +623,11 @@ Object { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", @@ -833,6 +853,11 @@ Object { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", @@ -1019,6 +1044,11 @@ Object { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/unused_types.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/unused_types.ts index 480395241c278..7dbcf2c270ba4 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/unused_types.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/unused_types.ts @@ -22,6 +22,8 @@ export const REMOVED_TYPES: string[] = [ 'fleet-agents', 'fleet-agent-actions', 'fleet-enrollment-api-keys', + // replaced by guided-onboarding-guide-state in 8.6 + 'guided-setup-state', // Was removed in 7.12 'ml-telemetry', 'server', diff --git a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts index 2b0e9a7c7f1a4..d1c19aa7d212e 100644 --- a/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts +++ b/packages/core/saved-objects/core-saved-objects-migration-server-internal/src/initial_state.test.ts @@ -107,6 +107,11 @@ describe('createInitialState', () => { "type": "fleet-enrollment-api-keys", }, }, + Object { + "term": Object { + "type": "guided-setup-state", + }, + }, Object { "term": Object { "type": "ml-telemetry", diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts index 4587cb1ebeb09..983b31caf7a2b 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/find.ts @@ -45,6 +45,10 @@ export const registerFindRoute = ( schema.oneOf([referenceSchema, schema.arrayOf(referenceSchema)]) ), has_reference_operator: searchOperatorSchema, + has_no_reference: schema.maybe( + schema.oneOf([referenceSchema, schema.arrayOf(referenceSchema)]) + ), + has_no_reference_operator: searchOperatorSchema, fields: schema.maybe(schema.oneOf([schema.string(), schema.arrayOf(schema.string())])), filter: schema.maybe(schema.string()), aggs: schema.maybe(schema.string()), @@ -88,6 +92,8 @@ export const registerFindRoute = ( sortField: query.sort_field, hasReference: query.has_reference, hasReferenceOperator: query.has_reference_operator, + hasNoReference: query.has_no_reference, + hasNoReferenceOperator: query.has_no_reference_operator, fields: typeof query.fields === 'string' ? [query.fields] : query.fields, filter: query.filter, aggs, diff --git a/packages/core/status/core-status-server-internal/src/routes/status.ts b/packages/core/status/core-status-server-internal/src/routes/status.ts index 34a5a9b4dcd20..199f55159a7c6 100644 --- a/packages/core/status/core-status-server-internal/src/routes/status.ts +++ b/packages/core/status/core-status-server-internal/src/routes/status.ts @@ -135,6 +135,7 @@ export const registerStatusRoute = ({ ...lastMetrics.requests, status_codes: lastMetrics.requests.statusCodes, }, + elasticsearch_client: lastMetrics.elasticsearch_client, }, }; diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/BUILD.bazel b/packages/core/test-helpers/core-test-helpers-so-type-serializer/BUILD.bazel new file mode 100644 index 0000000000000..714250a907fb4 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/BUILD.bazel @@ -0,0 +1,111 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_config") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project") + +PKG_DIRNAME = "core-test-helpers-so-type-serializer" +PKG_REQUIRE_NAME = "@kbn/core-test-helpers-so-type-serializer" + +SOURCE_FILES = glob( + [ + "**/*.ts", + ], + exclude = [ + "**/*.config.js", + "**/*.mock.*", + "**/*.test.*", + "**/*.stories.*", + "**/__snapshots__/**", + "**/integration_tests/**", + "**/mocks/**", + "**/scripts/**", + "**/storybook/**", + "**/test_fixtures/**", + "**/test_helpers/**", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", +] + +RUNTIME_DEPS = [ + "@npm//semver", + "//packages/kbn-std", +] + +TYPES_DEPS = [ + "@npm//@types/node", + "@npm//@types/jest", + "@npm//@types/semver", + "//packages/kbn-std:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-common:npm_module_types", + "//packages/core/saved-objects/core-saved-objects-server:npm_module_types", +] + +jsts_transpiler( + name = "target_node", + srcs = SRCS, + build_pkg_name = package_name(), +) + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + "//:tsconfig.bazel.json", + ], +) + +ts_project( + name = "tsc_types", + args = ['--pretty'], + srcs = SRCS, + deps = TYPES_DEPS, + declaration = True, + declaration_map = True, + emit_declaration_only = True, + out_dir = "target_types", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_DIRNAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = RUNTIME_DEPS + [":target_node"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [":" + PKG_DIRNAME], +) + +filegroup( + name = "build", + srcs = [":npm_module"], + visibility = ["//visibility:public"], +) + +pkg_npm_types( + name = "npm_module_types", + srcs = SRCS, + deps = [":tsc_types"], + package_name = PKG_REQUIRE_NAME, + tsconfig = ":tsconfig", + visibility = ["//visibility:public"], +) + +filegroup( + name = "build_types", + srcs = [":npm_module_types"], + visibility = ["//visibility:public"], +) diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/README.md b/packages/core/test-helpers/core-test-helpers-so-type-serializer/README.md new file mode 100644 index 0000000000000..d562272b96499 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/README.md @@ -0,0 +1,3 @@ +# @kbn/core-test-helpers-so-type-serializer + +Utility package for savedObjects integration tests. diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/index.ts b/packages/core/test-helpers/core-test-helpers-so-type-serializer/index.ts new file mode 100644 index 0000000000000..100acc28a2001 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { SavedObjectTypeMigrationInfo } from './src/extract_migration_info'; +export { extractMigrationInfo } from './src/extract_migration_info'; +export { getMigrationHash } from './src/get_migration_hash'; diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/jest.config.js b/packages/core/test-helpers/core-test-helpers-so-type-serializer/jest.config.js new file mode 100644 index 0000000000000..66287aba24c22 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../..', + roots: ['/packages/core/test-helpers/core-test-helpers-so-type-serializer'], +}; diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/kibana.jsonc b/packages/core/test-helpers/core-test-helpers-so-type-serializer/kibana.jsonc new file mode 100644 index 0000000000000..4a4a765bbc519 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/kibana.jsonc @@ -0,0 +1,7 @@ +{ + "type": "shared-common", + "id": "@kbn/core-test-helpers-so-type-serializer", + "owner": "@elastic/kibana-core", + "runtimeDeps": [], + "typeDeps": [], +} diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/package.json b/packages/core/test-helpers/core-test-helpers-so-type-serializer/package.json new file mode 100644 index 0000000000000..95de844e70ed9 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/core-test-helpers-so-type-serializer", + "private": true, + "version": "1.0.0", + "main": "./target_node/index.js", + "author": "Kibana Core", + "license": "SSPL-1.0 OR Elastic License 2.0" +} diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/extract_migration_info.test.ts b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/extract_migration_info.test.ts new file mode 100644 index 0000000000000..47620aee90b3c --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/extract_migration_info.test.ts @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema } from '@kbn/config-schema'; +import type { SavedObjectsType } from '@kbn/core-saved-objects-server'; +import { extractMigrationInfo } from './extract_migration_info'; + +const createType = (parts: Partial): SavedObjectsType => ({ + name: 'test-type', + hidden: false, + namespaceType: 'multiple', + mappings: { properties: {} }, + ...parts, +}); + +const dummyMigration = jest.fn(); +const dummySchema = schema.object({}); + +describe('extractMigrationInfo', () => { + describe('simple fields', () => { + it('returns the `name` from the SO type', () => { + const type = createType({ name: 'my-type' }); + const output = extractMigrationInfo(type); + expect(output.name).toEqual('my-type'); + }); + + it('returns the `namespaceType` from the SO type', () => { + const type = createType({ namespaceType: 'multiple-isolated' }); + const output = extractMigrationInfo(type); + expect(output.namespaceType).toEqual('multiple-isolated'); + }); + + it('returns the `convertToMultiNamespaceTypeVersion` from the SO type', () => { + const type = createType({ convertToMultiNamespaceTypeVersion: '6.6.6' }); + const output = extractMigrationInfo(type); + expect(output.convertToMultiNamespaceTypeVersion).toEqual('6.6.6'); + }); + + it('returns the `convertToAliasScript` from the SO type', () => { + const type = createType({ convertToAliasScript: 'some_value' }); + const output = extractMigrationInfo(type); + expect(output.convertToAliasScript).toEqual('some_value'); + }); + + it('returns true for `hasExcludeOnUpgrade` if the SO type specifies `excludeOnUpgrade`', () => { + expect( + extractMigrationInfo(createType({ excludeOnUpgrade: jest.fn() })).hasExcludeOnUpgrade + ).toEqual(true); + expect( + extractMigrationInfo(createType({ excludeOnUpgrade: undefined })).hasExcludeOnUpgrade + ).toEqual(false); + }); + }); + + describe('migrations', () => { + it('returns the versions with registered migrations, sorted asc', () => { + const type = createType({ + migrations: { + '8.3.3': dummyMigration, + '7.17.7': dummyMigration, + '8.0.2': dummyMigration, + }, + }); + + const output = extractMigrationInfo(type); + + expect(output.migrationVersions).toEqual(['7.17.7', '8.0.2', '8.3.3']); + }); + + it('supports migration provider functions', () => { + const type = createType({ + migrations: () => ({ + '8.3.3': dummyMigration, + '7.17.7': dummyMigration, + '8.0.2': dummyMigration, + }), + }); + + const output = extractMigrationInfo(type); + + expect(output.migrationVersions).toEqual(['7.17.7', '8.0.2', '8.3.3']); + }); + + it('returns an empty list when migrations are not defined', () => { + const type = createType({ + migrations: undefined, + }); + + const output = extractMigrationInfo(type); + + expect(output.migrationVersions).toEqual([]); + }); + }); + + describe('schemas', () => { + it('returns the versions with registered schemas, sorted asc', () => { + const type = createType({ + schemas: { + '8.3.2': dummySchema, + '7.15.2': dummySchema, + '8.1.2': dummySchema, + }, + }); + + const output = extractMigrationInfo(type); + + expect(output.schemaVersions).toEqual(['7.15.2', '8.1.2', '8.3.2']); + }); + + it('supports schema provider functions', () => { + const type = createType({ + schemas: () => ({ + '8.3.2': dummySchema, + '7.15.2': dummySchema, + '8.1.2': dummySchema, + }), + }); + + const output = extractMigrationInfo(type); + + expect(output.schemaVersions).toEqual(['7.15.2', '8.1.2', '8.3.2']); + }); + + it('returns an empty list when schemas are not defined', () => { + const type = createType({ + schemas: undefined, + }); + + const output = extractMigrationInfo(type); + + expect(output.schemaVersions).toEqual([]); + }); + }); + + describe('mappings', () => { + it('returns a flattened version of the mappings', () => { + const type = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + const output = extractMigrationInfo(type); + expect(output.mappings).toEqual({ + dynamic: false, + 'properties.description.type': 'text', + 'properties.hits.doc_values': false, + 'properties.hits.index': false, + 'properties.hits.type': 'integer', + }); + }); + }); +}); diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/extract_migration_info.ts b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/extract_migration_info.ts new file mode 100644 index 0000000000000..c2f1c0b7aa9a2 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/extract_migration_info.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { compare as semverCompare } from 'semver'; +import { getFlattenedObject } from '@kbn/std'; +import type { SavedObjectsNamespaceType } from '@kbn/core-saved-objects-common'; +import type { SavedObjectsType } from '@kbn/core-saved-objects-server'; + +export interface SavedObjectTypeMigrationInfo { + name: string; + namespaceType: SavedObjectsNamespaceType; + convertToAliasScript?: string; + convertToMultiNamespaceTypeVersion?: string; + migrationVersions: string[]; + schemaVersions: string[]; + mappings: Record; + hasExcludeOnUpgrade: boolean; +} + +/** + * Extract all migration-relevant informations bound to given type in a serializable format. + * + * @param soType + */ +export const extractMigrationInfo = (soType: SavedObjectsType): SavedObjectTypeMigrationInfo => { + const migrationMap = + typeof soType.migrations === 'function' ? soType.migrations() : soType.migrations; + const migrationVersions = Object.keys(migrationMap ?? {}); + migrationVersions.sort(semverCompare); + + const schemaMap = typeof soType.schemas === 'function' ? soType.schemas() : soType.schemas; + const schemaVersions = Object.keys(schemaMap ?? {}); + schemaVersions.sort(semverCompare); + + return { + name: soType.name, + namespaceType: soType.namespaceType, + convertToAliasScript: soType.convertToAliasScript, + convertToMultiNamespaceTypeVersion: soType.convertToMultiNamespaceTypeVersion, + migrationVersions, + schemaVersions, + mappings: getFlattenedObject(soType.mappings ?? {}), + hasExcludeOnUpgrade: !!soType.excludeOnUpgrade, + }; +}; diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/get_migration_hash.test.ts b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/get_migration_hash.test.ts new file mode 100644 index 0000000000000..2ac9e04172e86 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/get_migration_hash.test.ts @@ -0,0 +1,336 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { schema } from '@kbn/config-schema'; +import type { SavedObjectsType } from '@kbn/core-saved-objects-server'; +import { getMigrationHash } from './get_migration_hash'; + +const createType = (parts: Partial = {}): SavedObjectsType => ({ + name: 'test-type', + hidden: false, + namespaceType: 'multiple', + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + ...parts, +}); + +describe('getMigrationHash', () => { + it('returns the same hash for the exact same simple type', () => { + const type = createType(); + expect(getMigrationHash(type)).toEqual(getMigrationHash(type)); + }); + + describe('simple fields', () => { + it('returns different hashes if `name` changes', () => { + expect(getMigrationHash(createType({ name: 'typeA' }))).not.toEqual( + getMigrationHash(createType({ name: 'typeB' })) + ); + }); + it('returns different hashes if `namespaceType` changes', () => { + expect(getMigrationHash(createType({ namespaceType: 'single' }))).not.toEqual( + getMigrationHash(createType({ namespaceType: 'multiple' })) + ); + }); + it('returns different hashes if `convertToMultiNamespaceTypeVersion` changes', () => { + expect( + getMigrationHash(createType({ convertToMultiNamespaceTypeVersion: undefined })) + ).not.toEqual(getMigrationHash(createType({ convertToMultiNamespaceTypeVersion: '6.6.6' }))); + }); + it('returns different hashes if `convertToAliasScript` changes', () => { + expect(getMigrationHash(createType({ convertToAliasScript: undefined }))).not.toEqual( + getMigrationHash(createType({ convertToAliasScript: 'some_script' })) + ); + }); + it('returns different hashes if `excludeOnUpgrade` is defined or not', () => { + expect(getMigrationHash(createType({ excludeOnUpgrade: undefined }))).not.toEqual( + getMigrationHash(createType({ excludeOnUpgrade: jest.fn() })) + ); + }); + }); + + describe('migrations', () => { + it('returns same hash if same migration versions are registered', () => { + const typeA = createType({ + migrations: { + '7.17.1': jest.fn(), + '8.4.2': jest.fn(), + }, + }); + const typeB = createType({ + migrations: { + '7.17.1': jest.fn(), + '8.4.2': jest.fn(), + }, + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns same hash if same migration versions are registered in different order', () => { + const typeA = createType({ + migrations: { + '9.1.3': jest.fn(), + '7.17.1': jest.fn(), + '8.4.2': jest.fn(), + }, + }); + const typeB = createType({ + migrations: { + '8.4.2': jest.fn(), + '9.1.3': jest.fn(), + '7.17.1': jest.fn(), + }, + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns same hash if same migration versions are registered using record + function', () => { + const typeA = createType({ + migrations: { + '9.1.3': jest.fn(), + '7.17.1': jest.fn(), + '8.4.2': jest.fn(), + }, + }); + const typeB = createType({ + migrations: () => ({ + '8.4.2': jest.fn(), + '9.1.3': jest.fn(), + '7.17.1': jest.fn(), + }), + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns different hashes if different migration versions are registered', () => { + const typeA = createType({ + migrations: { + '7.17.1': jest.fn(), + '8.4.2': jest.fn(), + }, + }); + const typeB = createType({ + migrations: { + '7.17.69': jest.fn(), + '42.0.0': jest.fn(), + }, + }); + + expect(getMigrationHash(typeA)).not.toEqual(getMigrationHash(typeB)); + }); + }); + describe('schemas', () => { + it('returns same hash if same schema versions are registered', () => { + const typeA = createType({ + schemas: { + '7.17.1': schema.object({}), + '8.4.2': schema.object({}), + }, + }); + const typeB = createType({ + schemas: { + '7.17.1': schema.object({}), + '8.4.2': schema.object({}), + }, + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns same hash if same schema versions are registered in different order', () => { + const typeA = createType({ + schemas: { + '9.1.3': schema.object({}), + '7.17.1': schema.object({}), + '8.4.2': schema.object({}), + }, + }); + const typeB = createType({ + schemas: { + '8.4.2': schema.object({}), + '9.1.3': schema.object({}), + '7.17.1': schema.object({}), + }, + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns same hash if same schema versions are registered using record + function', () => { + const typeA = createType({ + schemas: { + '9.1.3': schema.object({}), + '7.17.1': schema.object({}), + '8.4.2': schema.object({}), + }, + }); + const typeB = createType({ + schemas: () => ({ + '8.4.2': schema.object({}), + '9.1.3': schema.object({}), + '7.17.1': schema.object({}), + }), + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns different hashes if different schema versions are registered', () => { + const typeA = createType({ + schemas: { + '7.17.1': schema.object({}), + '8.4.2': schema.object({}), + }, + }); + const typeB = createType({ + schemas: { + '7.17.69': schema.object({}), + '42.0.0': schema.object({}), + }, + }); + + expect(getMigrationHash(typeA)).not.toEqual(getMigrationHash(typeB)); + }); + }); + + describe('mappings', () => { + it('returns same hash for the same mappings', () => { + const typeA = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + const typeB = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns same hash for the same mappings in different order', () => { + const typeA = createType({ + mappings: { + dynamic: false, + properties: { + hits: { type: 'integer', index: false, doc_values: false }, + description: { type: 'text' }, + }, + }, + }); + const typeB = createType({ + mappings: { + properties: { + description: { type: 'text' }, + hits: { index: false, type: 'integer', doc_values: false }, + }, + dynamic: false, + }, + }); + + expect(getMigrationHash(typeA)).toEqual(getMigrationHash(typeB)); + }); + + it('returns different hashes for different mappings (removing nested property)', () => { + const typeA = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + const typeB = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', doc_values: false }, + }, + }, + }); + + expect(getMigrationHash(typeA)).not.toEqual(getMigrationHash(typeB)); + }); + + it('returns different hashes for different mappings (adding nested property)', () => { + const typeA = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + const typeB = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text', boost: 42 }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + + expect(getMigrationHash(typeA)).not.toEqual(getMigrationHash(typeB)); + }); + + it('returns different hashes for different mappings (removing top-level property)', () => { + const typeA = createType({ + mappings: { + dynamic: false, + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + const typeB = createType({ + mappings: { + properties: { + description: { type: 'text' }, + hits: { type: 'integer', index: false, doc_values: false }, + }, + }, + }); + + expect(getMigrationHash(typeA)).not.toEqual(getMigrationHash(typeB)); + }); + }); + + describe('ignored fields', () => { + it('returns same hash if `hidden` changes', () => { + expect(getMigrationHash(createType({ hidden: false }))).toEqual( + getMigrationHash(createType({ hidden: true })) + ); + }); + it('returns same hash if `management` changes', () => { + expect(getMigrationHash(createType({ management: undefined }))).toEqual( + getMigrationHash(createType({ management: { visibleInManagement: false } })) + ); + }); + }); +}); diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/get_migration_hash.ts b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/get_migration_hash.ts new file mode 100644 index 0000000000000..7e23ec35bb9e7 --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/src/get_migration_hash.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 { createHash } from 'crypto'; +import type { SavedObjectsType } from '@kbn/core-saved-objects-server'; +import { extractMigrationInfo } from './extract_migration_info'; + +type SavedObjectTypeMigrationHash = string; + +export const getMigrationHash = (soType: SavedObjectsType): SavedObjectTypeMigrationHash => { + const migInfo = extractMigrationInfo(soType); + + const hash = createHash('sha1'); + + const hashParts = [ + migInfo.name, + migInfo.namespaceType, + migInfo.convertToAliasScript ?? 'none', + migInfo.hasExcludeOnUpgrade, + migInfo.convertToMultiNamespaceTypeVersion ?? 'none', + migInfo.migrationVersions.join(','), + migInfo.schemaVersions.join(','), + JSON.stringify(migInfo.mappings, Object.keys(migInfo.mappings).sort()), + ]; + const hashFeed = hashParts.join('-'); + + return hash.update(hashFeed).digest('hex'); +}; diff --git a/packages/core/test-helpers/core-test-helpers-so-type-serializer/tsconfig.json b/packages/core/test-helpers/core-test-helpers-so-type-serializer/tsconfig.json new file mode 100644 index 0000000000000..71bb40fe57f3f --- /dev/null +++ b/packages/core/test-helpers/core-test-helpers-so-type-serializer/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../../../tsconfig.bazel.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "target_types", + "stripInternal": false, + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ] +} diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 3a0b89c1f0d1b..b7a3326942582 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -130,6 +130,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { crawlerGettingStarted: `${ENTERPRISE_SEARCH_DOCS}crawler-getting-started.html`, crawlerManaging: `${ENTERPRISE_SEARCH_DOCS}crawler-managing.html`, crawlerOverview: `${ENTERPRISE_SEARCH_DOCS}crawler.html`, + deployTrainedModels: `${MACHINE_LEARNING_DOCS}ml-nlp-deploy-models.html`, documentLevelSecurity: `${ELASTICSEARCH_DOCS}document-level-security.html`, ingestPipelines: `${ENTERPRISE_SEARCH_DOCS}ingest-pipelines.html`, languageAnalyzers: `${ELASTICSEARCH_DOCS}analysis-lang-analyzer.html`, @@ -363,6 +364,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { eventFilters: `${SECURITY_SOLUTION_DOCS}event-filters.html`, blocklist: `${SECURITY_SOLUTION_DOCS}blocklist.html`, threatIntelInt: `${SECURITY_SOLUTION_DOCS}es-threat-intel-integrations.html`, + endpointArtifacts: `${SECURITY_SOLUTION_DOCS}endpoint-artifacts.html`, policyResponseTroubleshooting: { full_disk_access: `${SECURITY_SOLUTION_DOCS}deploy-elastic-endpoint.html#enable-fda-endpoint`, macos_system_ext: `${SECURITY_SOLUTION_DOCS}deploy-elastic-endpoint.html#system-extension-endpoint`, @@ -373,6 +375,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { es_connection: '', }, responseActions: `${SECURITY_SOLUTION_DOCS}response-actions.html`, + configureEndpointIntegrationPolicy: `${SECURITY_SOLUTION_DOCS}configure-endpoint-integration-policy.html`, }, query: { eql: `${ELASTICSEARCH_DOCS}eql.html`, @@ -456,6 +459,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { userExperience: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/user-experience.html`, createAlerts: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/create-alerts.html`, syntheticsCommandReference: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/synthetics-configuration.html#synthetics-configuration-playwright-options`, + syntheticsProjectMonitors: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/synthetic-run-tests.html#synthetic-monitor-choose-project`, }, alerting: { guide: `${KIBANA_DOCS}create-and-manage-rules.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 7cd785ee194fa..16a80e7f7bf33 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -115,6 +115,7 @@ export interface DocLinks { readonly crawlerGettingStarted: string; readonly crawlerManaging: string; readonly crawlerOverview: string; + readonly deployTrainedModels: string; readonly documentLevelSecurity: string; readonly ingestPipelines: string; readonly languageAnalyzers: string; @@ -265,6 +266,7 @@ export interface DocLinks { readonly trustedApps: string; readonly eventFilters: string; readonly blocklist: string; + readonly endpointArtifacts: string; readonly policyResponseTroubleshooting: { full_disk_access: string; macos_system_ext: string; @@ -275,6 +277,7 @@ export interface DocLinks { }; readonly threatIntelInt: string; readonly responseActions: string; + readonly configureEndpointIntegrationPolicy: string; }; readonly query: { readonly eql: string; @@ -338,6 +341,7 @@ export interface DocLinks { userExperience: string; createAlerts: string; syntheticsCommandReference: string; + syntheticsProjectMonitors: string; }>; readonly alerting: Record; readonly maps: Readonly<{ diff --git a/packages/kbn-es-query/index.ts b/packages/kbn-es-query/index.ts index 7495d37fc990c..62107ad373277 100644 --- a/packages/kbn-es-query/index.ts +++ b/packages/kbn-es-query/index.ts @@ -67,6 +67,7 @@ export { buildEmptyFilter, buildExistsFilter, buildFilter, + buildOrFilter, buildPhraseFilter, buildPhrasesFilter, buildQueryFilter, @@ -89,6 +90,7 @@ export { isFilterPinned, isFilters, isMatchAllFilter, + isOrFilter, isPhraseFilter, isPhrasesFilter, isQueryStringFilter, diff --git a/packages/kbn-es-query/src/es_query/from_filters.ts b/packages/kbn-es-query/src/es_query/from_filters.ts index 2200648a52c4f..efeb8dd87ee6c 100644 --- a/packages/kbn-es-query/src/es_query/from_filters.ts +++ b/packages/kbn-es-query/src/es_query/from_filters.ts @@ -13,6 +13,7 @@ import { filterMatchesIndex } from './filter_matches_index'; import { Filter, cleanFilter, isFilterDisabled } from '../filters'; import { BoolQuery, DataViewBase } from './types'; import { handleNestedFilter } from './handle_nested_filter'; +import { handleOrFilter } from './handle_or_filter'; /** * Create a filter that can be reversed for filters with negate set @@ -66,10 +67,11 @@ export interface EsQueryFiltersConfig { export const buildQueryFromFilters = ( inputFilters: Filter[] = [], inputDataViews: DataViewBase | DataViewBase[] | undefined, - { ignoreFilterIfFieldNotInIndex = false, nestedIgnoreUnmapped }: EsQueryFiltersConfig = { + options: EsQueryFiltersConfig = { ignoreFilterIfFieldNotInIndex: false, } ): BoolQuery => { + const { ignoreFilterIfFieldNotInIndex = false, nestedIgnoreUnmapped } = options; const filters = inputFilters.filter((filter) => filter && !isFilterDisabled(filter)); const indexPatterns = Array.isArray(inputDataViews) ? inputDataViews : [inputDataViews]; @@ -92,6 +94,7 @@ export const buildQueryFromFilters = ( ignoreUnmapped: nestedIgnoreUnmapped, }); }) + .map((filter) => handleOrFilter(filter, inputDataViews, options)) .map(cleanFilter) .map(translateToQuery); }; diff --git a/packages/kbn-es-query/src/es_query/handle_or_filter.test.ts b/packages/kbn-es-query/src/es_query/handle_or_filter.test.ts new file mode 100644 index 0000000000000..913d61a378487 --- /dev/null +++ b/packages/kbn-es-query/src/es_query/handle_or_filter.test.ts @@ -0,0 +1,610 @@ +/* + * Copyright 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 { fields } from '../filters/stubs'; +import { DataViewBase } from './types'; +import { handleOrFilter } from './handle_or_filter'; +import { + buildExistsFilter, + buildOrFilter, + buildPhraseFilter, + buildPhrasesFilter, + buildRangeFilter, +} from '../filters'; + +describe('#handleOrFilter', function () { + const indexPattern: DataViewBase = { + id: 'logstash-*', + fields, + title: 'dataView', + }; + + const getField = (fieldName: string) => { + const field = fields.find(({ name }) => fieldName === name); + if (!field) throw new Error(`field ${name} does not exist`); + return field; + }; + + it('Handles an empty list of filters', () => { + const filter = buildOrFilter([]); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [], + }, + } + `); + }); + + it('Handles a simple list of filters', () => { + const filters = [ + buildPhraseFilter(getField('extension'), 'value', indexPattern), + buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern), + buildExistsFilter(getField('machine.os'), indexPattern), + ]; + const filter = buildOrFilter(filters); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "machine.os", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + } + `); + }); + + it('Handles a combination of filters and filter arrays', () => { + const filters = [ + buildPhraseFilter(getField('extension'), 'value', indexPattern), + [ + buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern), + buildExistsFilter(getField('machine.os'), indexPattern), + ], + ]; + const filter = buildOrFilter(filters); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + Object { + "exists": Object { + "field": "machine.os", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + } + `); + }); + + it('Handles nested OR filters', () => { + const nestedOrFilter = buildOrFilter([ + buildPhraseFilter(getField('machine.os'), 'value', indexPattern), + buildPhraseFilter(getField('extension'), 'value', indexPattern), + ]); + const filters = [ + buildPhraseFilter(getField('extension'), 'value2', indexPattern), + nestedOrFilter, + buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern), + buildExistsFilter(getField('machine.os.raw'), indexPattern), + ]; + const filter = buildOrFilter(filters); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value2", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "machine.os": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "machine.os.raw", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + } + `); + }); + + it('Handles negated sub-filters', () => { + const negatedFilter = buildPhrasesFilter(getField('extension'), ['tar', 'gz'], indexPattern); + negatedFilter.meta.negate = true; + + const filters = [ + [negatedFilter, buildPhraseFilter(getField('extension'), 'value', indexPattern)], + buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern), + buildExistsFilter(getField('machine.os'), indexPattern), + ]; + const filter = buildOrFilter(filters); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match_phrase": Object { + "extension": "tar", + }, + }, + Object { + "match_phrase": Object { + "extension": "gz", + }, + }, + ], + }, + }, + ], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "machine.os", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + } + `); + }); + + it('Handles disabled filters within a filter array', () => { + const disabledFilter = buildPhraseFilter(getField('ssl'), false, indexPattern); + disabledFilter.meta.disabled = true; + const filters = [ + buildPhraseFilter(getField('extension'), 'value', indexPattern), + [disabledFilter, buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern)], + buildExistsFilter(getField('machine.os'), indexPattern), + ]; + const filter = buildOrFilter(filters); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "machine.os", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + } + `); + }); + + it('Handles complex-nested filters with ANDs and ORs', () => { + const filters = [ + [ + buildPhrasesFilter(getField('extension'), ['tar', 'gz'], indexPattern), + buildPhraseFilter(getField('ssl'), false, indexPattern), + buildOrFilter([ + buildPhraseFilter(getField('extension'), 'value', indexPattern), + buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern), + ]), + buildExistsFilter(getField('machine.os'), indexPattern), + ], + buildPhrasesFilter(getField('machine.os.keyword'), ['foo', 'bar'], indexPattern), + ]; + const filter = buildOrFilter(filters); + const result = handleOrFilter(filter); + expect(result.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match_phrase": Object { + "extension": "tar", + }, + }, + Object { + "match_phrase": Object { + "extension": "gz", + }, + }, + ], + }, + }, + Object { + "match_phrase": Object { + "ssl": false, + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "match_phrase": Object { + "extension": "value", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + }, + Object { + "exists": Object { + "field": "machine.os", + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match_phrase": Object { + "machine.os.keyword": "foo", + }, + }, + Object { + "match_phrase": Object { + "machine.os.keyword": "bar", + }, + }, + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + ], + }, + } + `); + }); + + it('Preserves filter properties', () => { + const filters = [ + buildPhraseFilter(getField('extension'), 'value', indexPattern), + buildRangeFilter(getField('bytes'), { gte: 10 }, indexPattern), + buildExistsFilter(getField('machine.os'), indexPattern), + ]; + const filter = buildOrFilter(filters); + const { query, ...rest } = handleOrFilter(filter); + expect(rest).toMatchInlineSnapshot(` + Object { + "$state": Object { + "store": "appState", + }, + "meta": Object { + "alias": null, + "disabled": false, + "index": undefined, + "negate": false, + "params": Array [ + Object { + "meta": Object { + "index": "logstash-*", + }, + "query": Object { + "match_phrase": Object { + "extension": "value", + }, + }, + }, + Object { + "meta": Object { + "field": "bytes", + "index": "logstash-*", + "params": Object {}, + }, + "query": Object { + "range": Object { + "bytes": Object { + "gte": 10, + }, + }, + }, + }, + Object { + "meta": Object { + "index": "logstash-*", + }, + "query": Object { + "exists": Object { + "field": "machine.os", + }, + }, + }, + ], + "type": "OR", + }, + } + `); + }); +}); diff --git a/packages/kbn-es-query/src/es_query/handle_or_filter.ts b/packages/kbn-es-query/src/es_query/handle_or_filter.ts new file mode 100644 index 0000000000000..0e74d2981b6fd --- /dev/null +++ b/packages/kbn-es-query/src/es_query/handle_or_filter.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 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 { Filter, FilterItem, isOrFilter } from '../filters'; +import { DataViewBase } from './types'; +import { buildQueryFromFilters, EsQueryFiltersConfig } from './from_filters'; + +/** @internal */ +export const handleOrFilter = ( + filter: Filter, + inputDataViews?: DataViewBase | DataViewBase[], + options: EsQueryFiltersConfig = {} +): Filter => { + if (!isOrFilter(filter)) return filter; + const { params } = filter.meta; + const should = params.map((subFilter) => { + const subFilters = Array.isArray(subFilter) ? subFilter : [subFilter]; + return { bool: buildQueryFromFilters(flattenFilters(subFilters), inputDataViews, options) }; + }); + return { + ...filter, + query: { + bool: { + should, + minimum_should_match: 1, + }, + }, + }; +}; + +function flattenFilters(filters: FilterItem[]): Filter[] { + return filters.reduce((result, filter) => { + if (Array.isArray(filter)) return [...result, ...flattenFilters(filter)]; + return [...result, filter]; + }, []); +} diff --git a/packages/kbn-es-query/src/filters/build_filters/index.ts b/packages/kbn-es-query/src/filters/build_filters/index.ts index d9d4bbb82aeb1..5cde5a32fa317 100644 --- a/packages/kbn-es-query/src/filters/build_filters/index.ts +++ b/packages/kbn-es-query/src/filters/build_filters/index.ts @@ -14,6 +14,7 @@ export * from './exists_filter'; export * from './get_filter_field'; export * from './get_filter_params'; export * from './match_all_filter'; +export * from './or_filter'; export * from './phrase_filter'; export * from './phrases_filter'; export * from './query_string_filter'; diff --git a/packages/kbn-es-query/src/filters/build_filters/or_filter.ts b/packages/kbn-es-query/src/filters/build_filters/or_filter.ts new file mode 100644 index 0000000000000..e9f1bcb54a6a4 --- /dev/null +++ b/packages/kbn-es-query/src/filters/build_filters/or_filter.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 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 { Filter, FilterMeta, FILTERS } from './types'; +import { buildEmptyFilter } from './build_empty_filter'; + +/** + * Each item in an OR filter may represent either one filter (to be ORed) or an array of filters (ANDed together before + * becoming part of the OR clause). + * @public + */ +export type FilterItem = Filter | FilterItem[]; + +/** + * @public + */ +export interface OrFilterMeta extends FilterMeta { + type: typeof FILTERS.OR; + params: FilterItem[]; +} + +/** + * @public + */ +export interface OrFilter extends Filter { + meta: OrFilterMeta; +} + +/** + * @public + */ +export function isOrFilter(filter: Filter): filter is OrFilter { + return filter?.meta?.type === FILTERS.OR; +} + +/** + * Builds an OR filter. An OR filter is a filter with multiple sub-filters. Each sub-filter (FilterItem) represents a + * condition. + * @param filters An array of OrFilterItem + * @public + */ +export function buildOrFilter(filters: FilterItem[]): OrFilter { + const filter = buildEmptyFilter(false); + return { + ...filter, + meta: { + ...filter.meta, + type: FILTERS.OR, + params: filters, + }, + }; +} diff --git a/packages/kbn-es-query/src/filters/build_filters/types.ts b/packages/kbn-es-query/src/filters/build_filters/types.ts index 5e920d11bcab5..03f4556537be4 100644 --- a/packages/kbn-es-query/src/filters/build_filters/types.ts +++ b/packages/kbn-es-query/src/filters/build_filters/types.ts @@ -37,6 +37,7 @@ export enum FILTERS { RANGE = 'range', RANGE_FROM_VALUE = 'range_from_value', SPATIAL_FILTER = 'spatial_filter', + OR = 'OR', } /** diff --git a/packages/kbn-es-query/src/filters/index.ts b/packages/kbn-es-query/src/filters/index.ts index 820559d5f9069..1031db2593075 100644 --- a/packages/kbn-es-query/src/filters/index.ts +++ b/packages/kbn-es-query/src/filters/index.ts @@ -34,6 +34,8 @@ export { export { isExistsFilter, isMatchAllFilter, + buildOrFilter, + isOrFilter, isPhraseFilter, isPhrasesFilter, isRangeFilter, @@ -75,6 +77,9 @@ export type { CustomFilter, RangeFilterParams, QueryStringFilter, + OrFilter, + OrFilterMeta, + FilterItem, } from './build_filters'; export { FilterStateStore, FILTERS } from './build_filters/types'; diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 5cd1458028626..67064af8cddc5 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -10,7 +10,10 @@ pageLoadAssetSize: cases: 144442 charts: 55000 cloud: 21076 + cloudChat: 19894 cloudExperiments: 59358 + cloudFullStory: 18493 + cloudLinks: 17629 cloudSecurityPosture: 19109 console: 46091 controls: 40000 diff --git a/packages/kbn-rule-data-utils/src/technical_field_names.ts b/packages/kbn-rule-data-utils/src/technical_field_names.ts index e6b6494e68a56..672c25d4e8fab 100644 --- a/packages/kbn-rule-data-utils/src/technical_field_names.ts +++ b/packages/kbn-rule-data-utils/src/technical_field_names.ts @@ -34,6 +34,7 @@ const ALERT_REASON = `${ALERT_NAMESPACE}.reason` as const; const ALERT_RISK_SCORE = `${ALERT_NAMESPACE}.risk_score` as const; const ALERT_SEVERITY = `${ALERT_NAMESPACE}.severity` as const; const ALERT_START = `${ALERT_NAMESPACE}.start` as const; +const ALERT_TIME_RANGE = `${ALERT_NAMESPACE}.time_range` as const; const ALERT_STATUS = `${ALERT_NAMESPACE}.status` as const; const ALERT_SYSTEM_STATUS = `${ALERT_NAMESPACE}.system_status` as const; const ALERT_UUID = `${ALERT_NAMESPACE}.uuid` as const; @@ -126,6 +127,7 @@ const fields = { ALERT_RULE_UPDATED_BY, ALERT_RULE_VERSION, ALERT_START, + ALERT_TIME_RANGE, ALERT_SEVERITY, ALERT_STATUS, ALERT_SYSTEM_STATUS, @@ -183,6 +185,7 @@ export { ALERT_RULE_VERSION, ALERT_SEVERITY, ALERT_START, + ALERT_TIME_RANGE, ALERT_SYSTEM_STATUS, ALERT_UUID, ECS_VERSION, diff --git a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts index adbffa3c728ef..6f4bc7d51052f 100644 --- a/packages/kbn-securitysolution-list-utils/src/helpers/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/helpers/index.ts @@ -138,13 +138,13 @@ export const getNewExceptionItem = ({ namespaceType, ruleName, }: { - listId: string; - namespaceType: NamespaceType; + listId: string | undefined; + namespaceType: NamespaceType | undefined; ruleName: string; }): CreateExceptionListItemBuilderSchema => { return { comments: [], - description: `${ruleName} - exception list item`, + description: 'Exception list item', entries: addIdToEntries([ { field: '', diff --git a/packages/kbn-securitysolution-list-utils/src/types/index.ts b/packages/kbn-securitysolution-list-utils/src/types/index.ts index 24de9d1b1d756..13b62fac657a2 100644 --- a/packages/kbn-securitysolution-list-utils/src/types/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/types/index.ts @@ -9,6 +9,7 @@ import { DataViewFieldBase } from '@kbn/es-query'; import type { CreateExceptionListItemSchema, + CreateRuleExceptionListItemSchema, Entry, EntryExists, EntryMatch, @@ -18,6 +19,7 @@ import type { ExceptionListItemSchema, ListOperatorEnum as OperatorEnum, ListOperatorTypeEnum as OperatorTypeEnum, + NamespaceType, } from '@kbn/securitysolution-io-ts-list-types'; import { EXCEPTION_LIST_NAMESPACE, @@ -93,16 +95,23 @@ export type ExceptionListItemBuilderSchema = Omit & { meta: { temporaryUuid: string }; entries: BuilderEntry[]; + list_id: string | undefined; + namespace_type: NamespaceType | undefined; }; export type ExceptionsBuilderExceptionItem = | ExceptionListItemBuilderSchema | CreateExceptionListItemBuilderSchema; +export type ExceptionsBuilderReturnExceptionItem = + | ExceptionListItemSchema + | CreateExceptionListItemSchema + | CreateRuleExceptionListItemSchema; + export const exceptionListSavedObjectType = EXCEPTION_LIST_NAMESPACE; export const exceptionListAgnosticSavedObjectType = EXCEPTION_LIST_NAMESPACE_AGNOSTIC; export type SavedObjectType = diff --git a/packages/kbn-tinymath/src/functions/defaults.js b/packages/kbn-tinymath/src/functions/defaults.js new file mode 100644 index 0000000000000..4f2d276626d9e --- /dev/null +++ b/packages/kbn-tinymath/src/functions/defaults.js @@ -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 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. + */ + +/** + * Returns the default provided value when the first value if null. If at least one array is passed into the function, the function will be applied index-wise to each element. + * @param {(any|any[])} a array of any values + * @param {(any)} b a value to use as fallback. + * @return {(any|any[])} The `a` value if not null, `b` otherwise. Returns an array where each element is default to `b` when null, or kept the original value if `a` is an array. + * + * @example + * defaults(null, 1) // returns 1 + * defaults([3, null, 5], 1) // returns [3, 1, 5] + * defaults(5, 1) // returns 5 + */ + +module.exports = { defaults }; + +function defaults(a, b) { + if (Array.isArray(a)) { + return a.map((v) => (v == null ? b : v)); + } + return a == null ? b : a; +} + +defaults.skipNumberValidation = true; diff --git a/packages/kbn-tinymath/src/functions/index.js b/packages/kbn-tinymath/src/functions/index.js index eb58a4d56b569..37c2a13c41cf4 100644 --- a/packages/kbn-tinymath/src/functions/index.js +++ b/packages/kbn-tinymath/src/functions/index.js @@ -14,6 +14,7 @@ const { clamp } = require('./clamp'); const { cos } = require('./cos'); const { count } = require('./count'); const { cube } = require('./cube'); +const { defaults } = require('./defaults'); const { degtorad } = require('./degtorad'); const { divide } = require('./divide'); const { exp } = require('./exp'); @@ -56,6 +57,7 @@ module.exports = { count, cube, degtorad, + defaults, divide, exp, first, diff --git a/packages/kbn-tinymath/test/functions/defaults.test.js b/packages/kbn-tinymath/test/functions/defaults.test.js new file mode 100644 index 0000000000000..4490ba6787f29 --- /dev/null +++ b/packages/kbn-tinymath/test/functions/defaults.test.js @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +const { defaults } = require('../../src/functions/defaults'); + +describe('Defaults', () => { + it('number, number', () => { + expect(defaults(10, 2)).toEqual(10); + }); + + it('null, number', () => { + expect(defaults(null, 2)).toEqual(2); + }); + + it('number, null', () => { + expect(defaults(2, null)).toEqual(2); + }); + + it('array, number', () => { + expect(defaults([10, 20, 30, 40], 10)).toEqual([10, 20, 30, 40]); + }); + + it('arrays with null, number', () => { + expect(defaults([null, 20, 30, null], 10)).toEqual([10, 20, 30, 10]); + }); + + it('empty array, number', () => { + expect(defaults([], 10)).toEqual([]); + }); + + it('skips number validation', () => { + expect(defaults).toHaveProperty('skipNumberValidation', true); + }); +}); diff --git a/renovate.json b/renovate.json index 4075b2452bea1..bdaf373932fa1 100644 --- a/renovate.json +++ b/renovate.json @@ -210,7 +210,7 @@ }, { "groupName": "Profiling", - "matchPackageNames": ["fnv-plus", "peggy", "@types/dagre", "@types/fnv-plus"], + "matchPackageNames": ["peggy", "@types/dagre"], "reviewers": ["team:profiling-ui"], "matchBaseBranches": ["main"], "labels": ["release_note:skip", "backport:skip"], diff --git a/src/cli_setup/utils.ts b/src/cli_setup/utils.ts index 5c66fa84c0f30..47b8199f16ea0 100644 --- a/src/cli_setup/utils.ts +++ b/src/cli_setup/utils.ts @@ -48,7 +48,7 @@ export const elasticsearch = new ElasticsearchService(logger, kibanaPackageJson. logger, type, // we use an independent AgentManager for cli_setup, no need to track performance of this one - agentManager: new AgentManager(), + agentFactoryProvider: new AgentManager(), kibanaVersion: kibanaPackageJson.version, }); }, diff --git a/src/core/server/core_app/core_app.test.ts b/src/core/server/core_app/core_app.test.ts index 76663eeed2fd1..1ea3eeef29a09 100644 --- a/src/core/server/core_app/core_app.test.ts +++ b/src/core/server/core_app/core_app.test.ts @@ -12,7 +12,7 @@ import { mockCoreContext } from '@kbn/core-base-server-mocks'; import { mockRouter } from '@kbn/core-http-router-server-mocks'; import type { UiPlugins } from '@kbn/core-plugins-base-server-internal'; import { coreMock, httpServerMock } from '../mocks'; -import { httpResourcesMock } from '../http_resources/http_resources_service.mock'; +import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; import { PluginType } from '../plugins'; import { CoreApp } from './core_app'; import { RequestHandlerContext } from '..'; diff --git a/src/core/server/core_app/core_app.ts b/src/core/server/core_app/core_app.ts index b8701d7646b7e..f0940f6abad50 100644 --- a/src/core/server/core_app/core_app.ts +++ b/src/core/server/core_app/core_app.ts @@ -21,7 +21,7 @@ import type { IBasePath, } from '@kbn/core-http-server'; import type { UiPlugins } from '@kbn/core-plugins-base-server-internal'; -import { HttpResources, HttpResourcesServiceToolkit } from '../http_resources'; +import type { HttpResources, HttpResourcesServiceToolkit } from '@kbn/core-http-resources-server'; import { InternalCorePreboot, InternalCoreSetup } from '../internal_types'; import { registerBundleRoutes } from './bundle_routes'; import type { InternalCoreAppRequestHandlerContext } from './internal_types'; diff --git a/src/core/server/docs/kib_core_reviewing_so_type_pr.mdx b/src/core/server/docs/kib_core_reviewing_so_type_pr.mdx new file mode 100644 index 0000000000000..95dc466109543 --- /dev/null +++ b/src/core/server/docs/kib_core_reviewing_so_type_pr.mdx @@ -0,0 +1,84 @@ +--- +id: kibCoreReviewingSoPr +slug: /kibana-dev-docs/review/reviewing-so-pr +title: Reviewing SavedObject PRs +description: How to review PRs that changes savedObjects registration +date: 2022-09-30 +tags: ['kibana','dev', 'contributor', 'api docs'] +--- + +# Reviewing PRs that change Saved Object types + +## How does automatic review assignment work when SO types are changed? + +PRs modifying / adding / deleting any SO type registration will be flagged by the integration +test located at `src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts`. + +This test will fail any time a change is performed on an SO type registration that could risk having an impact on +upgrades/migrations, and will force the PR's author to update the test's snapshot, which will trigger a review +from the Core team. + +## What and how to review? + +Reviews will be triggered when one, or more, of these scenarios occur: +- a new type was added (registered) +- a type was removed (is no longer registered) +- a new migration function was added +- a mapping change was performed +- a new validation schema was added +- an `excludeOnUpgrade` function was added or removed + +Note: reviews will **not** automatically be triggered in these scenarios: +- an existing migration function is changed +- an existing validation schema is changed +- an existing `excludeOnUpgrade` function is changed + +### A new type was added + +We have another integration test detecting this scenario (`src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts`) + +In that scenario, we should: +- check the initial mappings of the type to spot potential issues: + - fields being defined explicitly in the mappings but not directly used for search + - overall amount of fields is high + - use of `dynamic: true` (this can lead to mapping explosions) +- check if the type is registered as `hidden: true` and encourage to do so otherwise. + - this avoids polluting the global SO HTTP APIs with another type, and instead requires plugin developers to build + their own HTTP APIs to access this type of SO if they truly need to. + +### A type was removed + +The integration test mentioned in the previous section also detects those scenarios. + +Here, we need to check: +- that `REMOVED_TYPES` (`packages/core/saved-objects/core-saved-objects-migration-server-internal/src/core/unused_types.ts`) was properly updated + - (but, again, the integration test will fail otherwise) +- that no other existing SO types may be referencing this type + - can't really be automated, will likely need to ask the owning team directly + +### A new migration function was added + +- Review the migration function + - owners are supposed to do it, but an additional review never hurts + - make sure they are typing their migration function using `SavedObjectMigrationFn` and supplying arguments for the generics + e.g. `SavedObjectMigrationFn`. +- Make sure that the migration function is properly tested + - by unit tests + - and, ideally, by integration tests using 'real' data +- If the migration function is moving/creating/deleting/mutating fields, make sure that the type's mappings and/or schemas were updated accordingly +- Please refer to [the migration section of our testing docs](https://github.com/elastic/kibana/blob/main/dev_docs/tutorials/testing_plugins.mdx#L796) for more details + +### A mapping change was performed + +- Make sure a migration function was added to reflect the changes: + - If a field was removed, ensure the migration function always removes the field from all documents + - If a field type was changed from e.g. `text` to `long`, make sure the migration function guarantees that all documents have compatible fields + - If a text type was changed to a keyword, make sure the text won't exceed Elasticsearch's 32k keyword length limit by e.g. specifying: `ignore_above: 256` +- If the migration function is present, refer to previous section. +- If the type is registering validation schemas, make sure a new schema was added reflecting the changes to the model. + +### A new validation schema was added + +- Make sure the associated mapping changes were performed, and that a migration function was added accordingly. +- Ideally schemas are validated with unit tests as well, especially for more complex ones. +- Refer to prior sections to see what to check. \ No newline at end of file diff --git a/src/core/server/index.ts b/src/core/server/index.ts index dafd53e374fe8..6232a17eb6111 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -69,7 +69,7 @@ import type { I18nServiceSetup } from '@kbn/core-i18n-server'; import type { StatusServiceSetup } from '@kbn/core-status-server'; import type { UiSettingsServiceSetup, UiSettingsServiceStart } from '@kbn/core-ui-settings-server'; import type { RequestHandlerContext } from '@kbn/core-http-request-handler-context-server'; -import { HttpResources } from './http_resources'; +import type { HttpResources } from '@kbn/core-http-resources-server'; import { PluginsServiceSetup, PluginsServiceStart } from './plugins'; export type { PluginOpaqueId } from '@kbn/core-base-common'; @@ -228,7 +228,7 @@ export type { HttpResourcesResponseOptions, HttpResourcesServiceToolkit, HttpResourcesRequestHandler, -} from './http_resources'; +} from '@kbn/core-http-resources-server'; export type { LoggingServiceSetup, diff --git a/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts b/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts new file mode 100644 index 0000000000000..d7704db87476f --- /dev/null +++ b/src/core/server/integration_tests/saved_objects/migrations/check_registered_types.test.ts @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { ISavedObjectTypeRegistry } from '@kbn/core-saved-objects-server'; +import { getMigrationHash } from '@kbn/core-test-helpers-so-type-serializer'; +import { Root } from '../../../root'; +import * as kbnTestServer from '../../../../test_helpers/kbn_server'; + +describe('checking migration metadata changes on all registered SO types', () => { + let esServer: kbnTestServer.TestElasticsearchUtils; + let root: Root; + let typeRegistry: ISavedObjectTypeRegistry; + + beforeAll(async () => { + const { startES } = kbnTestServer.createTestServers({ + adjustTimeout: (t: number) => jest.setTimeout(t), + }); + + esServer = await startES(); + root = kbnTestServer.createRootWithCorePlugins({}, { oss: false }); + await root.preboot(); + await root.setup(); + const coreStart = await root.start(); + typeRegistry = coreStart.savedObjects.getTypeRegistry(); + }); + + afterAll(async () => { + if (root) { + await root.shutdown(); + } + if (esServer) { + await esServer.stop(); + } + }); + + // This test is meant to fail when any change is made in registered types that could potentially impact the SO migration. + // Just update the snapshot by running this test file via jest_integration with `-u` and push the update. + // The intent is to trigger a code review from the Core team to review the SO type changes. + it('detecting migration related changes in registered types', () => { + const allTypes = typeRegistry.getAllTypes(); + + const hashMap = allTypes.reduce((map, type) => { + map[type.name] = getMigrationHash(type); + return map; + }, {} as Record); + + expect(hashMap).toMatchInlineSnapshot(` + Object { + "action": "7858e6d5a9f231bf23f6f2e57328eb0095b26735", + "action_task_params": "bbd38cbfd74bf6713586fe078e3fa92db2234299", + "alert": "48461f3375d9ba22882ea23a318b62a5b0921a9b", + "api_key_pending_invalidation": "9b4bc1235337da9a87ef05a1d1f4858b2a3b77c6", + "apm-indices": "ceb0870f3a74e2ffc3a1cd3a3c73af76baca0999", + "apm-server-schema": "2bfd2998d3873872e1366458ce553def85418f91", + "apm-service-group": "07ecbf25ee4828d2b686abc98656b6665831d1a0", + "apm-telemetry": "abaa1e9469e6e0bad76938309f0ac4c66b528d58", + "app_search_telemetry": "7fc4fc08852bf0924ee29942bb394fda9aa8954d", + "application_usage_daily": "6e645e0b60ef3af2e8fde80963c2a4f09a190d61", + "application_usage_totals": "b2af3577dcd50bfae492b166a7804f69e2cc41dc", + "canvas-element": "5f32b99ba6ff9c1f17cc093591b975be65a27b9b", + "canvas-workpad": "b60252414fb6159a14f9febf98dbe41e5a8bf199", + "canvas-workpad-template": "c371cad0a8d61385f4782cab9a9063d3cf241ee0", + "cases": "7ff5ce930146a2d6fc8fbf536ce2ee16e9df296f", + "cases-comments": "8cfbad4ede637305eb6fb79db680f03dc0ce5ec4", + "cases-configure": "1afc414f5563a36e4612fa269193d3ed7277c7bd", + "cases-connector-mappings": "4b16d440af966e5d6e0fa33368bfa15d987a4b69", + "cases-telemetry": "16e261e7378a72acd0806f18df92525dd1da4f37", + "cases-user-actions": "3973dfcaacbe6ae147d7331699cfc25d2a27ca30", + "config": "e3f0408976dbdd453641f5699927b28b188f6b8c", + "connector_token": "fa5301aa5a2914795d3b1b82d0a49939444009da", + "core-usage-stats": "f40a213da2c597b0de94e364a4326a5a1baa4ca9", + "csp-rule-template": "3679c5f2431da8153878db79c78a4e695357fb61", + "csp_rule": "d2bb53ea5d2bdfba1a835ad8956dfcd2b2c32e19", + "dashboard": "0b0842b6aa40c125d64233fd81cee11080580dc2", + "endpoint:user-artifact": "f94c250a52b30d0a2d32635f8b4c5bdabd1e25c0", + "endpoint:user-artifact-manifest": "8c14d49a385d5d1307d956aa743ec78de0b2be88", + "enterprise_search_telemetry": "fafcc8318528d34f721c42d1270787c52565bad5", + "epm-packages": "c4c39f20d6bcfff40994813ee0f2bab01d34b646", + "epm-packages-assets": "9fd3d6726ac77369249e9a973902c2cd615fc771", + "event_loop_delays_daily": "d2ed39cf669577d90921c176499908b4943fb7bd", + "exception-list": "fe8cc004fd2742177cdb9300f4a67689463faf9c", + "exception-list-agnostic": "49fae8fcd1967cc4be45ba2a2c66c4afbc1e341b", + "file": "280f28bd48b3ad1f1a9f84c6c0ae6dd5ed1179da", + "file-upload-usage-collection-telemetry": "8478924cf0057bd90df737155b364f98d05420a5", + "fileShare": "3f88784b041bb8728a7f40763a08981828799a75", + "fleet-preconfiguration-deletion-record": "7b28f200513c28ae774f1b7d7d7906954e3c6e16", + "graph-workspace": "3342f2cd561afdde8f42f5fb284bf550dee8ebb5", + "guided-onboarding-guide-state": "561db8d481b131a2bbf46b1e534d6ce960255135", + "index-pattern": "48e77ca393c254e93256f11a7cdc0232dd754c08", + "infrastructure-monitoring-log-view": "e2c78c1076bd35e57d7c5fa1b410e5c126d12327", + "infrastructure-ui-source": "7c8dbbc0a608911f1b683a944f4a65383f6153ed", + "ingest-agent-policies": "5d728f483dc3b14dcfa6bbad95c2024d2da68890", + "ingest-download-sources": "1e69dabd6db5e320fe08c5bda8f35f29bafc6b54", + "ingest-outputs": "29b867bf7bfd28b1e17c84697dce5c6d078f9705", + "ingest-package-policies": "e8707a8c7821ea085e67c2d213e24efa56307393", + "ingest_manager_settings": "bb71f20e36a9ac3a2e46d9345e2caa96e7bf8c22", + "inventory-view": "bc2bd1e7ec7c186159447ab228d269f22bd39056", + "kql-telemetry": "29544cd7d3b767c5399878efae6bd724d24c03fd", + "legacy-url-alias": "7172dfd54f2e0c89fe263fd7095519b2d826a930", + "lens": "08769c789ad6d1b8a4d0cffebc9d9bb08bf01ad9", + "lens-ui-telemetry": "df2844565c9e18fed2bdb1f6cc3aadd58cf1e45b", + "map": "00ca6c4cf46ae59f70f1436262eb9f457b45eb14", + "maps-telemetry": "5adbde35bd50ec2b8e9ea5b96d4d9f886e31ecfb", + "metrics-explorer-view": "09e56993352b8ee678e88f71e4410d9aeee72f3a", + "ml-job": "2836da98a81bd220db61c0549e8e28da7a876cb2", + "ml-module": "95055522c8406afa67a554690a43506f6c040744", + "ml-trained-model": "e39dd10b2da827e194ddcaaf3db141ad1daf0201", + "monitoring-telemetry": "af508cea8e22edaa909e462069390650fbbf01b7", + "osquery-manager-usage-metric": "fbe3cbea25a96e2ca522ca436878e0162c94dcc2", + "osquery-pack": "afb3b46c5e23fc24ad438e9c4317ff37e4e5164a", + "osquery-pack-asset": "32421669c87c49dfabd4d3957f044e5eb7f7fb20", + "osquery-saved-query": "7b213b4b7a3e59350e99c50e8df9948662ed493a", + "query": "4640ef356321500a678869f24117b7091a911cb6", + "sample-data-telemetry": "8b10336d9efae6f3d5593c4cc89fb4abcdf84e04", + "search": "e7ba25ea37cb36b622db42c9590c6d8dfc838801", + "search-session": "ba383309da68a15be3765977f7a44c84f0ec7964", + "search-telemetry": "beb3fc25488c753f2a6dcff1845d667558712b66", + "security-rule": "e0dfdba5d66139d0300723b2e6672993cd4a11f3", + "security-solution-signals-migration": "e65933e32926e0ca385415bd44fc6da0b6d3d419", + "siem-detection-engine-rule-actions": "d4b5934c0c0e4ccdf509a41000eb0bee07be0c28", + "siem-detection-engine-rule-execution-info": "b92d51db7b7d591758d3e85892a91064aff01ff8", + "siem-ui-timeline": "95474f10662802e2f9ea068b45bf69212a2f5842", + "siem-ui-timeline-note": "08c71dc0b8b8018a67e80beb4659a078404c223d", + "siem-ui-timeline-pinned-event": "e2697b38751506c7fce6e8b7207a830483dc4283", + "space": "c4a0acce1bd4b9cce85154f2a350624a53111c59", + "spaces-usage-stats": "922d3235bbf519e3fb3b260e27248b1df8249b79", + "synthetics-monitor": "cffb4dfe9e0a36755a226d5cf983c21aac2b5b1e", + "synthetics-privates-locations": "dd00385f4a27ef062c3e57312eeb3799872fa4af", + "tag": "39413f4578cc2128c9a0fda97d0acd1c8862c47a", + "task": "ef53d0f070bd54957b8fe22fae3b1ff208913f76", + "telemetry": "9142dc5f18123fb6e6a9083db04e5becbfde94fd", + "ui-metric": "2fb66ccdee2d1fad52547964421629c5a485c38f", + "upgrade-assistant-ml-upgrade-operation": "408120d386c04ab25fe64a03937597aa0438c10d", + "upgrade-assistant-reindex-operation": "d9e18b3d9578ecabf09a297296dcf7e36b2481fd", + "upgrade-assistant-telemetry": "a0c80933a9f8b50a2590d19e1d1e5f97d28f7104", + "uptime-dynamic-settings": "9de35c5aeaef915c5bc3c5b1632c33fb0f6f1c55", + "uptime-synthetics-api-key": "df9d8418ddc210d832a069a0fb796f73e63d1082", + "url": "d66c1f26ed23a392be3617a8444d713571f58380", + "usage-counters": "33e2081a52215293041da1100e6602fb553ff446", + "visualization": "f45d06858a5634c9ed0367e11eb44f7f7dde0be2", + "workplace_search_telemetry": "45bd03e12b060c08381b0fd325d939f80d08c914", + } + `); + }); +}); diff --git a/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts b/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts index a1f7490168345..4fd5ca5cd2aea 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/type_registrations.test.ts @@ -60,6 +60,7 @@ const previouslyRegisteredTypes = [ 'fleet-preconfiguration-deletion-record', 'graph-workspace', 'guided-setup-state', + 'guided-onboarding-guide-state', 'index-pattern', 'infrastructure-monitoring-log-view', 'infrastructure-ui-source', diff --git a/src/core/server/integration_tests/saved_objects/routes/find.test.ts b/src/core/server/integration_tests/saved_objects/routes/find.test.ts index ab3ca6c459dae..2c7b1c9838b50 100644 --- a/src/core/server/integration_tests/saved_objects/routes/find.test.ts +++ b/src/core/server/integration_tests/saved_objects/routes/find.test.ts @@ -123,6 +123,7 @@ describe('GET /api/saved_objects/_find', () => { type: ['foo', 'bar'], defaultSearchOperator: 'OR', hasReferenceOperator: 'OR', + hasNoReferenceOperator: 'OR', }); }); @@ -213,6 +214,73 @@ describe('GET /api/saved_objects/_find', () => { ); }); + it('accepts the query parameter has_no_reference as an object', async () => { + const references = querystring.escape( + JSON.stringify({ + id: '1', + type: 'reference', + }) + ); + await supertest(httpSetup.server.listener) + .get(`/api/saved_objects/_find?type=foo&has_no_reference=${references}`) + .expect(200); + + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); + + const options = savedObjectsClient.find.mock.calls[0][0]; + expect(options.hasNoReference).toEqual({ + id: '1', + type: 'reference', + }); + }); + + it('accepts the query parameter has_no_reference as an array', async () => { + const references = querystring.escape( + JSON.stringify([ + { + id: '1', + type: 'reference', + }, + { + id: '2', + type: 'reference', + }, + ]) + ); + await supertest(httpSetup.server.listener) + .get(`/api/saved_objects/_find?type=foo&has_no_reference=${references}`) + .expect(200); + + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); + + const options = savedObjectsClient.find.mock.calls[0][0]; + expect(options.hasNoReference).toEqual([ + { + id: '1', + type: 'reference', + }, + { + id: '2', + type: 'reference', + }, + ]); + }); + + it('accepts the query parameter has_no_reference_operator', async () => { + await supertest(httpSetup.server.listener) + .get('/api/saved_objects/_find?type=foo&has_no_reference_operator=AND') + .expect(200); + + expect(savedObjectsClient.find).toHaveBeenCalledTimes(1); + + const options = savedObjectsClient.find.mock.calls[0][0]; + expect(options).toEqual( + expect.objectContaining({ + hasNoReferenceOperator: 'AND', + }) + ); + }); + it('accepts the query parameter search_fields', async () => { await supertest(httpSetup.server.listener) .get('/api/saved_objects/_find?type=foo&search_fields=title') diff --git a/src/core/server/internal_types.ts b/src/core/server/internal_types.ts index 683d08fe4f849..c66fdf9a968d2 100644 --- a/src/core/server/internal_types.ts +++ b/src/core/server/internal_types.ts @@ -59,7 +59,10 @@ import type { InternalUiSettingsServiceStart, } from '@kbn/core-ui-settings-server-internal'; import type { InternalRenderingServiceSetup } from '@kbn/core-rendering-server-internal'; -import { InternalHttpResourcesPreboot, InternalHttpResourcesSetup } from './http_resources'; +import type { + InternalHttpResourcesPreboot, + InternalHttpResourcesSetup, +} from '@kbn/core-http-resources-server-internal'; /** @internal */ export interface InternalCorePreboot { diff --git a/src/core/server/mocks.ts b/src/core/server/mocks.ts index cd0429415e7cb..356fd4deb44d6 100644 --- a/src/core/server/mocks.ts +++ b/src/core/server/mocks.ts @@ -32,6 +32,7 @@ import { i18nServiceMock } from '@kbn/core-i18n-server-mocks'; import { statusServiceMock } from '@kbn/core-status-server-mocks'; import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; import { renderingServiceMock } from '@kbn/core-rendering-server-mocks'; +import { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; import type { PluginInitializerContext, CoreSetup, @@ -40,7 +41,6 @@ import type { CorePreboot, RequestHandlerContext, } from '.'; -import { httpResourcesMock } from './http_resources/http_resources_service.mock'; import { SharedGlobalConfig } from './plugins'; export { configServiceMock, configDeprecationsMock } from '@kbn/config-mocks'; @@ -48,7 +48,7 @@ export { loggingSystemMock } from '@kbn/core-logging-server-mocks'; export { httpServerMock, sessionStorageMock, httpServiceMock } from '@kbn/core-http-server-mocks'; export { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; export { typeRegistryMock as savedObjectsTypeRegistryMock } from '@kbn/core-saved-objects-base-server-mocks'; -export { httpResourcesMock } from './http_resources/http_resources_service.mock'; +export { httpResourcesMock } from '@kbn/core-http-resources-server-mocks'; export { savedObjectsServiceMock } from '@kbn/core-saved-objects-server-mocks'; export { savedObjectsClientMock, diff --git a/src/core/server/server.ts b/src/core/server/server.ts index b7f41dd31dd04..07e10cc72845a 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -68,8 +68,8 @@ import type { } from '@kbn/core-http-request-handler-context-server'; import { RenderingService } from '@kbn/core-rendering-server-internal'; +import { HttpResourcesService } from '@kbn/core-http-resources-server-internal'; import { CoreApp } from './core_app'; -import { HttpResourcesService } from './http_resources'; import { PluginsService, config as pluginsConfig } from './plugins'; import { InternalCorePreboot, InternalCoreSetup, InternalCoreStart } from './internal_types'; import { DiscoveredPlugins } from './plugins'; @@ -280,7 +280,10 @@ export class Server { executionContext: executionContextSetup, }); - const metricsSetup = await this.metrics.setup({ http: httpSetup }); + const metricsSetup = await this.metrics.setup({ + http: httpSetup, + elasticsearchService: elasticsearchServiceSetup, + }); const coreUsageDataSetup = this.coreUsageData.setup({ http: httpSetup, diff --git a/src/dev/build/tasks/download_cloud_dependencies.ts b/src/dev/build/tasks/download_cloud_dependencies.ts index 25730fc88bd08..266901afb67dc 100644 --- a/src/dev/build/tasks/download_cloud_dependencies.ts +++ b/src/dev/build/tasks/download_cloud_dependencies.ts @@ -9,6 +9,7 @@ import Path from 'path'; import del from 'del'; import Axios from 'axios'; +import Fsp from 'fs/promises'; import { Task, downloadToDisk, downloadToString } from '../lib'; export const DownloadCloudDependencies: Task = { @@ -38,18 +39,41 @@ export const DownloadCloudDependencies: Task = { return Promise.all(downloads); }; + const writeManifest = async (manifestUrl: string, manifestJSON: object) => { + const destination = config.resolveFromRepo('.beats', 'beats_manifest.json'); + return Fsp.writeFile( + destination, + JSON.stringify( + { + manifest_url: manifestUrl, + ...manifestJSON, + }, + null, + 2 + ) + ); + }; + let buildId = ''; + let manifestUrl = ''; + let manifestJSON = null; const buildUrl = `https://${subdomain}.elastic.co/beats/latest/${config.getBuildVersion()}.json`; try { const latest = await Axios.get(buildUrl); buildId = latest.data.build_id; + manifestUrl = latest.data.manifest_url; + manifestJSON = (await Axios.get(manifestUrl)).data; + if (!(manifestUrl && manifestJSON)) throw new Error('Missing manifest.'); } catch (e) { log.error(`Unable to find Beats artifacts for ${config.getBuildVersion()} at ${buildUrl}.`); throw e; } + await del([config.resolveFromRepo('.beats')]); await downloadBeat('metricbeat', buildId); await downloadBeat('filebeat', buildId); + + await writeManifest(manifestUrl, manifestJSON); }, }; diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index b4224e154def5..6f82ec078f7ab 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -11,7 +11,7 @@ export const storybookAliases = { apm: 'x-pack/plugins/apm/.storybook', canvas: 'x-pack/plugins/canvas/storybook', ci_composite: '.ci/.storybook', - cloud: 'x-pack/plugins/cloud/.storybook', + cloud_chat: 'x-pack/plugins/cloud_integrations/cloud_chat/.storybook', coloring: 'packages/kbn-coloring/.storybook', chart_icons: 'packages/kbn-chart-icons/.storybook', content_management: 'packages/content-management/.storybook', diff --git a/src/plugins/bfetch/server/plugin.ts b/src/plugins/bfetch/server/plugin.ts index 0f51f5da62353..85720480cf9a0 100644 --- a/src/plugins/bfetch/server/plugin.ts +++ b/src/plugins/bfetch/server/plugin.ts @@ -20,6 +20,7 @@ import { } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { map$ } from '@kbn/std'; +import { RouteConfigOptions } from '@kbn/core-http-server'; import { StreamingResponseHandler, BatchRequestData, @@ -54,7 +55,8 @@ export interface BfetchServerSetup { context: RequestHandlerContext ) => StreamingResponseHandler, method?: 'GET' | 'POST' | 'PUT' | 'DELETE', - pluginRouter?: ReturnType + pluginRouter?: ReturnType, + options?: RouteConfigOptions<'get' | 'post' | 'put' | 'delete'> ) => void; } @@ -117,14 +119,16 @@ export class BfetchServerPlugin router: ReturnType; logger: Logger; }): BfetchServerSetup['addStreamingResponseRoute'] => - (path, handler, method = 'POST', pluginRouter) => { + (path, handler, method = 'POST', pluginRouter, options) => { const httpRouter = pluginRouter || router; + const routeDefinition = { path: `/${removeLeadingSlash(path)}`, validate: { body: schema.any(), query: schema.object({ compress: schema.boolean({ defaultValue: false }) }), }, + options, }; const routeHandler: RequestHandler = async ( context: RequestHandlerContext, diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx index 5a03e2dd3187c..6588cefdb8f2b 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.test.tsx @@ -211,7 +211,7 @@ describe('GaugeComponent', function () { }); describe('ticks and color bands', () => { - it('sets proper color bands for values smaller than maximum', () => { + it('sets proper color bands and ticks on color bands for values smaller than maximum', () => { const palette = { type: 'palette' as const, name: 'custom', @@ -236,6 +236,7 @@ describe('GaugeComponent', function () { }, } as GaugeRenderProps; const goal = shallowWithIntl().find(Goal); + expect(goal.prop('ticks')).toEqual([0, 1, 2, 3, 4, 10]); expect(goal.prop('bands')).toEqual([0, 1, 2, 3, 4, 10]); }); it('sets proper color bands if palette steps are smaller than minimum', () => { diff --git a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx index b75d613f814a7..37e3ca6bdd8f1 100644 --- a/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx +++ b/src/plugins/chart_expressions/expression_gauge/public/components/gauge_component.tsx @@ -18,6 +18,8 @@ import { GaugeLabelMajorMode, GaugeLabelMajorModes, GaugeColorModes, + GaugeShapes, + GaugeTicksPositions, } from '../../common'; import { getAccessorsFromArgs, @@ -30,7 +32,7 @@ import { } from './utils'; import { getIcons } from './utils/icons'; import './index.scss'; -import { GaugeCentralMajorMode } from '../../common/types'; +import { GaugeCentralMajorMode, GaugeTicksPosition } from '../../common/types'; import { isBulletShape, isRoundShape } from '../../common/utils'; import './gauge.scss'; @@ -135,6 +137,35 @@ const getPreviousSectionValue = (value: number, bands: number[]) => { return prevSectionValue; }; +function getTicksLabels(baseStops: number[]) { + const tenPercentRange = (Math.max(...baseStops) - Math.min(...baseStops)) * 0.1; + const lastIndex = baseStops.length - 1; + return baseStops.filter((stop, i) => { + if (i === 0 || i === lastIndex) { + return true; + } + + return !( + stop - baseStops[i - 1] < tenPercentRange || baseStops[lastIndex] - stop < tenPercentRange + ); + }); +} + +function getTicks( + ticksPosition: GaugeTicksPosition, + range: [number, number], + colorBands?: number[], + percentageMode?: boolean +) { + if (ticksPosition === GaugeTicksPositions.HIDDEN) { + return []; + } + + if (ticksPosition === GaugeTicksPositions.BANDS && colorBands) { + return colorBands && getTicksLabels(colorBands); + } +} + export const GaugeComponent: FC = memo( ({ data, args, uiState, formatFactory, paletteService, chartsThemeService, renderComplete }) => { const { @@ -146,6 +177,7 @@ export const GaugeComponent: FC = memo( labelMajorMode, centralMajor, centralMajorMode, + ticksPosition, commonLabel, } = args; @@ -294,6 +326,12 @@ export const GaugeComponent: FC = memo( actualValue = actualValueToPercentsLegacy(palette?.params as CustomPaletteState, actualValue); } + const totalTicks = getTicks(ticksPosition, [min, max], bands, args.percentageMode); + const ticks = + totalTicks && gaugeType === GaugeShapes.CIRCLE + ? totalTicks.slice(0, totalTicks.length - 1) + : totalTicks; + const goalConfig = getGoalConfig(gaugeType); const labelMajorTitle = getTitle(labelMajorMode, labelMajor, metricColumn?.name); @@ -329,6 +367,7 @@ export const GaugeComponent: FC = memo( tickValueFormatter={({ value: tickValue }) => tickFormatter.convert(tickValue)} tooltipValueFormatter={(tooltipValue) => tickFormatter.convert(tooltipValue)} bands={bands} + ticks={ticks} domain={{ min, max }} bandFillColor={ colorMode === GaugeColorModes.PALETTE diff --git a/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap b/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap index 9a7a7d5a5035c..defaca87fad1c 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap +++ b/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/__snapshots__/metric_vis_function.test.ts.snap @@ -26,6 +26,7 @@ Object { "as": "legacyMetricVis", "type": "render", "value": Object { + "canNavigateToLens": false, "visConfig": Object { "dimensions": Object { "metrics": Array [ diff --git a/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/metric_vis_function.ts b/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/metric_vis_function.ts index 8ec638d139bff..a7d655107fc2d 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/metric_vis_function.ts +++ b/src/plugins/chart_expressions/expression_legacy_metric/common/expression_functions/metric_vis_function.ts @@ -200,6 +200,7 @@ export const metricVisFunction = (): MetricVisExpressionFunctionDefinition => ({ ...(args.bucket ? { bucket: args.bucket } : {}), }, }, + canNavigateToLens: Boolean(handlers?.variables?.canNavigateToLens), }, }; }, diff --git a/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts b/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts index 0c7c0331975e8..f0a63b012dc0a 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts +++ b/src/plugins/chart_expressions/expression_legacy_metric/common/types/expression_functions.ts @@ -38,6 +38,7 @@ export interface MetricVisRenderConfig { visType: typeof visType; visData: Datatable; visConfig: Pick; + canNavigateToLens: boolean; } export type MetricVisExpressionFunctionDefinition = ExpressionFunctionDefinition< diff --git a/src/plugins/chart_expressions/expression_legacy_metric/public/__stories__/metric_renderer.stories.tsx b/src/plugins/chart_expressions/expression_legacy_metric/public/__stories__/metric_renderer.stories.tsx index 36fc6cd712f83..ba2835806f4f5 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/public/__stories__/metric_renderer.stories.tsx +++ b/src/plugins/chart_expressions/expression_legacy_metric/public/__stories__/metric_renderer.stories.tsx @@ -43,6 +43,7 @@ const style: MetricStyle = { }; const config: MetricVisRenderConfig = { + canNavigateToLens: false, visType, visData: { type: 'datatable', diff --git a/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx b/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx index 798bc62938ca1..456a7f9cbf8a4 100644 --- a/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_legacy_metric/public/expression_renderers/metric_vis_renderer.tsx @@ -67,7 +67,7 @@ export const getMetricVisRenderer: ( name: EXPRESSION_METRIC_NAME, displayName: 'metric visualization', reuseDomNode: true, - render: async (domNode, { visData, visConfig }, handlers) => { + render: async (domNode, { visData, visConfig, canNavigateToLens }, handlers) => { const { core, plugins } = getStartDeps(); handlers.onDestroy(() => { @@ -82,9 +82,12 @@ export const getMetricVisRenderer: ( const visualizationType = extractVisualizationType(executionContext); if (containerType && visualizationType) { - plugins.usageCollection?.reportUiCounter(containerType, METRIC_TYPE.COUNT, [ + const events = [ `render_${visualizationType}_legacy_metric`, - ]); + canNavigateToLens ? `render_${visualizationType}_legacy_metric_convertable` : undefined, + ].filter((event): event is string => Boolean(event)); + + plugins.usageCollection?.reportUiCounter(containerType, METRIC_TYPE.COUNT, events); } handlers.done(); diff --git a/src/plugins/console/public/application/components/settings_modal.tsx b/src/plugins/console/public/application/components/settings_modal.tsx index 095dde1c29507..67b0e2c0d957a 100644 --- a/src/plugins/console/public/application/components/settings_modal.tsx +++ b/src/plugins/console/public/application/components/settings_modal.tsx @@ -77,9 +77,9 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => { const [polling, setPolling] = useState(props.settings.polling); const [pollInterval, setPollInterval] = useState(props.settings.pollInterval); const [tripleQuotes, setTripleQuotes] = useState(props.settings.tripleQuotes); - const [isHistoryDisabled, setIsHistoryDisabled] = useState(props.settings.isHistoryDisabled); - const [isKeyboardShortcutsDisabled, setIsKeyboardShortcutsDisabled] = useState( - props.settings.isKeyboardShortcutsDisabled + const [isHistoryEnabled, setIsHistoryEnabled] = useState(props.settings.isHistoryEnabled); + const [isKeyboardShortcutsEnabled, setIsKeyboardShortcutsEnabled] = useState( + props.settings.isKeyboardShortcutsEnabled ); const autoCompleteCheckboxes = [ @@ -140,8 +140,8 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => { polling, pollInterval, tripleQuotes, - isHistoryDisabled, - isKeyboardShortcutsDisabled, + isHistoryEnabled, + isKeyboardShortcutsEnabled, }); } @@ -153,17 +153,17 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => { }, []); const toggleKeyboardShortcuts = useCallback( - (isDisabled: boolean) => { + (isEnabled: boolean) => { if (props.editorInstance) { unregisterCommands(props.editorInstance); - setIsKeyboardShortcutsDisabled(isDisabled); + setIsKeyboardShortcutsEnabled(isEnabled); } }, [props.editorInstance] ); const toggleSavingToHistory = useCallback( - (isDisabled: boolean) => setIsHistoryDisabled(isDisabled), + (isEnabled: boolean) => setIsHistoryEnabled(isEnabled), [] ); @@ -289,11 +289,11 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => { } > } onChange={(e) => toggleSavingToHistory(e.target.checked)} @@ -309,11 +309,11 @@ export const DevToolsSettingsModal = (props: DevToolsSettingsModalProps) => { } > } onChange={(e) => toggleKeyboardShortcuts(e.target.checked)} diff --git a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx index 74a052646e198..ed8c87b5df147 100644 --- a/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx +++ b/src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx @@ -259,8 +259,8 @@ function EditorUI({ initialTextValue, setEditorInstance }: EditorProps) { }, [settings]); useEffect(() => { - const { isKeyboardShortcutsDisabled } = settings; - if (!isKeyboardShortcutsDisabled) { + const { isKeyboardShortcutsEnabled } = settings; + if (isKeyboardShortcutsEnabled) { registerCommands({ senseEditor: editorInstanceRef.current!, sendCurrentRequest, diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx index 0c7e4c46d95a6..e895ddc135db8 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx +++ b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.test.tsx @@ -106,7 +106,9 @@ describe('useSendCurrentRequest', () => { (sendRequest as jest.Mock).mockReturnValue( [{ request: {} }, { request: {} }] /* two responses to save history */ ); - (mockContextValue.services.settings.toJSON as jest.Mock).mockReturnValue({}); + (mockContextValue.services.settings.toJSON as jest.Mock).mockReturnValue({ + isHistoryEnabled: true, + }); (mockContextValue.services.history.addToHistory as jest.Mock).mockImplementation(() => { // Mock throwing throw new Error('cannot save!'); diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts index 87f72571a63e6..28d875c246ca3 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request/use_send_current_request.ts @@ -52,9 +52,9 @@ export const useSendCurrentRequest = () => { const results = await sendRequest({ http, requests }); let saveToHistoryError: undefined | Error; - const { isHistoryDisabled } = settings.toJSON(); + const { isHistoryEnabled } = settings.toJSON(); - if (!isHistoryDisabled) { + if (isHistoryEnabled) { results.forEach(({ request: { path, method, data } }) => { try { history.addToHistory(path, method, data); @@ -84,7 +84,7 @@ export const useSendCurrentRequest = () => { notifications.toasts.remove(toast); }, onDisableSavingToHistory: () => { - settings.setIsHistoryDisabled(true); + settings.setIsHistoryEnabled(false); notifications.toasts.remove(toast); }, }), diff --git a/src/plugins/console/public/services/settings.ts b/src/plugins/console/public/services/settings.ts index aa2280f06064f..e4731dd3f3a31 100644 --- a/src/plugins/console/public/services/settings.ts +++ b/src/plugins/console/public/services/settings.ts @@ -15,8 +15,8 @@ export const DEFAULT_SETTINGS = Object.freeze({ tripleQuotes: true, wrapMode: true, autocomplete: Object.freeze({ fields: true, indices: true, templates: true, dataStreams: true }), - isHistoryDisabled: false, - isKeyboardShortcutsDisabled: false, + isHistoryEnabled: true, + isKeyboardShortcutsEnabled: true, }); export interface DevToolsSettings { @@ -31,8 +31,8 @@ export interface DevToolsSettings { polling: boolean; pollInterval: number; tripleQuotes: boolean; - isHistoryDisabled: boolean; - isKeyboardShortcutsDisabled: boolean; + isHistoryEnabled: boolean; + isKeyboardShortcutsEnabled: boolean; } enum SettingKeys { @@ -42,12 +42,32 @@ enum SettingKeys { AUTOCOMPLETE_SETTINGS = 'autocomplete_settings', CONSOLE_POLLING = 'console_polling', POLL_INTERVAL = 'poll_interval', - IS_HISTORY_DISABLED = 'is_history_disabled', - IS_KEYBOARD_SHORTCUTS_DISABLED = 'is_keyboard_shortcuts_disabled', + IS_HISTORY_ENABLED = 'is_history_enabled', + IS_KEYBOARD_SHORTCUTS_ENABLED = 'is_keyboard_shortcuts_enabled', } export class Settings { - constructor(private readonly storage: Storage) {} + constructor(private readonly storage: Storage) { + // Migration from old settings to new ones + this.addMigrationRule('is_history_disabled', SettingKeys.IS_HISTORY_ENABLED, (value: any) => { + return !value; + }); + this.addMigrationRule( + 'is_keyboard_shortcuts_disabled', + SettingKeys.IS_KEYBOARD_SHORTCUTS_ENABLED, + (value: any) => { + return !value; + } + ); + } + + private addMigrationRule(previousKey: string, newKey: string, migration: (value: any) => any) { + const value = this.storage.get(previousKey); + if (value !== undefined) { + this.storage.set(newKey, migration(value)); + this.storage.delete(previousKey); + } + } getFontSize() { return this.storage.get(SettingKeys.FONT_SIZE, DEFAULT_SETTINGS.fontSize); @@ -94,13 +114,13 @@ export class Settings { return true; } - setIsHistoryDisabled(isDisabled: boolean) { - this.storage.set(SettingKeys.IS_HISTORY_DISABLED, isDisabled); + setIsHistoryEnabled(isEnabled: boolean) { + this.storage.set(SettingKeys.IS_HISTORY_ENABLED, isEnabled); return true; } - getIsHistoryDisabled() { - return this.storage.get(SettingKeys.IS_HISTORY_DISABLED, DEFAULT_SETTINGS.isHistoryDisabled); + getIsHistoryEnabled() { + return this.storage.get(SettingKeys.IS_HISTORY_ENABLED, DEFAULT_SETTINGS.isHistoryEnabled); } setPollInterval(interval: number) { @@ -111,15 +131,15 @@ export class Settings { return this.storage.get(SettingKeys.POLL_INTERVAL, DEFAULT_SETTINGS.pollInterval); } - setIsKeyboardShortcutsDisabled(disable: boolean) { - this.storage.set(SettingKeys.IS_KEYBOARD_SHORTCUTS_DISABLED, disable); + setIsKeyboardShortcutsEnabled(isEnabled: boolean) { + this.storage.set(SettingKeys.IS_KEYBOARD_SHORTCUTS_ENABLED, isEnabled); return true; } getIsKeyboardShortcutsDisabled() { return this.storage.get( - SettingKeys.IS_KEYBOARD_SHORTCUTS_DISABLED, - DEFAULT_SETTINGS.isKeyboardShortcutsDisabled + SettingKeys.IS_KEYBOARD_SHORTCUTS_ENABLED, + DEFAULT_SETTINGS.isKeyboardShortcutsEnabled ); } @@ -131,8 +151,8 @@ export class Settings { fontSize: parseFloat(this.getFontSize()), polling: Boolean(this.getPolling()), pollInterval: this.getPollInterval(), - isHistoryDisabled: Boolean(this.getIsHistoryDisabled()), - isKeyboardShortcutsDisabled: Boolean(this.getIsKeyboardShortcutsDisabled()), + isHistoryEnabled: Boolean(this.getIsHistoryEnabled()), + isKeyboardShortcutsEnabled: Boolean(this.getIsKeyboardShortcutsDisabled()), }; } @@ -143,8 +163,8 @@ export class Settings { autocomplete, polling, pollInterval, - isHistoryDisabled, - isKeyboardShortcutsDisabled, + isHistoryEnabled, + isKeyboardShortcutsEnabled, }: DevToolsSettings) { this.setFontSize(fontSize); this.setWrapMode(wrapMode); @@ -152,8 +172,8 @@ export class Settings { this.setAutocomplete(autocomplete); this.setPolling(polling); this.setPollInterval(pollInterval); - this.setIsHistoryDisabled(isHistoryDisabled); - this.setIsKeyboardShortcutsDisabled(isKeyboardShortcutsDisabled); + this.setIsHistoryEnabled(isHistoryEnabled); + this.setIsKeyboardShortcutsEnabled(isKeyboardShortcutsEnabled); } } diff --git a/src/plugins/data/common/search/aggs/agg_config.test.ts b/src/plugins/data/common/search/aggs/agg_config.test.ts index bf6dfbd51b26a..6ea409e327d56 100644 --- a/src/plugins/data/common/search/aggs/agg_config.test.ts +++ b/src/plugins/data/common/search/aggs/agg_config.test.ts @@ -191,6 +191,85 @@ describe('AggConfig', () => { expect(dsl.aggs[medianConfig.id]).toHaveProperty('percentiles'); expect(dsl.aggs[medianConfig.id].percentiles).toBe(football); }); + + it('properly handles nested sibling pipeline aggregations', () => { + const customBucket = { + type: 'date_histogram', + params: { + field: '@timestamp', + interval: '1h', + }, + }; + const customMetric = { + type: 'avg_bucket', + params: { + customBucket: { + type: 'date_histogram', + params: { + field: '@timestamp', + interval: '30m', + }, + }, + customMetric: { + type: 'sum', + params: { + field: 'bytes', + }, + }, + }, + }; + const configStates = [ + { + type: 'avg_bucket', + params: { + customBucket, + customMetric, + }, + }, + ]; + const ac = new AggConfigs(indexPattern, configStates, { typesRegistry }, jest.fn()); + const dsl = ac.toDsl(); + + expect(dsl).toMatchInlineSnapshot(` + Object { + "1": Object { + "avg_bucket": Object { + "buckets_path": "1-bucket>1-metric", + }, + }, + "1-bucket": Object { + "aggs": Object { + "1-bucket": Object { + "aggs": Object { + "1-metric": Object { + "sum": Object { + "field": "bytes", + }, + }, + }, + "date_histogram": Object { + "field": "@timestamp", + "fixed_interval": "30m", + "min_doc_count": 1, + "time_zone": "dateFormat:tz", + }, + }, + "1-metric": Object { + "avg_bucket": Object { + "buckets_path": "1-bucket>1-metric", + }, + }, + }, + "date_histogram": Object { + "calendar_interval": "1h", + "field": "@timestamp", + "min_doc_count": 1, + "time_zone": "dateFormat:tz", + }, + }, + } + `); + }); }); describe('::ensureIds', () => { diff --git a/src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts b/src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts index 752bacd7554e5..fb47e53362826 100644 --- a/src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts +++ b/src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts @@ -6,21 +6,25 @@ * Side Public License, v 1. */ +import { siblingPipelineType } from '../../../..'; import { IMetricAggConfig } from '../metric_agg_type'; import { METRIC_TYPES } from '../metric_agg_types'; export const siblingPipelineAggWriter = (agg: IMetricAggConfig, output: Record) => { - const customMetric = agg.getParam('customMetric'); - - if (!customMetric) return; - - const metricAgg = customMetric; + const metricAgg = agg.getParam('customMetric'); const bucketAgg = agg.getParam('customBucket'); + if (!metricAgg) return; // if a bucket is selected, we must add this agg as a sibling to it, and add a metric to that bucket (or select one of its) if (metricAgg.type.name !== METRIC_TYPES.COUNT) { bucketAgg.subAggs = (output.subAggs || []).concat(metricAgg); output.params.buckets_path = `${bucketAgg.id}>${metricAgg.id}`; + + // If the metric is another nested sibling pipeline agg, we need to include it as a sub-agg of this agg's bucket agg + if (metricAgg.type.subtype === siblingPipelineType) { + const subAgg = metricAgg.getParam('customBucket'); + if (subAgg) bucketAgg.subAggs.push(subAgg); + } } else { output.params.buckets_path = bucketAgg.id + '>_count'; } diff --git a/src/plugins/data/common/search/session/status.ts b/src/plugins/data/common/search/session/status.ts index 790adbe7ba000..24fac7b69c2a3 100644 --- a/src/plugins/data/common/search/session/status.ts +++ b/src/plugins/data/common/search/session/status.ts @@ -13,3 +13,9 @@ export enum SearchSessionStatus { CANCELLED = 'cancelled', EXPIRED = 'expired', } + +export enum SearchStatus { + IN_PROGRESS = 'in_progress', + ERROR = 'error', + COMPLETE = 'complete', +} diff --git a/src/plugins/data/common/search/session/types.ts b/src/plugins/data/common/search/session/types.ts index cbe3de9be4c73..7824a1db6362e 100644 --- a/src/plugins/data/common/search/session/types.ts +++ b/src/plugins/data/common/search/session/types.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ +import type { SavedObjectsFindResponse } from '@kbn/core/server'; import { SerializableRecord } from '@kbn/utility-types'; -import { SearchSessionStatus } from './status'; +import type { SearchSessionStatus, SearchStatus } from './status'; export const SEARCH_SESSION_TYPE = 'search-session'; export interface SearchSessionSavedObjectAttributes { @@ -24,25 +25,12 @@ export interface SearchSessionSavedObjectAttributes { * Creation time of the session */ created: string; - /** - * Last touch time of the session - */ - touched: string; + /** * Expiration time of the session. Expiration itself is managed by Elasticsearch. */ expires: string; - /** - * Time of transition into completed state, - * - * Can be "null" in case already completed session - * transitioned into in-progress session - */ - completed?: string | null; - /** - * status - */ - status: SearchSessionStatus; + /** * locatorId (see share.url.locators service) */ @@ -62,10 +50,6 @@ export interface SearchSessionSavedObjectAttributes { */ idMapping: Record; - /** - * This value is true if the session was actively stored by the user. If it is false, the session may be purged by the system. - */ - persisted: boolean; /** * The realm type/name & username uniquely identifies the user who created this search session */ @@ -76,6 +60,11 @@ export interface SearchSessionSavedObjectAttributes { * Version information to display warnings when trying to restore a session from a different version */ version: string; + + /** + * `true` if session was cancelled + */ + isCanceled?: boolean; } export interface SearchSessionRequestInfo { @@ -87,20 +76,30 @@ export interface SearchSessionRequestInfo { * Search strategy used to submit the search request */ strategy: string; - /** - * status - */ - status: string; +} + +export interface SearchSessionRequestStatus { + status: SearchStatus; /** * An optional error. Set if status is set to error. */ error?: string; } -export interface SearchSessionFindOptions { - page?: number; - perPage?: number; - sortField?: string; - sortOrder?: string; - filter?: string; +/** + * On-the-fly calculated search session status + */ +export interface SearchSessionStatusResponse { + status: SearchSessionStatus; +} + +/** + * List of search session objects with on-the-fly calculated search session statuses + */ +export interface SearchSessionsFindResponse + extends SavedObjectsFindResponse { + /** + * Map containing calculated statuses of search sessions from the find response + */ + statuses: Record; } diff --git a/src/plugins/data/common/search/types.ts b/src/plugins/data/common/search/types.ts index 802af347b8e69..cedfa3ee02274 100644 --- a/src/plugins/data/common/search/types.ts +++ b/src/plugins/data/common/search/types.ts @@ -72,6 +72,11 @@ export interface IKibanaSearchResponse { */ isRestored?: boolean; + /** + * Indicates whether the search has been saved to a search-session object and long keepAlive was set + */ + isStored?: boolean; + /** * Optional warnings returned from Elasticsearch (for example, deprecation warnings) */ @@ -119,6 +124,11 @@ export interface ISearchOptions { */ isStored?: boolean; + /** + * Whether the search was successfully polled after session was saved. Search was added to a session saved object and keepAlive extended. + */ + isSearchStored?: boolean; + /** * Whether the session is restored (i.e. search requests should re-use the stored search IDs, * rather than starting from scratch) @@ -148,5 +158,11 @@ export interface ISearchOptions { */ export type ISearchOptionsSerializable = Pick< ISearchOptions, - 'strategy' | 'legacyHitsTotal' | 'sessionId' | 'isStored' | 'isRestore' | 'executionContext' + | 'strategy' + | 'legacyHitsTotal' + | 'sessionId' + | 'isStored' + | 'isSearchStored' + | 'isRestore' + | 'executionContext' >; diff --git a/src/plugins/data/config.ts b/src/plugins/data/config.ts index 0ec794d9bd63c..d4331ecd760b4 100644 --- a/src/plugins/data/config.ts +++ b/src/plugins/data/config.ts @@ -13,42 +13,13 @@ export const searchSessionsConfigSchema = schema.object({ * Turns the feature on \ off (incl. removing indicator and management screens) */ enabled: schema.boolean({ defaultValue: true }), - /** - * pageSize controls how many search session objects we load at once while monitoring - * session completion - */ - pageSize: schema.number({ defaultValue: 100 }), - /** - * trackingInterval controls how often we track persisted search session objects progress - */ - trackingInterval: schema.duration({ defaultValue: '10s' }), - - /** - * cleanupInterval controls how often we track non-persisted search session objects for cleanup - */ - cleanupInterval: schema.duration({ defaultValue: '60s' }), - - /** - * expireInterval controls how often we track persisted search session objects for expiration - */ - expireInterval: schema.duration({ defaultValue: '60m' }), - - /** - * monitoringTaskTimeout controls for how long task manager waits for search session monitoring task to complete before considering it timed out, - * If tasks timeouts it receives cancel signal and next task starts in "trackingInterval" time - */ - monitoringTaskTimeout: schema.duration({ defaultValue: '5m' }), /** - * notTouchedTimeout controls how long do we store unpersisted search session results, - * after the last search in the session has completed + * notTouchedTimeout controls how long user can save a session after all searches completed. + * The client continues to poll searches to keep the alive until this timeout hits */ notTouchedTimeout: schema.duration({ defaultValue: '5m' }), - /** - * notTouchedInProgressTimeout controls how long do allow a search session to run after - * a user has navigated away without persisting - */ - notTouchedInProgressTimeout: schema.duration({ defaultValue: '1m' }), + /** * maxUpdateRetries controls how many retries we perform while attempting to save a search session */ @@ -60,15 +31,15 @@ export const searchSessionsConfigSchema = schema.object({ defaultExpiration: schema.duration({ defaultValue: '7d' }), management: schema.object({ /** - * maxSessions controls how many saved search sessions we display per page on the management screen. + * maxSessions controls how many saved search sessions we load on the management screen. */ - maxSessions: schema.number({ defaultValue: 10000 }), + maxSessions: schema.number({ defaultValue: 100 }), /** - * refreshInterval controls how often we refresh the management screen. + * refreshInterval controls how often we refresh the management screen. 0s as duration means that auto-refresh is turned off. */ - refreshInterval: schema.duration({ defaultValue: '10s' }), + refreshInterval: schema.duration({ defaultValue: '0s' }), /** - * refreshTimeout controls how often we refresh the management screen. + * refreshTimeout controls the timeout for loading search sessions on mgmt screen */ refreshTimeout: schema.duration({ defaultValue: '1m' }), expiresSoonWarning: schema.duration({ defaultValue: '1d' }), diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts index 68f1ff1910c98..73c86d8845a18 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.test.ts @@ -548,6 +548,7 @@ describe('SearchInterceptor', () => { sessionId, isStored: true, isRestore: true, + isSearchStored: false, strategy: 'ese', }, }) @@ -732,17 +733,21 @@ describe('SearchInterceptor', () => { ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); + const trackSearchComplete = jest.fn(); + sessionService.trackSearch.mockImplementation(() => ({ + complete: trackSearchComplete, + error: () => {}, + beforePoll: () => [{ isSearchStored: false }, () => {}], + })); const response = searchInterceptor.search({}, { pollInterval: 0, sessionId }); response.subscribe({ next, error }); await timeTravel(10); expect(sessionService.trackSearch).toBeCalledTimes(1); - expect(untrack).not.toBeCalled(); + expect(trackSearchComplete).not.toBeCalled(); await timeTravel(300); expect(sessionService.trackSearch).toBeCalledTimes(1); - expect(untrack).toBeCalledTimes(1); + expect(trackSearchComplete).toBeCalledTimes(1); }); test('session service should be able to cancel search', async () => { @@ -752,9 +757,6 @@ describe('SearchInterceptor', () => { ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); - const response = searchInterceptor.search({}, { pollInterval: 0, sessionId }); response.subscribe({ next, error }); await timeTravel(10); @@ -778,9 +780,6 @@ describe('SearchInterceptor', () => { ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); - const response1 = searchInterceptor.search( {}, { pollInterval: 0, sessionId: 'something different' } @@ -798,9 +797,6 @@ describe('SearchInterceptor', () => { sessionService.getSessionId.mockImplementation(() => undefined); sessionService.isCurrentSession.mockImplementation((_sessionId) => false); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); - const response1 = searchInterceptor.search( {}, { pollInterval: 0, sessionId: 'something different' } @@ -911,15 +907,22 @@ describe('SearchInterceptor', () => { expect(fetchMock).toBeCalledTimes(2); }); - test('should track searches that come from cache', async () => { + test('should not track searches that come from cache', async () => { mockFetchImplementation(partialCompleteResponse); sessionService.isCurrentSession.mockImplementation( (_sessionId) => _sessionId === sessionId ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); + const completeSearch = jest.fn(); + + sessionService.trackSearch.mockImplementation((params) => ({ + complete: completeSearch, + error: jest.fn(), + beforePoll: jest.fn(() => { + return [{ isSearchStored: false }, () => {}]; + }), + })); const req = { params: { @@ -932,14 +935,15 @@ describe('SearchInterceptor', () => { response.subscribe({ next, error, complete }); response2.subscribe({ next, error, complete }); await timeTravel(10); + expect(fetchMock).toBeCalledTimes(1); - expect(sessionService.trackSearch).toBeCalledTimes(2); - expect(untrack).not.toBeCalled(); + expect(sessionService.trackSearch).toBeCalledTimes(1); + expect(completeSearch).not.toBeCalled(); await timeTravel(300); // Should be called only 2 times (once per partial response) expect(fetchMock).toBeCalledTimes(2); - expect(sessionService.trackSearch).toBeCalledTimes(2); - expect(untrack).toBeCalledTimes(2); + expect(sessionService.trackSearch).toBeCalledTimes(1); + expect(completeSearch).toBeCalledTimes(1); expect(next).toBeCalledTimes(4); expect(error).toBeCalledTimes(0); @@ -1125,8 +1129,15 @@ describe('SearchInterceptor', () => { ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); + const completeSearch = jest.fn(); + + sessionService.trackSearch.mockImplementation((params) => ({ + complete: completeSearch, + error: jest.fn(), + beforePoll: jest.fn(() => { + return [{ isSearchStored: false }, () => {}]; + }), + })); const req = { params: { @@ -1149,7 +1160,6 @@ describe('SearchInterceptor', () => { expect(error).toBeCalledTimes(0); expect(complete).toBeCalledTimes(0); expect(sessionService.trackSearch).toBeCalledTimes(1); - expect(untrack).not.toBeCalled(); const next2 = jest.fn(); const error2 = jest.fn(); @@ -1161,9 +1171,9 @@ describe('SearchInterceptor', () => { abortController.abort(); await timeTravel(300); - // Both searches should be tracked and untracked - expect(sessionService.trackSearch).toBeCalledTimes(2); - expect(untrack).toBeCalledTimes(2); + // Only first searches should be tracked and untracked + expect(sessionService.trackSearch).toBeCalledTimes(1); + expect(completeSearch).toBeCalledTimes(1); // First search should error expect(next).toBeCalledTimes(1); @@ -1186,8 +1196,15 @@ describe('SearchInterceptor', () => { ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); + const completeSearch = jest.fn(); + + sessionService.trackSearch.mockImplementation((params) => ({ + complete: completeSearch, + error: jest.fn(), + beforePoll: jest.fn(() => { + return [{ isSearchStored: false }, () => {}]; + }), + })); const req = { params: { @@ -1206,7 +1223,7 @@ describe('SearchInterceptor', () => { expect(error).toBeCalledTimes(0); expect(complete).toBeCalledTimes(0); expect(sessionService.trackSearch).toBeCalledTimes(1); - expect(untrack).not.toBeCalled(); + expect(completeSearch).not.toBeCalled(); const next2 = jest.fn(); const error2 = jest.fn(); @@ -1222,8 +1239,8 @@ describe('SearchInterceptor', () => { abortController.abort(); await timeTravel(300); - expect(sessionService.trackSearch).toBeCalledTimes(2); - expect(untrack).toBeCalledTimes(2); + expect(sessionService.trackSearch).toBeCalledTimes(1); + expect(completeSearch).toBeCalledTimes(1); expect(next).toBeCalledTimes(2); expect(error).toBeCalledTimes(0); @@ -1243,7 +1260,6 @@ describe('SearchInterceptor', () => { (_sessionId) => _sessionId === sessionId ); sessionService.getSessionId.mockImplementation(() => sessionId); - sessionService.trackSearch.mockImplementation(() => jest.fn()); const req = { params: { @@ -1282,8 +1298,15 @@ describe('SearchInterceptor', () => { ); sessionService.getSessionId.mockImplementation(() => sessionId); - const untrack = jest.fn(); - sessionService.trackSearch.mockImplementation(() => untrack); + const completeSearch = jest.fn(); + + sessionService.trackSearch.mockImplementation((params) => ({ + complete: completeSearch, + error: jest.fn(), + beforePoll: jest.fn(() => { + return [{ isSearchStored: false }, () => {}]; + }), + })); const req = { params: { diff --git a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts index ed21e4ef1d1e6..baa5eb30bca4c 100644 --- a/src/plugins/data/public/search/search_interceptor/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor/search_interceptor.ts @@ -7,7 +7,16 @@ */ import { memoize, once } from 'lodash'; -import { BehaviorSubject, EMPTY, from, fromEvent, of, Subscription, throwError } from 'rxjs'; +import { + BehaviorSubject, + EMPTY, + from, + fromEvent, + Observable, + of, + Subscription, + throwError, +} from 'rxjs'; import { catchError, filter, @@ -42,6 +51,7 @@ import { IAsyncSearchOptions, IKibanaSearchRequest, IKibanaSearchResponse, + isCompleteResponse, ISearchOptions, ISearchOptionsSerializable, pollSearch, @@ -146,18 +156,24 @@ export class SearchInterceptor { : TimeoutErrorMode.CONTACT; } - private createRequestHash$(request: IKibanaSearchRequest, options: IAsyncSearchOptions) { - const { sessionId, isRestore } = options; + private createRequestHash$( + request: IKibanaSearchRequest, + options: IAsyncSearchOptions + ): Observable { + const { sessionId } = options; // Preference is used to ensure all queries go to the same set of shards and it doesn't need to be hashed // https://www.elastic.co/guide/en/elasticsearch/reference/current/search-shard-routing.html#shard-and-node-preference const { preference, ...params } = request.params || {}; const hashOptions = { ...params, sessionId, - isRestore, }; - return from(sessionId ? createRequestHash(hashOptions) : of(undefined)); + if (!sessionId) return of(undefined); // don't use cache if doesn't belong to a session + const sessionOptions = this.deps.session.getSearchOptions(options.sessionId); + if (sessionOptions?.isRestore) return of(undefined); // don't use cache if restoring a session + + return from(createRequestHash(hashOptions)); } /* @@ -206,6 +222,8 @@ export class SearchInterceptor { serializableOptions.legacyHitsTotal = combined.legacyHitsTotal; if (combined.strategy !== undefined) serializableOptions.strategy = combined.strategy; if (combined.isStored !== undefined) serializableOptions.isStored = combined.isStored; + if (combined.isSearchStored !== undefined) + serializableOptions.isSearchStored = combined.isSearchStored; if (combined.executionContext !== undefined) { serializableOptions.executionContext = combined.executionContext; } @@ -222,16 +240,47 @@ export class SearchInterceptor { options: IAsyncSearchOptions, searchAbortController: SearchAbortController ) { - const search = () => - this.runSearch( - { id, ...request }, - { ...options, abortSignal: searchAbortController.getSignal() } - ); const { sessionId, strategy } = options; + const search = () => { + const [{ isSearchStored }, afterPoll] = searchTracker?.beforePoll() ?? [ + { isSearchStored: false }, + ({ isSearchStored: boolean }) => {}, + ]; + return this.runSearch( + { id, ...request }, + { + ...options, + ...this.deps.session.getSearchOptions(sessionId), + abortSignal: searchAbortController.getSignal(), + isSearchStored, + } + ) + .then((result) => { + afterPoll({ isSearchStored: result.isStored ?? false }); + return result; + }) + .catch((err) => { + afterPoll({ isSearchStored: false }); + throw err; + }); + }; + + const searchTracker = this.deps.session.isCurrentSession(sessionId) + ? this.deps.session.trackSearch({ + abort: () => searchAbortController.abort(), + poll: async () => { + if (id) { + await search(); + } + }, + }) + : undefined; + // track if this search's session will be send to background // if yes, then we don't need to cancel this search when it is aborted - let isSavedToBackground = false; + let isSavedToBackground = + this.deps.session.isCurrentSession(sessionId) && this.deps.session.isStored(); const savedToBackgroundSub = this.deps.session.isCurrentSession(sessionId) && this.deps.session.state$ @@ -256,8 +305,15 @@ export class SearchInterceptor { ...options, abortSignal: searchAbortController.getSignal(), }).pipe( - tap((response) => (id = response.id)), + tap((response) => { + id = response.id; + + if (isCompleteResponse(response)) { + searchTracker?.complete(); + } + }), catchError((e: Error) => { + searchTracker?.error(); cancel(); return throwError(e); }), @@ -378,9 +434,6 @@ export class SearchInterceptor { ); this.pendingCount$.next(this.pendingCount$.getValue() + 1); - const untrackSearch = this.deps.session.isCurrentSession(sessionId) - ? this.deps.session.trackSearch({ abort: () => searchAbortController.abort() }) - : undefined; // Abort the replay if the abortSignal is aborted. // The underlaying search will not abort unless searchAbortController fires. @@ -410,10 +463,6 @@ export class SearchInterceptor { }), finalize(() => { this.pendingCount$.next(this.pendingCount$.getValue() - 1); - if (untrackSearch && this.deps.session.isCurrentSession(sessionId)) { - // untrack if this search still belongs to current session - untrackSearch(); - } }) ); }) diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 3fba162d7173c..c88201405d7f0 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -23,7 +23,6 @@ import { Storage } from '@kbn/kibana-utils-plugin/public'; import { ManagementSetup } from '@kbn/management-plugin/public'; import { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import moment from 'moment'; import React from 'react'; import { BehaviorSubject } from 'rxjs'; import { @@ -118,7 +117,8 @@ export class SearchService implements Plugin { this.initializerContext, getStartServices, this.sessionsClient, - nowProvider + nowProvider, + this.usageCollector ); /** * A global object that intercepts all searches and provides convenience methods for cancelling @@ -256,9 +256,6 @@ export class SearchService implements Plugin { application, basePath: http.basePath, storage: new Storage(window.localStorage), - disableSaveAfterSessionCompletesTimeout: moment - .duration(config.search.sessions.notTouchedTimeout) - .asMilliseconds(), usageCollector: this.usageCollector, tourDisabled: screenshotMode.isScreenshotMode(), }) diff --git a/src/plugins/data/public/search/session/mocks.ts b/src/plugins/data/public/search/session/mocks.ts index c6706ff8cf72d..3c64267bd1782 100644 --- a/src/plugins/data/public/search/session/mocks.ts +++ b/src/plugins/data/public/search/session/mocks.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, of } from 'rxjs'; import { ISessionsClient } from './sessions_client'; import { ISessionService } from './session_service'; import { SearchSessionState } from './search_session_state'; @@ -34,9 +34,17 @@ export function getSessionServiceMock(): jest.Mocked { state$: new BehaviorSubject(SearchSessionState.None).asObservable(), sessionMeta$: new BehaviorSubject({ state: SearchSessionState.None, + isContinued: false, }).asObservable(), + disableSaveAfterSearchesExpire$: of(false), renameCurrentSession: jest.fn(), - trackSearch: jest.fn((searchDescriptor) => () => {}), + trackSearch: jest.fn((searchDescriptor) => ({ + complete: jest.fn(), + error: jest.fn(), + beforePoll: jest.fn(() => { + return [{ isSearchStored: false }, () => {}]; + }), + })), destroy: jest.fn(), cancel: jest.fn(), isStored: jest.fn(), diff --git a/src/plugins/data/public/search/session/search_session_state.test.ts b/src/plugins/data/public/search/session/search_session_state.test.ts index 1137ceddb0da6..c85c635b7fc1a 100644 --- a/src/plugins/data/public/search/session/search_session_state.test.ts +++ b/src/plugins/data/public/search/session/search_session_state.test.ts @@ -8,7 +8,6 @@ import { createSessionStateContainer, SearchSessionState } from './search_session_state'; import type { SearchSessionSavedObject } from './sessions_client'; -import { SearchSessionStatus } from '../../../common'; const mockSavedObject: SearchSessionSavedObject = { id: 'd7170a35-7e2c-48d6-8dec-9a056721b489', @@ -19,11 +18,8 @@ const mockSavedObject: SearchSessionSavedObject = { locatorId: 'my_url_generator_id', idMapping: {}, sessionId: 'session_id', - touched: new Date().toISOString(), created: new Date().toISOString(), expires: new Date().toISOString(), - status: SearchSessionStatus.COMPLETE, - persisted: true, version: '8.0.0', }, references: [], @@ -46,7 +42,7 @@ describe('Session state container', () => { expect(state.get().appName).toBe(appName); }); - test('track', () => { + test('trackSearch', () => { expect(() => state.transitions.trackSearch({})).toThrowError(); state.transitions.start({ appName }); @@ -55,12 +51,12 @@ describe('Session state container', () => { expect(state.selectors.getState()).toBe(SearchSessionState.Loading); }); - test('untrack', () => { + test('removeSearch', () => { state.transitions.start({ appName }); const search = {}; state.transitions.trackSearch(search); expect(state.selectors.getState()).toBe(SearchSessionState.Loading); - state.transitions.unTrackSearch(search); + state.transitions.removeSearch(search); expect(state.selectors.getState()).toBe(SearchSessionState.Completed); }); @@ -95,7 +91,7 @@ describe('Session state container', () => { expect(state.selectors.getState()).toBe(SearchSessionState.Loading); state.transitions.store(mockSavedObject); expect(state.selectors.getState()).toBe(SearchSessionState.BackgroundLoading); - state.transitions.unTrackSearch(search); + state.transitions.removeSearch(search); expect(state.selectors.getState()).toBe(SearchSessionState.BackgroundCompleted); state.transitions.clear(); expect(state.selectors.getState()).toBe(SearchSessionState.None); @@ -124,7 +120,7 @@ describe('Session state container', () => { const search = {}; state.transitions.trackSearch(search); expect(state.selectors.getState()).toBe(SearchSessionState.BackgroundLoading); - state.transitions.unTrackSearch(search); + state.transitions.removeSearch(search); expect(state.selectors.getState()).toBe(SearchSessionState.Restored); expect(() => state.transitions.store(mockSavedObject)).toThrowError(); diff --git a/src/plugins/data/public/search/session/search_session_state.ts b/src/plugins/data/public/search/session/search_session_state.ts index 329d40da89b60..9b4c5d3098cc0 100644 --- a/src/plugins/data/public/search/session/search_session_state.ts +++ b/src/plugins/data/public/search/session/search_session_state.ts @@ -57,13 +57,28 @@ export enum SearchSessionState { Canceled = 'canceled', } +/** + * State of the tracked search + */ +export enum TrackedSearchState { + InProgress = 'inProgress', + Completed = 'completed', + Errored = 'errored', +} + +export interface TrackedSearch { + state: TrackedSearchState; + searchDescriptor: SearchDescriptor; + searchMeta: SearchMeta; +} + /** * Internal state of SessionService * {@link SearchSessionState} is inferred from this state * * @private */ -export interface SessionStateInternal { +export interface SessionStateInternal { /** * Current session Id * Empty means there is no current active session. @@ -92,10 +107,9 @@ export interface SessionStateInternal { isRestore: boolean; /** - * Set of currently running searches - * within a session and any info associated with them + * Set of all searches within a session and any info associated with them */ - pendingSearches: SearchDescriptor[]; + trackedSearches: Array>; /** * There was at least a single search in this session @@ -107,6 +121,17 @@ export interface SessionStateInternal { */ isCanceled: boolean; + /** + * If session was continued from a different app, + * If session continued from a different app, then it is very likely that `trackedSearches` + * doesn't have all the search that were included into the session. + * Session that was continued can't be saved because we can't guarantee all the searches saved. + * This limitation should be fixed in https://github.com/elastic/kibana/issues/121543 + * + * @deprecated - https://github.com/elastic/kibana/issues/121543 + */ + isContinued: boolean; + /** * Start time of the current session (from browser perspective) */ @@ -124,27 +149,34 @@ export interface SessionStateInternal { } const createSessionDefaultState: < - SearchDescriptor = unknown ->() => SessionStateInternal = () => ({ + SearchDescriptor = unknown, + SearchMeta extends {} = {} +>() => SessionStateInternal = () => ({ sessionId: undefined, appName: undefined, isStored: false, isRestore: false, isCanceled: false, + isContinued: false, isStarted: false, - pendingSearches: [], + trackedSearches: [], }); export interface SessionPureTransitions< SearchDescriptor = unknown, - S = SessionStateInternal + SearchMeta extends {} = {}, + S = SessionStateInternal > { start: (state: S) => ({ appName }: { appName: string }) => S; restore: (state: S) => (sessionId: string) => S; clear: (state: S) => () => S; store: (state: S) => (searchSessionSavedObject: SearchSessionSavedObject) => S; - trackSearch: (state: S) => (search: SearchDescriptor) => S; - unTrackSearch: (state: S) => (search: SearchDescriptor) => S; + trackSearch: (state: S) => (search: SearchDescriptor, meta?: SearchMeta) => S; + removeSearch: (state: S) => (search: SearchDescriptor) => S; + completeSearch: (state: S) => (search: SearchDescriptor) => S; + errorSearch: (state: S) => (search: SearchDescriptor) => S; + updateSearchMeta: (state: S) => (search: SearchDescriptor, meta: Partial) => S; + cancel: (state: S) => () => S; setSearchSessionSavedObject: ( state: S @@ -177,21 +209,78 @@ export const sessionPureTransitions: SessionPureTransitions = { searchSessionSavedObject, }; }, - trackSearch: (state) => (search) => { - if (!state.sessionId) throw new Error("Can't track search. Missing sessionId"); + trackSearch: + (state) => + (search, meta = {}) => { + if (!state.sessionId) throw new Error("Can't track search. Missing sessionId"); + return { + ...state, + isStarted: true, + trackedSearches: state.trackedSearches.concat({ + state: TrackedSearchState.InProgress, + searchDescriptor: search, + searchMeta: meta, + }), + completedTime: undefined, + }; + }, + removeSearch: (state) => (search) => { + const trackedSearches = state.trackedSearches.filter((s) => s.searchDescriptor !== search); return { ...state, - isStarted: true, - pendingSearches: state.pendingSearches.concat(search), - completedTime: undefined, + trackedSearches, + completedTime: + trackedSearches.filter((s) => s.state !== TrackedSearchState.InProgress).length === 0 + ? new Date() + : state.completedTime, }; }, - unTrackSearch: (state) => (search) => { - const pendingSearches = state.pendingSearches.filter((s) => s !== search); + completeSearch: (state) => (search) => { return { ...state, - pendingSearches, - completedTime: pendingSearches.length === 0 ? new Date() : state.completedTime, + trackedSearches: state.trackedSearches.map((s) => { + if (s.searchDescriptor === search) { + return { + ...s, + state: TrackedSearchState.Completed, + }; + } + + return s; + }), + }; + }, + errorSearch: (state) => (search) => { + return { + ...state, + trackedSearches: state.trackedSearches.map((s) => { + if (s.searchDescriptor === search) { + return { + ...s, + state: TrackedSearchState.Errored, + }; + } + + return s; + }), + }; + }, + updateSearchMeta: (state) => (search, meta) => { + return { + ...state, + trackedSearches: state.trackedSearches.map((s) => { + if (s.searchDescriptor === search) { + return { + ...s, + searchMeta: { + ...s.searchMeta, + ...meta, + }, + }; + } + + return s; + }), }; }, cancel: (state) => () => { @@ -232,14 +321,23 @@ export interface SessionMeta { startTime?: Date; canceledTime?: Date; completedTime?: Date; + + /** + * @deprecated - see remarks in {@link SessionStateInternal} + */ + isContinued: boolean; } export interface SessionPureSelectors< SearchDescriptor = unknown, - S = SessionStateInternal + SearchMeta extends {} = {}, + S = SessionStateInternal > { getState: (state: S) => () => SearchSessionState; getMeta: (state: S) => () => SessionMeta; + getSearch: ( + state: S + ) => (search: SearchDescriptor) => TrackedSearch | null; } export const sessionPureSelectors: SessionPureSelectors = { @@ -247,17 +345,22 @@ export const sessionPureSelectors: SessionPureSelectors = { if (!state.sessionId) return SearchSessionState.None; if (!state.isStarted) return SearchSessionState.None; if (state.isCanceled) return SearchSessionState.Canceled; + + const pendingSearches = state.trackedSearches.filter( + (s) => s.state === TrackedSearchState.InProgress + ); + switch (true) { case state.isRestore: - return state.pendingSearches.length > 0 + return pendingSearches.length > 0 ? SearchSessionState.BackgroundLoading : SearchSessionState.Restored; case state.isStored: - return state.pendingSearches.length > 0 + return pendingSearches.length > 0 ? SearchSessionState.BackgroundLoading : SearchSessionState.BackgroundCompleted; default: - return state.pendingSearches.length > 0 + return pendingSearches.length > 0 ? SearchSessionState.Loading : SearchSessionState.Completed; } @@ -272,24 +375,31 @@ export const sessionPureSelectors: SessionPureSelectors = { startTime: state.searchSessionSavedObject?.attributes.created ? new Date(state.searchSessionSavedObject?.attributes.created) : state.startTime, - completedTime: state.searchSessionSavedObject?.attributes.completed - ? new Date(state.searchSessionSavedObject?.attributes.completed) - : state.completedTime, + completedTime: state.completedTime, canceledTime: state.canceledTime, + isContinued: state.isContinued, }); }, + getSearch(state) { + return (search) => { + return state.trackedSearches.find((s) => s.searchDescriptor === search) ?? null; + }; + }, }; -export type SessionStateContainer = StateContainer< - SessionStateInternal, - SessionPureTransitions, - SessionPureSelectors +export type SessionStateContainer< + SearchDescriptor = unknown, + SearchMeta extends {} = {} +> = StateContainer< + SessionStateInternal, + SessionPureTransitions, + SessionPureSelectors >; -export const createSessionStateContainer = ( +export const createSessionStateContainer = ( { freeze = true }: { freeze: boolean } = { freeze: true } ): { - stateContainer: SessionStateContainer; + stateContainer: SessionStateContainer; sessionState$: Observable; sessionMeta$: Observable; } => { @@ -298,7 +408,7 @@ export const createSessionStateContainer = ( sessionPureTransitions, sessionPureSelectors, freeze ? undefined : { freeze: (s) => s } - ) as SessionStateContainer; + ) as unknown as SessionStateContainer; const sessionMeta$: Observable = stateContainer.state$.pipe( map(() => stateContainer.selectors.getMeta()), diff --git a/src/plugins/data/public/search/session/session_helpers.test.ts b/src/plugins/data/public/search/session/session_helpers.test.ts index c06185d438401..bc092a4f6ac3f 100644 --- a/src/plugins/data/public/search/session/session_helpers.test.ts +++ b/src/plugins/data/public/search/session/session_helpers.test.ts @@ -23,7 +23,13 @@ let nowProvider: jest.Mocked; let currentAppId$: BehaviorSubject; beforeEach(() => { - const initializerContext = coreMock.createPluginInitializerContext(); + const initializerContext = coreMock.createPluginInitializerContext({ + search: { + sessions: { + notTouchedTimeout: '5m', + }, + }, + }); const startService = coreMock.createSetup().getStartServices; nowProvider = createNowProviderMock(); currentAppId$ = new BehaviorSubject('app'); @@ -50,6 +56,7 @@ beforeEach(() => { ]), getSessionsClientMock(), nowProvider, + undefined, { freezeState: false } // needed to use mocks inside state container ); state$ = new BehaviorSubject(SearchSessionState.None); @@ -67,8 +74,13 @@ describe('waitUntilNextSessionCompletes$', () => { 'emits when next session starts', fakeSchedulers((advance) => { sessionService.start(); - let untrackSearch = sessionService.trackSearch({ abort: () => {} }); - untrackSearch(); + + let { complete: completeSearch } = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }); + + completeSearch(); const next = jest.fn(); const complete = jest.fn(); @@ -78,8 +90,12 @@ describe('waitUntilNextSessionCompletes$', () => { sessionService.start(); expect(next).not.toBeCalled(); - untrackSearch = sessionService.trackSearch({ abort: () => {} }); - untrackSearch(); + completeSearch = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }).complete; + + completeSearch(); expect(next).not.toBeCalled(); advance(500); diff --git a/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx b/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx index d791cf51ddbe6..9f29e2866fb61 100644 --- a/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx +++ b/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.test.tsx @@ -40,7 +40,6 @@ const timeFilter = dataStart.query.timefilter.timefilter as jest.Mocked refreshInterval$.pipe(map(() => {}))); timeFilter.getRefreshInterval.mockImplementation(() => refreshInterval$.getValue()); -const disableSaveAfterSessionCompletesTimeout = 5 * 60 * 1000; const tourDisabled = false; function Container({ children }: { children?: ReactNode }) { @@ -64,7 +63,6 @@ test("shouldn't show indicator in case no active search session", async () => { sessionService, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -93,7 +91,6 @@ test("shouldn't show indicator in case app hasn't opt-in", async () => { sessionService, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -124,7 +121,6 @@ test('should show indicator in case there is an active search session', async () sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -150,7 +146,6 @@ test('should be disabled in case uiConfig says so ', async () => { sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -175,7 +170,6 @@ test('should be disabled in case not enough permissions', async () => { sessionService: { ...sessionService, state$, hasAccess: () => false }, application, storage, - disableSaveAfterSessionCompletesTimeout, basePath, tourDisabled, }); @@ -195,20 +189,15 @@ test('should be disabled in case not enough permissions', async () => { }); describe('Completed inactivity', () => { - beforeEach(() => { - jest.useFakeTimers(); - }); - afterEach(() => { - jest.useRealTimers(); - }); test('save should be disabled after completed and timeout', async () => { const state$ = new BehaviorSubject(SearchSessionState.Loading); + const disableSaveAfterSearchesExpire$ = new BehaviorSubject(false); + const SearchSessionIndicator = createConnectedSearchSessionIndicator({ - sessionService: { ...sessionService, state$ }, + sessionService: { ...sessionService, state$, disableSaveAfterSearchesExpire$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -227,30 +216,10 @@ describe('Completed inactivity', () => { expect(screen.getByRole('button', { name: 'Save session' })).not.toBeDisabled(); act(() => { - jest.advanceTimersByTime(5 * 60 * 1000); - }); - - expect(screen.getByRole('button', { name: 'Save session' })).not.toBeDisabled(); - - act(() => { - state$.next(SearchSessionState.Completed); - }); - - expect(screen.getByRole('button', { name: 'Save session' })).not.toBeDisabled(); - - act(() => { - jest.advanceTimersByTime(2.5 * 60 * 1000); - }); - - expect(screen.getByRole('button', { name: 'Save session' })).not.toBeDisabled(); - expect(usageCollector.trackSessionIndicatorSaveDisabled).toHaveBeenCalledTimes(0); - - act(() => { - jest.advanceTimersByTime(2.5 * 60 * 1000); + disableSaveAfterSearchesExpire$.next(true); }); expect(screen.getByRole('button', { name: 'Save session' })).toBeDisabled(); - expect(usageCollector.trackSessionIndicatorSaveDisabled).toHaveBeenCalledTimes(1); }); }); @@ -270,7 +239,6 @@ describe('tour steps', () => { sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -312,7 +280,6 @@ describe('tour steps', () => { sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -347,7 +314,6 @@ describe('tour steps', () => { sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled: true, @@ -393,7 +359,6 @@ describe('tour steps', () => { sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -421,7 +386,6 @@ describe('tour steps', () => { sessionService: { ...sessionService, state$ }, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, diff --git a/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx b/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx index 727a188fc2c00..9a23342d58c62 100644 --- a/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx +++ b/src/plugins/data/public/search/session/session_indicator/connected_search_session_indicator/connected_search_session_indicator.tsx @@ -7,8 +7,8 @@ */ import React, { useCallback, useEffect, useState } from 'react'; -import { debounce, distinctUntilChanged, mapTo, switchMap, tap } from 'rxjs/operators'; -import { merge, of, timer } from 'rxjs'; +import { debounce } from 'rxjs/operators'; +import { timer } from 'rxjs'; import useObservable from 'react-use/lib/useObservable'; import { i18n } from '@kbn/i18n'; import { RedirectAppLinks } from '@kbn/kibana-react-plugin/public'; @@ -25,11 +25,6 @@ export interface SearchSessionIndicatorDeps { application: ApplicationStart; basePath: IBasePath; storage: IStorageWrapper; - /** - * Controls for how long we allow to save a session, - * after the last search in the session has completed - */ - disableSaveAfterSessionCompletesTimeout: number; tourDisabled: boolean; usageCollector?: SearchUsageCollector; } @@ -38,7 +33,6 @@ export const createConnectedSearchSessionIndicator = ({ sessionService, application, storage, - disableSaveAfterSessionCompletesTimeout, usageCollector, basePath, tourDisabled, @@ -49,25 +43,14 @@ export const createConnectedSearchSessionIndicator = ({ debounce((_state) => timer(_state === SearchSessionState.None ? 50 : 300)) // switch to None faster to quickly remove indicator when navigating away ); - const disableSaveAfterSessionCompleteTimedOut$ = sessionService.state$.pipe( - switchMap((_state) => - _state === SearchSessionState.Completed - ? merge(of(false), timer(disableSaveAfterSessionCompletesTimeout).pipe(mapTo(true))) - : of(false) - ), - distinctUntilChanged(), - tap((value) => { - if (value) usageCollector?.trackSessionIndicatorSaveDisabled(); - }) - ); - return () => { const state = useObservable(debouncedSessionServiceState$, SearchSessionState.None); const isSaveDisabledByApp = sessionService.getSearchSessionIndicatorUiConfig().isDisabled(); - const disableSaveAfterSessionCompleteTimedOut = useObservable( - disableSaveAfterSessionCompleteTimedOut$, + const disableSaveAfterSearchesExpire = useObservable( + sessionService.disableSaveAfterSearchesExpire$, false ); + const [searchSessionIndicator, setSearchSessionIndicator] = useState(null); const searchSessionIndicatorRef = useCallback((ref: SearchSessionIndicatorRef) => { @@ -82,7 +65,7 @@ export const createConnectedSearchSessionIndicator = ({ let managementDisabled = false; let managementDisabledReasonText: string = ''; - if (disableSaveAfterSessionCompleteTimedOut) { + if (disableSaveAfterSearchesExpire) { saveDisabled = true; saveDisabledReasonText = i18n.translate( 'data.searchSessionIndicator.disabledDueToTimeoutMessage', @@ -160,7 +143,7 @@ export const createConnectedSearchSessionIndicator = ({ startTime, completedTime, canceledTime, - } = useObservable(sessionService.sessionMeta$, { state }); + } = useObservable(sessionService.sessionMeta$, { state, isContinued: false }); const saveSearchSessionNameFn = useCallback(async (newName: string) => { await sessionService.renameCurrentSession(newName); }, []); diff --git a/src/plugins/data/public/search/session/session_indicator/search_session_indicator/search_session_indicator.tsx b/src/plugins/data/public/search/session/session_indicator/search_session_indicator/search_session_indicator.tsx index 239a4ea4c2aa7..465c447039e5e 100644 --- a/src/plugins/data/public/search/session/session_indicator/search_session_indicator/search_session_indicator.tsx +++ b/src/plugins/data/public/search/session/session_indicator/search_session_indicator/search_session_indicator.tsx @@ -75,7 +75,7 @@ const ContinueInBackgroundButton = ({ diff --git a/src/plugins/data/public/search/session/session_service.test.ts b/src/plugins/data/public/search/session/session_service.test.ts index d377cca07a738..7517174698d61 100644 --- a/src/plugins/data/public/search/session/session_service.test.ts +++ b/src/plugins/data/public/search/session/session_service.test.ts @@ -6,18 +6,19 @@ * Side Public License, v 1. */ -import { SessionService, ISessionService } from './session_service'; +import { ISessionService, SessionService } from './session_service'; import { coreMock } from '@kbn/core/public/mocks'; -import { take, toArray } from 'rxjs/operators'; +import { first, take, toArray } from 'rxjs/operators'; import { getSessionsClientMock } from './mocks'; import { BehaviorSubject } from 'rxjs'; import { SearchSessionState } from './search_session_state'; import { createNowProviderMock } from '../../now_provider/mocks'; import { NowProviderInternalContract } from '../../now_provider'; import { SEARCH_SESSIONS_MANAGEMENT_ID } from './constants'; -import type { SearchSessionSavedObject, ISessionsClient } from './sessions_client'; -import { SearchSessionStatus } from '../../../common'; +import type { ISessionsClient, SearchSessionSavedObject } from './sessions_client'; import { CoreStart } from '@kbn/core/public'; +import { SearchUsageCollector } from '../..'; +import { createSearchUsageCollectorMock } from '../collectors/mocks'; const mockSavedObject: SearchSessionSavedObject = { id: 'd7170a35-7e2c-48d6-8dec-9a056721b489', @@ -28,11 +29,8 @@ const mockSavedObject: SearchSessionSavedObject = { locatorId: 'my_locator_id', idMapping: {}, sessionId: 'session_id', - touched: new Date().toISOString(), created: new Date().toISOString(), expires: new Date().toISOString(), - status: SearchSessionStatus.COMPLETE, - persisted: true, version: '8.0.0', }, references: [], @@ -46,9 +44,16 @@ describe('Session service', () => { let currentAppId$: BehaviorSubject; let toastService: jest.Mocked; let sessionsClient: jest.Mocked; + let usageCollector: jest.Mocked; beforeEach(() => { - const initializerContext = coreMock.createPluginInitializerContext(); + const initializerContext = coreMock.createPluginInitializerContext({ + search: { + sessions: { + notTouchedTimeout: 5 * 60 * 1000, + }, + }, + }); const startService = coreMock.createSetup().getStartServices; const startServicesMock = coreMock.createStart(); toastService = startServicesMock.notifications.toasts; @@ -60,6 +65,7 @@ describe('Session service', () => { id, attributes: { ...mockSavedObject.attributes, sessionId: id }, })); + usageCollector = createSearchUsageCollectorMock(); sessionService = new SessionService( initializerContext, () => @@ -83,6 +89,7 @@ describe('Session service', () => { ]), sessionsClient, nowProvider, + usageCollector, { freezeState: false } // needed to use mocks inside state container ); state$ = new BehaviorSubject(SearchSessionState.None); @@ -132,34 +139,86 @@ describe('Session service', () => { }); it('Tracks searches for current session', () => { - expect(() => sessionService.trackSearch({ abort: () => {} })).toThrowError(); + expect(() => + sessionService.trackSearch({ abort: () => {}, poll: async () => {} }) + ).toThrowError(); expect(state$.getValue()).toBe(SearchSessionState.None); sessionService.start(); - const untrack1 = sessionService.trackSearch({ abort: () => {} }); + const complete1 = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }).complete; expect(state$.getValue()).toBe(SearchSessionState.Loading); - const untrack2 = sessionService.trackSearch({ abort: () => {} }); + const complete2 = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }).complete; + expect(state$.getValue()).toBe(SearchSessionState.Loading); - untrack1(); + complete1(); expect(state$.getValue()).toBe(SearchSessionState.Loading); - untrack2(); + complete2(); expect(state$.getValue()).toBe(SearchSessionState.Completed); }); it('Cancels all tracked searches within current session', async () => { const abort = jest.fn(); + const poll = jest.fn(); sessionService.start(); - sessionService.trackSearch({ abort }); - sessionService.trackSearch({ abort }); - sessionService.trackSearch({ abort }); - const untrack = sessionService.trackSearch({ abort }); + sessionService.trackSearch({ abort, poll }); + sessionService.trackSearch({ abort, poll }); + sessionService.trackSearch({ abort, poll }); + const complete = sessionService.trackSearch({ abort, poll }).complete; + complete(); - untrack(); await sessionService.cancel(); expect(abort).toBeCalledTimes(3); }); + + describe('Keeping searches alive', () => { + let dateNowSpy: jest.SpyInstance; + let now = Date.now(); + const advanceTimersBy = (by: number) => { + now = now + by; + jest.advanceTimersByTime(by); + }; + beforeEach(() => { + dateNowSpy = jest.spyOn(Date, 'now').mockImplementation(() => now); + now = Date.now(); + jest.useFakeTimers(); + }); + afterEach(() => { + dateNowSpy.mockRestore(); + jest.useRealTimers(); + }); + + it('Polls all completed searches to keep them alive', async () => { + const abort = jest.fn(); + const poll = jest.fn(() => Promise.resolve()); + + sessionService.enableStorage({ + getName: async () => 'Name', + getLocatorData: async () => ({ + id: 'id', + initialState: {}, + restoreState: {}, + }), + }); + sessionService.start(); + + const searchTracker = sessionService.trackSearch({ abort, poll }); + searchTracker.complete(); + + expect(poll).toHaveBeenCalledTimes(0); + + advanceTimersBy(30000); + + expect(poll).toHaveBeenCalledTimes(1); + }); + }); }); it('Can continue previous session from another app', async () => { @@ -171,6 +230,7 @@ describe('Session service', () => { sessionService.continue(sessionId!); expect(sessionService.getSessionId()).toBe(sessionId); + expect((await sessionService.sessionMeta$.pipe(first()).toPromise())!.isContinued).toBe(true); }); it('Calling clear() more than once still allows previous session from another app to continue', async () => { @@ -213,7 +273,7 @@ describe('Session service', () => { it('Continue drops client side loading state', async () => { const sessionId = sessionService.start(); - sessionService.trackSearch({ abort: () => {} }); + sessionService.trackSearch({ abort: () => {}, poll: async () => {} }); expect(state$.getValue()).toBe(SearchSessionState.Loading); sessionService.clear(); // even allow to call clear multiple times @@ -389,4 +449,96 @@ describe('Session service', () => { }) ); }); + + describe('disableSaveAfterSearchesExpire$', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + afterEach(() => { + jest.useRealTimers(); + }); + + test('disables save after session completes on timeout', async () => { + const emitResult: boolean[] = []; + sessionService.disableSaveAfterSearchesExpire$.subscribe((result) => { + emitResult.push(result); + }); + + sessionService.start(); + const complete = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }).complete; + + complete(); + + expect(emitResult).toEqual([false]); + + jest.advanceTimersByTime(2 * 60 * 1000); // 2 minutes + + expect(emitResult).toEqual([false]); + + jest.advanceTimersByTime(3 * 60 * 1000); // 3 minutes + + expect(emitResult).toEqual([false, true]); + + sessionService.start(); + + expect(emitResult).toEqual([false, true, false]); + }); + + test('disables save for continued from different app sessions', async () => { + const emitResult: boolean[] = []; + sessionService.disableSaveAfterSearchesExpire$.subscribe((result) => { + emitResult.push(result); + }); + + const sessionId = sessionService.start(); + + const complete = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }).complete; + + complete(); + + expect(emitResult).toEqual([false]); + + sessionService.clear(); + + sessionService.continue(sessionId); + + expect(emitResult).toEqual([false, true]); + + sessionService.start(); + + expect(emitResult).toEqual([false, true, false]); + }); + + test('emits usage once', async () => { + const emitResult: boolean[] = []; + sessionService.disableSaveAfterSearchesExpire$.subscribe((result) => { + emitResult.push(result); + }); + sessionService.disableSaveAfterSearchesExpire$.subscribe(); // testing that source is shared + + sessionService.start(); + const complete = sessionService.trackSearch({ + abort: () => {}, + poll: async () => {}, + }).complete; + + expect(usageCollector.trackSessionIndicatorSaveDisabled).toHaveBeenCalledTimes(0); + + complete(); + + jest.advanceTimersByTime(5 * 60 * 1000); // 5 minutes + + expect(usageCollector.trackSessionIndicatorSaveDisabled).toHaveBeenCalledTimes(1); + + sessionService.start(); + + expect(usageCollector.trackSessionIndicatorSaveDisabled).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/src/plugins/data/public/search/session/session_service.ts b/src/plugins/data/public/search/session/session_service.ts index 4b5d4da33132d..e71b8ed321825 100644 --- a/src/plugins/data/public/search/session/session_service.ts +++ b/src/plugins/data/public/search/session/session_service.ts @@ -7,32 +7,116 @@ */ import { PublicContract, SerializableRecord } from '@kbn/utility-types'; -import { distinctUntilChanged, map, startWith } from 'rxjs/operators'; -import { Observable, Subscription } from 'rxjs'; +import { + distinctUntilChanged, + filter, + map, + mapTo, + mergeMap, + repeat, + startWith, + switchMap, + takeUntil, + tap, +} from 'rxjs/operators'; +import { + BehaviorSubject, + combineLatest, + EMPTY, + from, + merge, + Observable, + of, + Subscription, + timer, +} from 'rxjs'; import { PluginInitializerContext, StartServicesAccessor, ToastsStart as ToastService, } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; +import moment from 'moment'; +import { SearchUsageCollector } from '../..'; import { ConfigSchema } from '../../../config'; -import { createSessionStateContainer } from './search_session_state'; import type { - SearchSessionState, SessionMeta, SessionStateContainer, SessionStateInternal, } from './search_session_state'; +import { + createSessionStateContainer, + SearchSessionState, + TrackedSearchState, +} from './search_session_state'; import { ISessionsClient } from './sessions_client'; import { ISearchOptions } from '../../../common'; import { NowProviderInternalContract } from '../../now_provider'; import { SEARCH_SESSIONS_MANAGEMENT_ID } from './constants'; import { formatSessionName } from './lib/session_name_formatter'; +/** + * Polling interval for keeping completed searches alive + * until the user saves the session + */ +const KEEP_ALIVE_COMPLETED_SEARCHES_INTERVAL = 30000; + export type ISessionService = PublicContract; interface TrackSearchDescriptor { + /** + * Cancel the search + */ abort: () => void; + + /** + * Keep polling the search to keep it alive + */ + poll: () => Promise; + + /** + * Notify search that session is being saved, could be used to restart the search with different params + * @deprecated - this is used as an escape hatch for TSVB/Timelion to restart a search with different params + */ + onSavingSession?: ( + options: Required> + ) => Promise; +} + +interface TrackSearchMeta { + /** + * Time that indicates when last time this search was polled + */ + lastPollingTime: Date; + + /** + * If the keep_alive of this search was extended up to saved session keep_alive + */ + isStored: boolean; +} + +/** + * Api to manage tracked search + */ +interface TrackSearchHandler { + /** + * Transition search into "complete" status + */ + complete(): void; + + /** + * Transition search into "error" status + */ + error(): void; + + /** + * Call to notify when search is about to be polled to get current search state to build `searchOptions` from (mainly isSearchStored), + * When poll completes or errors, call `afterPoll` callback and confirm is search was successfully stored + */ + beforePoll(): [ + currentSearchState: { isSearchStored: boolean }, + afterPoll: (newSearchState: { isSearchStored: boolean }) => void + ]; } /** @@ -82,9 +166,26 @@ interface SearchSessionIndicatorUiConfig { */ export class SessionService { public readonly state$: Observable; - private readonly state: SessionStateContainer; + private readonly state: SessionStateContainer; public readonly sessionMeta$: Observable; + + /** + * Emits `true` when session completes and `config.search.sessions.notTouchedTimeout` duration has passed. + * Used to stop keeping searches alive after some times and disabled "save session" button + * + * or when failed to extend searches after session completes + */ + private readonly _disableSaveAfterSearchesExpire$ = new BehaviorSubject(false); + + /** + * Emits `true` when it is no longer possible to save a session: + * - Failed to keep searches alive after they completed + * - `config.search.sessions.notTouchedTimeout` after searches completed hit + * - Continued session from a different app and lost information about previous searches (https://github.com/elastic/kibana/issues/121543) + */ + public readonly disableSaveAfterSearchesExpire$: Observable; + private searchSessionInfoProvider?: SearchSessionInfoProvider; private searchSessionIndicatorUiConfig?: Partial; private subscription = new Subscription(); @@ -105,16 +206,50 @@ export class SessionService { getStartServices: StartServicesAccessor, private readonly sessionsClient: ISessionsClient, private readonly nowProvider: NowProviderInternalContract, + private readonly usageCollector?: SearchUsageCollector, { freezeState = true }: { freezeState: boolean } = { freezeState: true } ) { - const { stateContainer, sessionState$, sessionMeta$ } = - createSessionStateContainer({ - freeze: freezeState, - }); + const { stateContainer, sessionState$, sessionMeta$ } = createSessionStateContainer< + TrackSearchDescriptor, + TrackSearchMeta + >({ + freeze: freezeState, + }); this.state$ = sessionState$; this.state = stateContainer; this.sessionMeta$ = sessionMeta$; + this.disableSaveAfterSearchesExpire$ = combineLatest([ + this._disableSaveAfterSearchesExpire$, + this.sessionMeta$.pipe(map((meta) => meta.isContinued)), + ]).pipe( + map( + ([_disableSaveAfterSearchesExpire, isSessionContinued]) => + _disableSaveAfterSearchesExpire || isSessionContinued + ), + distinctUntilChanged() + ); + + const notTouchedTimeout = moment + .duration(initializerContext.config.get().search.sessions.notTouchedTimeout) + .asMilliseconds(); + + this.subscription.add( + this.state$ + .pipe( + switchMap((_state) => + _state === SearchSessionState.Completed + ? merge(of(false), timer(notTouchedTimeout).pipe(mapTo(true))) + : of(false) + ), + distinctUntilChanged(), + tap((value) => { + if (value) this.usageCollector?.trackSessionIndicatorSaveDisabled(); + }) + ) + .subscribe(this._disableSaveAfterSearchesExpire$) + ); + this.subscription.add( sessionMeta$ .pipe( @@ -155,6 +290,54 @@ export class SessionService { }) ); }); + + // keep completed searches alive until user explicitly saves the session + this.subscription.add( + this.getSession$() + .pipe( + switchMap((sessionId) => { + if (!sessionId) return EMPTY; + if (this.isStored()) return EMPTY; // no need to keep searches alive because session and searches are already stored + if (!this.hasAccess()) return EMPTY; // don't need to keep searches alive if the user can't save session + if (!this.isSessionStorageReady()) return EMPTY; // don't need to keep searches alive if app doesn't allow saving session + + const schedulePollSearches = () => { + return timer(KEEP_ALIVE_COMPLETED_SEARCHES_INTERVAL).pipe( + mergeMap(() => { + const searchesToKeepAlive = this.state.get().trackedSearches.filter( + (s) => + !s.searchMeta.isStored && + s.state === TrackedSearchState.Completed && + s.searchMeta.lastPollingTime.getTime() < Date.now() - 5000 // don't poll if was very recently polled + ); + + return from( + Promise.all( + searchesToKeepAlive.map((s) => + s.searchDescriptor.poll().catch((e) => { + // eslint-disable-next-line no-console + console.warn( + `Error while polling search to keep it alive. Considering that it is no longer possible to extend a session.`, + e + ); + if (this.isCurrentSession(sessionId)) { + this._disableSaveAfterSearchesExpire$.next(true); + } + }) + ) + ) + ); + }), + repeat(), + takeUntil(this.disableSaveAfterSearchesExpire$.pipe(filter((disable) => disable))) + ); + }; + + return schedulePollSearches(); + }) + ) + .subscribe(() => {}) + ); } /** @@ -167,15 +350,51 @@ export class SessionService { } /** - * Used to track pending searches within current session + * Used to track searches within current session * - * @param searchDescriptor - uniq object that will be used to untrack the search - * @returns untrack function + * @param searchDescriptor - uniq object that will be used to as search identifier + * @returns {@link TrackSearchHandler} */ - public trackSearch(searchDescriptor: TrackSearchDescriptor): () => void { - this.state.transitions.trackSearch(searchDescriptor); - return () => { - this.state.transitions.unTrackSearch(searchDescriptor); + public trackSearch(searchDescriptor: TrackSearchDescriptor): TrackSearchHandler { + this.state.transitions.trackSearch(searchDescriptor, { + lastPollingTime: new Date(), + isStored: false, + }); + + return { + complete: () => { + this.state.transitions.completeSearch(searchDescriptor); + + // when search completes and session has just been saved, + // trigger polling once again to save search into a session and extend its keep_alive + if (this.isStored()) { + const search = this.state.selectors.getSearch(searchDescriptor); + if (search && !search.searchMeta.isStored) { + search.searchDescriptor.poll().catch((e) => { + // eslint-disable-next-line no-console + console.warn(`Failed to extend search after it was completed`, e); + }); + } + } + }, + error: () => { + this.state.transitions.errorSearch(searchDescriptor); + }, + beforePoll: () => { + const search = this.state.selectors.getSearch(searchDescriptor); + this.state.transitions.updateSearchMeta(searchDescriptor, { + lastPollingTime: new Date(), + }); + + return [ + { isSearchStored: search?.searchMeta?.isStored ?? false }, + ({ isSearchStored }) => { + this.state.transitions.updateSearchMeta(searchDescriptor, { + isStored: isSearchStored, + }); + }, + ]; + }, }; } @@ -244,6 +463,12 @@ export class SessionService { * * This is different from {@link restore} as it reuses search session state and search results held in client memory instead of restoring search results from elasticsearch * @param sessionId + * + * TODO: remove this functionality in favor of separate architecture for client side search cache + * that won't interfere with saving search sessions + * https://github.com/elastic/kibana/issues/121543 + * + * @deprecated */ public continue(sessionId: string) { if (this.lastSessionSnapshot?.sessionId === sessionId) { @@ -254,7 +479,8 @@ export class SessionService { // also have to drop all pending searches which are used to derive client side state of search session indicator, // if we weren't dropping this searches, then we would get into "infinite loading" state when continuing a session that was cleared with pending searches // possible solution to this problem is to refactor session service to support multiple sessions - pendingSearches: [], + trackedSearches: [], + isContinued: true, }); this.lastSessionSnapshot = undefined; } else { @@ -293,10 +519,13 @@ export class SessionService { * Request a cancellation of on-going search requests within current session */ public async cancel(): Promise { - const isStoredSession = this.state.get().isStored; - this.state.get().pendingSearches.forEach((s) => { - s.abort(); - }); + const isStoredSession = this.isStored(); + this.state + .get() + .trackedSearches.filter((s) => s.state === TrackedSearchState.InProgress) + .forEach((s) => { + s.searchDescriptor.abort(); + }); this.state.transitions.cancel(); if (isStoredSession) { await this.sessionsClient.delete(this.state.get().sessionId!); @@ -335,8 +564,41 @@ export class SessionService { }); // if we are still interested in this result - if (this.getSessionId() === sessionId) { + if (this.isCurrentSession(sessionId)) { this.state.transitions.store(searchSessionSavedObject); + + // trigger new poll for all completed searches that are not stored to propogate them into newly creates search session saved object and extend their keepAlive + const completedSearches = this.state + .get() + .trackedSearches.filter( + (s) => s.state === TrackedSearchState.Completed && !s.searchMeta.isStored + ); + const pollCompletedSearchesPromise = Promise.all( + completedSearches.map((s) => + s.searchDescriptor.poll().catch((e) => { + // eslint-disable-next-line no-console + console.warn('Failed to extend search after session was saved', e); + }) + ) + ); + + // notify all the searches with onSavingSession that session has been saved and saved object has been created + // don't wait for the result + const searchesWithSavingHandler = this.state + .get() + .trackedSearches.filter((s) => s.searchDescriptor.onSavingSession); + searchesWithSavingHandler.forEach((s) => + s.searchDescriptor.onSavingSession!({ + sessionId, + isRestore: this.isRestore(), + isStored: this.isStored(), + }).catch((e) => { + // eslint-disable-next-line no-console + console.warn('Failed to execute "onSavingSession" handler after session was saved', e); + }) + ); + + await pollCompletedSearchesPromise; } } diff --git a/src/plugins/data/public/search/session/sessions_client.ts b/src/plugins/data/public/search/session/sessions_client.ts index 12fd424e57dd8..80fe88c22a951 100644 --- a/src/plugins/data/public/search/session/sessions_client.ts +++ b/src/plugins/data/public/search/session/sessions_client.ts @@ -14,7 +14,10 @@ import type { SavedObjectsUpdateResponse, SavedObjectsFindOptions, } from '@kbn/core/server'; -import type { SearchSessionSavedObjectAttributes } from '../../../common'; +import type { + SearchSessionSavedObjectAttributes, + SearchSessionsFindResponse, +} from '../../../common'; export type SearchSessionSavedObject = SavedObject; export type ISessionsClient = PublicContract; export interface SessionsClientDeps { @@ -62,7 +65,7 @@ export class SessionsClient { }); } - public find(options: Omit): Promise { + public find(options: Omit): Promise { return this.http!.post(`/internal/session/_find`, { body: JSON.stringify(options), }); diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/table/app_filter.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/table/app_filter.tsx index 48cfda93e1f91..05070814d9a5d 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/table/app_filter.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/table/app_filter.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FieldValueOptionType, SearchFilterConfig } from '@elastic/eui'; +import { SearchFilterConfig } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { capitalize } from 'lodash'; import { UISession } from '../../types'; @@ -18,12 +18,7 @@ export const getAppFilter: (tableData: UISession[]) => SearchFilterConfig = (tab }), field: 'appId', multiSelect: 'or', - options: tableData.reduce((options: FieldValueOptionType[], { appId }) => { - const existingOption = options.find((o) => o.value === appId); - if (!existingOption) { - return [...options, { value: appId, view: capitalize(appId) }]; - } - - return options; - }, []), + options: [...new Set(tableData.map((data) => data.appId ?? 'unknown'))] + .sort() + .map((appId) => ({ value: appId, view: capitalize(appId) })), }); diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/table/status_filter.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/table/status_filter.tsx index 25fc7dc092ab8..bf34b72c7971f 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/table/status_filter.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/table/status_filter.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FieldValueOptionType, SearchFilterConfig } from '@elastic/eui'; +import { SearchFilterConfig } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { TableText } from '..'; @@ -20,14 +20,7 @@ export const getStatusFilter: (tableData: UISession[]) => SearchFilterConfig = ( }), field: 'status', multiSelect: 'or', - options: tableData.reduce((options: FieldValueOptionType[], session) => { - const { status: statusType } = session; - const existingOption = options.find((o) => o.value === statusType); - if (!existingOption) { - const view = {getStatusText(session.status)}; - return [...options, { value: statusType, view }]; - } - - return options; - }, []), + options: [...new Set(tableData.map((data) => data.status ?? 'unknown'))] + .sort() + .map((status) => ({ value: status, view: {getStatusText(status)} })), }); diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx index 1fe4dbe0468ee..ac554af701d04 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.test.tsx @@ -68,13 +68,15 @@ describe('Background Search Session Management Table', () => { id: 'wtywp9u2802hahgp-flps', url: '/app/great-app-url/#48', appId: 'canvas', - status: SearchSessionStatus.IN_PROGRESS, created: '2020-12-02T00:19:32Z', expires: '2020-12-07T00:19:32Z', idMapping: {}, }, }, ], + statuses: { + 'wtywp9u2802hahgp-flps': { status: SearchSessionStatus.EXPIRED }, + }, }; }; diff --git a/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.tsx b/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.tsx index b887d9af43f53..833ad3ec7e75e 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.tsx +++ b/src/plugins/data/public/search/session/sessions_mgmt/components/table/table.tsx @@ -12,7 +12,6 @@ import { CoreStart } from '@kbn/core/public'; import moment from 'moment'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import useDebounce from 'react-use/lib/useDebounce'; -import useInterval from 'react-use/lib/useInterval'; import { TableText } from '..'; import { SEARCH_SESSIONS_TABLE_ID } from '../../../../../../common'; import { SearchSessionsMgmtAPI } from '../../lib/api'; @@ -47,6 +46,7 @@ export function SearchSessionsMgmtTable({ const [debouncedIsLoading, setDebouncedIsLoading] = useState(false); const [pagination, setPagination] = useState({ pageIndex: 0 }); const showLatestResultsHandler = useRef(); + const refreshTimeoutRef = useRef(null); const refreshInterval = useMemo( () => moment.duration(config.management.refreshInterval).asMilliseconds(), [config.management.refreshInterval] @@ -63,30 +63,44 @@ export function SearchSessionsMgmtTable({ // refresh behavior const doRefresh = useCallback(async () => { + if (refreshTimeoutRef.current) { + clearTimeout(refreshTimeoutRef.current); + refreshTimeoutRef.current = null; + } + setIsLoading(true); const renderResults = (results: UISession[]) => { setTableData(results); }; showLatestResultsHandler.current = renderResults; - let results: UISession[] = []; - try { - results = await api.fetchTableData(); - } catch (e) {} // eslint-disable-line no-empty - if (showLatestResultsHandler.current === renderResults) { - renderResults(results); - setIsLoading(false); + if (document.visibilityState !== 'hidden') { + let results: UISession[] = []; + try { + results = await api.fetchTableData(); + } catch (e) {} // eslint-disable-line no-empty + + if (showLatestResultsHandler.current === renderResults) { + renderResults(results); + setIsLoading(false); + } } - }, [api]); + + if (showLatestResultsHandler.current === renderResults && refreshInterval > 0) { + if (refreshTimeoutRef.current) clearTimeout(refreshTimeoutRef.current); + refreshTimeoutRef.current = window.setTimeout(doRefresh, refreshInterval); + } + }, [api, refreshInterval]); // initial data load useEffect(() => { doRefresh(); searchUsageCollector.trackSessionsListLoaded(); + return () => { + if (refreshTimeoutRef.current) clearTimeout(refreshTimeoutRef.current); + }; }, [doRefresh, searchUsageCollector]); - useInterval(doRefresh, refreshInterval); - const onActionComplete: OnActionComplete = () => { doRefresh(); }; diff --git a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts index 29a925d066905..73e1e8dc08668 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts +++ b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.test.ts @@ -52,14 +52,16 @@ describe('Search Sessions Management API', () => { attributes: { name: 'Veggie', appId: 'pizza', - status: 'complete', initialState: {}, restoreState: {}, idMapping: [], }, }, ], - } as SavedObjectsFindResponse; + statuses: { + 'hello-pizza-123': { status: 'complete' }, + }, + }; }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { @@ -93,7 +95,7 @@ describe('Search Sessions Management API', () => { `); }); - test('completed session with expired time is showed as expired', async () => { + test('expired session is showed as expired', async () => { sessionsClient.find = jest.fn().mockImplementation(async () => { return { saved_objects: [ @@ -102,7 +104,6 @@ describe('Search Sessions Management API', () => { attributes: { name: 'Veggie', appId: 'pizza', - status: 'complete', expires: moment().subtract(3, 'days'), initialState: {}, restoreState: {}, @@ -110,7 +111,10 @@ describe('Search Sessions Management API', () => { }, }, ], - } as SavedObjectsFindResponse; + statuses: { + 'hello-pizza-123': { status: 'expired' }, + }, + }; }); const api = new SearchSessionsMgmtAPI(sessionsClient, mockConfig, { diff --git a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts index 9830cb436f7df..4fac2d36203c4 100644 --- a/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts +++ b/src/plugins/data/public/search/session/sessions_mgmt/lib/api.ts @@ -21,7 +21,7 @@ import { } from '../types'; import { ISessionsClient } from '../../sessions_client'; import { SearchUsageCollector } from '../../../collectors'; -import { SearchSessionStatus } from '../../../../../common'; +import { SearchSessionsFindResponse, SearchSessionStatus } from '../../../../../common'; import { SearchSessionsConfigSchema } from '../../../../../config'; type LocatorsStart = SharePluginStart['url']['locators']; @@ -42,25 +42,6 @@ function getActions(status: UISearchSessionState) { return actions; } -/** - * Status we display on mgtm UI might be different from the one inside the saved object - * @param status - */ -function getUIStatus(session: PersistedSearchSessionSavedObjectAttributes): UISearchSessionState { - const isSessionExpired = () => { - const curTime = moment(); - return curTime.diff(moment(session.expires), 'ms') > 0; - }; - - switch (session.status) { - case SearchSessionStatus.COMPLETE: - case SearchSessionStatus.IN_PROGRESS: - return isSessionExpired() ? SearchSessionStatus.EXPIRED : session.status; - } - - return session.status; -} - function getUrlFromState(locators: LocatorsStart, locatorId: string, state: SerializableRecord) { try { const locator = locators.get(locatorId); @@ -75,7 +56,11 @@ function getUrlFromState(locators: LocatorsStart, locatorId: string, state: Seri // Helper: factory for a function to map server objects to UI objects const mapToUISession = - (locators: LocatorsStart, config: SearchSessionsConfigSchema) => + ( + locators: LocatorsStart, + config: SearchSessionsConfigSchema, + sessionStatuses: SearchSessionsFindResponse['statuses'] + ) => async ( savedObject: SavedObject ): Promise => { @@ -91,7 +76,7 @@ const mapToUISession = version, } = savedObject.attributes; - const status = getUIStatus(savedObject.attributes); + const status = sessionStatuses[savedObject.id]?.status; const actions = getActions(status); // TODO: initialState should be saved without the searchSessionID @@ -141,9 +126,7 @@ export class SearchSessionsMgmtAPI { page: 1, perPage: mgmtConfig.maxSessions, sortField: 'created', - sortOrder: 'asc', - searchFields: ['persisted'], - search: 'true', + sortOrder: 'desc', }) ); const timeout$ = timer(refreshTimeout.asMilliseconds()).pipe( @@ -165,7 +148,9 @@ export class SearchSessionsMgmtAPI { const savedObjects = result.saved_objects as Array< SavedObject >; - return await Promise.all(savedObjects.map(mapToUISession(this.deps.locators, this.config))); + return await Promise.all( + savedObjects.map(mapToUISession(this.deps.locators, this.config, result.statuses)) + ); } } catch (err) { // eslint-disable-next-line no-console diff --git a/src/plugins/data/server/config_deprecations.test.ts b/src/plugins/data/server/config_deprecations.test.ts index 9c54c793f661a..674e1e9a6435b 100644 --- a/src/plugins/data/server/config_deprecations.test.ts +++ b/src/plugins/data/server/config_deprecations.test.ts @@ -64,4 +64,87 @@ describe('Config Deprecations', () => { ] `); }); + + test('reports about old, no longer used configs', () => { + const config = { + data: { + search: { + sessions: { + enabled: false, + pageSize: 1000, + trackingInterval: '30s', + cleanupInterval: '30s', + expireInterval: '30s', + monitoringTaskTimeout: '30s', + notTouchedInProgressTimeout: '30s', + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated).toMatchInlineSnapshot(` + Object { + "data": Object { + "search": Object { + "sessions": Object { + "enabled": false, + }, + }, + }, + } + `); + expect(messages).toMatchInlineSnapshot(` + Array [ + "You no longer need to configure \\"data.search.sessions.pageSize\\".", + "You no longer need to configure \\"data.search.sessions.trackingInterval\\".", + "You no longer need to configure \\"data.search.sessions.cleanupInterval\\".", + "You no longer need to configure \\"data.search.sessions.expireInterval\\".", + "You no longer need to configure \\"data.search.sessions.monitoringTaskTimeout\\".", + "You no longer need to configure \\"data.search.sessions.notTouchedInProgressTimeout\\".", + ] + `); + }); + + test('reports about old, no longer used configs from xpack.data_enhanced', () => { + const config = { + xpack: { + data_enhanced: { + search: { + sessions: { + enabled: false, + pageSize: 1000, + trackingInterval: '30s', + cleanupInterval: '30s', + expireInterval: '30s', + monitoringTaskTimeout: '30s', + notTouchedInProgressTimeout: '30s', + }, + }, + }, + }, + }; + const { messages, migrated } = applyConfigDeprecations(cloneDeep(config)); + expect(migrated).toMatchInlineSnapshot(` + Object { + "data": Object { + "search": Object { + "sessions": Object { + "enabled": false, + }, + }, + }, + } + `); + expect(messages).toMatchInlineSnapshot(` + Array [ + "Setting \\"xpack.data_enhanced.search.sessions\\" has been replaced by \\"data.search.sessions\\"", + "You no longer need to configure \\"data.search.sessions.pageSize\\".", + "You no longer need to configure \\"data.search.sessions.trackingInterval\\".", + "You no longer need to configure \\"data.search.sessions.cleanupInterval\\".", + "You no longer need to configure \\"data.search.sessions.expireInterval\\".", + "You no longer need to configure \\"data.search.sessions.monitoringTaskTimeout\\".", + "You no longer need to configure \\"data.search.sessions.notTouchedInProgressTimeout\\".", + ] + `); + }); }); diff --git a/src/plugins/data/server/config_deprecations.ts b/src/plugins/data/server/config_deprecations.ts index dcc168f306e1e..3adbcf1c2178d 100644 --- a/src/plugins/data/server/config_deprecations.ts +++ b/src/plugins/data/server/config_deprecations.ts @@ -8,8 +8,17 @@ import type { ConfigDeprecationProvider } from '@kbn/core/server'; -export const configDeprecationProvider: ConfigDeprecationProvider = ({ renameFromRoot }) => [ +export const configDeprecationProvider: ConfigDeprecationProvider = ({ + renameFromRoot, + unusedFromRoot, +}) => [ renameFromRoot('xpack.data_enhanced.search.sessions', 'data.search.sessions', { level: 'warning', }), + unusedFromRoot('data.search.sessions.pageSize', { level: 'warning' }), + unusedFromRoot('data.search.sessions.trackingInterval', { level: 'warning' }), + unusedFromRoot('data.search.sessions.cleanupInterval', { level: 'warning' }), + unusedFromRoot('data.search.sessions.expireInterval', { level: 'warning' }), + unusedFromRoot('data.search.sessions.monitoringTaskTimeout', { level: 'warning' }), + unusedFromRoot('data.search.sessions.notTouchedInProgressTimeout', { level: 'warning' }), ]; diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index 31944922c7b44..8630f2be1585c 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -42,5 +42,6 @@ export function createSearchRequestHandlerContext() { extendSession: jest.fn(), cancelSession: jest.fn(), deleteSession: jest.fn(), + getSessionStatus: jest.fn(), }; } diff --git a/src/plugins/data/server/search/routes/session.test.ts b/src/plugins/data/server/search/routes/session.test.ts index dbc12e44b7a2b..2fdf02c86ce6b 100644 --- a/src/plugins/data/server/search/routes/session.test.ts +++ b/src/plugins/data/server/search/routes/session.test.ts @@ -65,6 +65,21 @@ describe('registerSessionRoutes', () => { expect(mockContext.search!.getSession).toHaveBeenCalledWith(id); }); + it('status calls getSessionStatus with sessionId', async () => { + const id = 'd7170a35-7e2c-48d6-8dec-9a056721b489'; + const params = { id }; + + const mockRequest = httpServerMock.createKibanaRequest({ params }); + const mockResponse = httpServerMock.createResponseFactory(); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const [[], [, statusHandler]] = mockRouter.get.mock.calls; + + await statusHandler(mockContext, mockRequest, mockResponse); + + expect(mockContext.search!.getSessionStatus).toHaveBeenCalledWith(id); + }); + it('find calls findSession with options', async () => { const page = 1; const perPage = 5; diff --git a/src/plugins/data/server/search/routes/session.ts b/src/plugins/data/server/search/routes/session.ts index 6106a69df207a..c654fcb53adbd 100644 --- a/src/plugins/data/server/search/routes/session.ts +++ b/src/plugins/data/server/search/routes/session.ts @@ -86,6 +86,35 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger): } ); + router.get( + { + path: '/internal/session/{id}/status', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + options: { + tags: [STORE_SEARCH_SESSIONS_ROLE_TAG], + }, + }, + async (context, request, res) => { + const { id } = request.params; + try { + const searchContext = await context.search; + const response = await searchContext!.getSessionStatus(id); + + return res.ok({ + body: response, + }); + } catch (e) { + const err = e.output?.payload || e; + logger.error(err); + return reportServerError(res, err); + } + } + ); + router.post( { path: '/internal/session/_find', diff --git a/src/plugins/data/server/search/saved_objects/search_session.ts b/src/plugins/data/server/search/saved_objects/search_session.ts index c77c8379af365..3eb1c6190dd6e 100644 --- a/src/plugins/data/server/search/saved_objects/search_session.ts +++ b/src/plugins/data/server/search/saved_objects/search_session.ts @@ -16,9 +16,6 @@ export const searchSessionSavedObjectType: SavedObjectsType = { hidden: true, mappings: { properties: { - persisted: { - type: 'boolean', - }, sessionId: { type: 'keyword', }, @@ -31,15 +28,6 @@ export const searchSessionSavedObjectType: SavedObjectsType = { expires: { type: 'date', }, - touched: { - type: 'date', - }, - completed: { - type: 'date', - }, - status: { - type: 'keyword', - }, appId: { type: 'keyword', }, @@ -70,6 +58,9 @@ export const searchSessionSavedObjectType: SavedObjectsType = { version: { type: 'keyword', }, + isCanceled: { + type: 'boolean', + }, }, }, migrations: searchSessionSavedObjectMigrations, diff --git a/src/plugins/data/server/search/saved_objects/search_session_migration.test.ts b/src/plugins/data/server/search/saved_objects/search_session_migration.test.ts index 251d57e884ac1..f18ac70bc4f43 100644 --- a/src/plugins/data/server/search/saved_objects/search_session_migration.test.ts +++ b/src/plugins/data/server/search/saved_objects/search_session_migration.test.ts @@ -11,9 +11,10 @@ import { SearchSessionSavedObjectAttributesPre$7$13$0, SearchSessionSavedObjectAttributesPre$7$14$0, SearchSessionSavedObjectAttributesPre$8$0$0, + SearchSessionSavedObjectAttributesPre$8$6$0, } from './search_session_migration'; import { SavedObject } from '@kbn/core/types'; -import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common'; +import { SEARCH_SESSION_TYPE, SearchSessionStatus, SearchStatus } from '../../../common'; import { SavedObjectMigrationContext } from '@kbn/core/server'; describe('7.12.0 -> 7.13.0', () => { @@ -356,3 +357,98 @@ describe('7.14.0 -> 8.0.0', () => { ); }); }); + +describe('8.0.0 -> 8.6.0', () => { + const migration = searchSessionSavedObjectMigrations['8.6.0']; + + const mockSessionSavedObject: SavedObject = { + id: 'id', + type: SEARCH_SESSION_TYPE, + attributes: { + appId: 'my_app_id', + completed: '2021-03-29T00:00:00.000Z', + created: '2021-03-26T00:00:00.000Z', + expires: '2021-03-30T00:00:00.000Z', + idMapping: { + search1: { id: 'id1', strategy: 'ese', status: SearchStatus.COMPLETE }, + search2: { + id: 'id2', + strategy: 'sql', + status: SearchStatus.ERROR, + error: 'error', + }, + search3: { id: 'id3', strategy: 'es', status: SearchStatus.COMPLETE }, + }, + initialState: {}, + locatorId: undefined, + name: 'my_name', + persisted: true, + realmName: 'realmName', + realmType: 'realmType', + restoreState: {}, + sessionId: 'sessionId', + status: SearchSessionStatus.COMPLETE, + touched: '2021-03-29T00:00:00.000Z', + username: 'username', + version: '7.14.0', + }, + references: [], + }; + + test('migrates object', () => { + const migratedSession = migration(mockSessionSavedObject, {} as SavedObjectMigrationContext); + + expect(migratedSession.attributes).not.toHaveProperty('status'); + expect(migratedSession.attributes).not.toHaveProperty('touched'); + expect(migratedSession.attributes).not.toHaveProperty('completed'); + expect(migratedSession.attributes).not.toHaveProperty('persisted'); + expect(migratedSession.attributes.idMapping.search1).not.toHaveProperty('status'); + expect(migratedSession.attributes.idMapping.search2).not.toHaveProperty('error'); + + expect(migratedSession.attributes).toMatchInlineSnapshot(` + Object { + "appId": "my_app_id", + "created": "2021-03-26T00:00:00.000Z", + "expires": "2021-03-30T00:00:00.000Z", + "idMapping": Object { + "search1": Object { + "id": "id1", + "strategy": "ese", + }, + "search2": Object { + "id": "id2", + "strategy": "sql", + }, + "search3": Object { + "id": "id3", + "strategy": "es", + }, + }, + "initialState": Object {}, + "locatorId": undefined, + "name": "my_name", + "realmName": "realmName", + "realmType": "realmType", + "restoreState": Object {}, + "sessionId": "sessionId", + "username": "username", + "version": "7.14.0", + } + `); + }); + + test('status:canceled -> isCanceled', () => { + const migratedSession = migration( + { + ...mockSessionSavedObject, + attributes: { + ...mockSessionSavedObject.attributes, + status: SearchSessionStatus.CANCELLED, + }, + }, + {} as SavedObjectMigrationContext + ); + + expect(migratedSession.attributes.isCanceled).toBe(true); + }); +}); diff --git a/src/plugins/data/server/search/saved_objects/search_session_migration.ts b/src/plugins/data/server/search/saved_objects/search_session_migration.ts index 314db0fb8b58f..fec4e3c33a93b 100644 --- a/src/plugins/data/server/search/saved_objects/search_session_migration.ts +++ b/src/plugins/data/server/search/saved_objects/search_session_migration.ts @@ -39,12 +39,39 @@ export type SearchSessionSavedObjectAttributesPre$7$14$0 = Omit< * from using `urlGeneratorId` to `locatorId`. */ export type SearchSessionSavedObjectAttributesPre$8$0$0 = Omit< - SearchSessionSavedObjectAttributesLatest, + SearchSessionSavedObjectAttributesPre$8$6$0, 'locatorId' > & { urlGeneratorId?: string; }; +/** + * In 8.6.0 with search session refactoring and moving away from using task manager we are no longer track of: + * - `completed` - when session was completed + * - `persisted` - if session was saved + * - `touched` - when session was last updated (touched by the user) + * - `status` - status is no longer persisted. Except 'canceled' which was moved to `isCanceled` + * - `status` and `error` in idMapping (search info) + */ +export type SearchSessionSavedObjectAttributesPre$8$6$0 = Omit< + SearchSessionSavedObjectAttributesLatest, + 'idMapping' | 'isCanceled' +> & { + completed?: string | null; + persisted: boolean; + touched: string; + status: SearchSessionStatus; + idMapping: Record< + string, + { + id: string; + strategy: string; + status: string; + error?: string; + } + >; +}; + function getLocatorId(urlGeneratorId?: string) { if (!urlGeneratorId) return; if (urlGeneratorId === 'DISCOVER_APP_URL_GENERATOR') return 'DISCOVER_APP_LOCATOR'; @@ -89,4 +116,27 @@ export const searchSessionSavedObjectMigrations: SavedObjectMigrationMap = { const attributes = { ...otherAttrs, locatorId }; return { ...doc, attributes }; }, + '8.6.0': ( + doc: SavedObjectUnsanitizedDoc + ): SavedObjectUnsanitizedDoc => { + const { + attributes: { touched, completed, persisted, idMapping, status, ...otherAttrs }, + } = doc; + + const attributes: SearchSessionSavedObjectAttributesLatest = { + ...otherAttrs, + idMapping: Object.entries(idMapping).reduce< + SearchSessionSavedObjectAttributesLatest['idMapping'] + >((res, [searchHash, { status: searchStatus, error, ...otherSearchAttrs }]) => { + res[searchHash] = otherSearchAttrs; + return res; + }, {}), + }; + + if (status === SearchSessionStatus.CANCELLED) { + attributes.isCanceled = true; + } + + return { ...doc, attributes }; + }, }; diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index 56733b6871ec8..cb3575caec510 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -33,6 +33,8 @@ import { ENHANCED_ES_SEARCH_STRATEGY } from '../../common'; let mockSessionClient: jest.Mocked; jest.mock('./session', () => { class SearchSessionService { + setup() {} + start() {} asScopedProvider = () => (request: any) => mockSessionClient; } return { @@ -193,7 +195,7 @@ describe('Search service', () => { it('does not fail if `trackId` throws', async () => { const searchRequest = { params: {} }; - const options = { sessionId, isStored: false, isRestore: false }; + const options = { sessionId, isStored: true, isRestore: false }; mockSessionClient.trackId = jest.fn().mockRejectedValue(undefined); mockStrategy.search.mockReturnValue( @@ -203,14 +205,32 @@ describe('Search service', () => { }) ); - await mockScopedClient.search(searchRequest, options).toPromise(); + const result = await mockScopedClient.search(searchRequest, options).toPromise(); expect(mockSessionClient.trackId).toBeCalledTimes(1); + expect(result?.isStored).toBeUndefined(); }); - it('calls `trackId` for every response, if the response contains an `id` and not restoring', async () => { + it("doesn't call trackId if session is not stored", async () => { const searchRequest = { params: {} }; - const options = { sessionId, isStored: false, isRestore: false }; + const options = { sessionId }; + mockSessionClient.trackId = jest.fn(); + + mockStrategy.search.mockReturnValue( + of({ + id: 'my_id', + rawResponse: {} as any, + }) + ); + + await mockScopedClient.search(searchRequest, options).toPromise(); + + expect(mockSessionClient.trackId).toBeCalledTimes(0); + }); + + it('calls `trackId` once, if the response contains an `id`, session is stored and not restoring', async () => { + const searchRequest = { params: {} }; + const options = { sessionId, isStored: true, isRestore: false }; mockSessionClient.trackId = jest.fn().mockResolvedValue(undefined); mockStrategy.search.mockReturnValue( @@ -228,10 +248,20 @@ describe('Search service', () => { await mockScopedClient.search(searchRequest, options).toPromise(); - expect(mockSessionClient.trackId).toBeCalledTimes(2); + expect(mockSessionClient.trackId).toBeCalledTimes(1); expect(mockSessionClient.trackId.mock.calls[0]).toEqual([searchRequest, 'my_id', options]); - expect(mockSessionClient.trackId.mock.calls[1]).toEqual([searchRequest, 'my_id', options]); + }); + + it('does not call `trackId` if search is already tracked', async () => { + const searchRequest = { params: {} }; + const options = { sessionId, isStored: true, isRestore: false, isSearchStored: true }; + mockSessionClient.getId = jest.fn().mockResolvedValueOnce('my_id'); + mockSessionClient.trackId = jest.fn().mockResolvedValue(undefined); + + await mockScopedClient.search(searchRequest, options).toPromise(); + + expect(mockSessionClient.trackId).not.toBeCalled(); }); it('does not call `trackId` if restoring', async () => { diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index b5d140c36a0f5..7523da61752b4 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { firstValueFrom, from, Observable, throwError } from 'rxjs'; +import { concatMap, firstValueFrom, from, Observable, of, throwError } from 'rxjs'; import { pick } from 'lodash'; import moment from 'moment'; import { @@ -19,7 +19,7 @@ import { SharedGlobalConfig, StartServicesAccessor, } from '@kbn/core/server'; -import { map, switchMap, tap, withLatestFrom } from 'rxjs/operators'; +import { catchError, map, switchMap, tap } from 'rxjs/operators'; import { BfetchServerSetup } from '@kbn/bfetch-plugin/server'; import { ExpressionsServerSetup } from '@kbn/expressions-plugin/server'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; @@ -156,13 +156,7 @@ export class SearchService implements Plugin { registerSearchRoute(router); registerSessionRoutes(router, this.logger); - if (taskManager) { - this.sessionService.setup(core, { taskManager, security }); - } else { - // this should never happen in real world, but - // taskManager and security are optional deps because they are in x-pack - this.logger.debug('Skipping sessionService setup because taskManager is not available'); - } + this.sessionService.setup(core, { security }); core.http.registerRouteHandlerContext( 'search', @@ -273,9 +267,7 @@ export class SearchService implements Plugin { ): ISearchStart { const { elasticsearch, savedObjects, uiSettings } = core; - if (taskManager) { - this.sessionService.start(core, { taskManager }); - } + this.sessionService.start(core, {}); const aggs = this.aggsService.start({ fieldFormats, @@ -384,22 +376,55 @@ export class SearchService implements Plugin { }; const searchRequest$ = from(getSearchRequest()); + let isInternalSearchStored = false; // used to prevent tracking current search more than once const search$ = searchRequest$.pipe( - switchMap((searchRequest) => strategy.search(searchRequest, options, deps)), - withLatestFrom(searchRequest$), - tap(([response, requestWithId]) => { - if (!options.sessionId || !response.id || (options.isRestore && requestWithId.id)) return; - // intentionally swallow tracking error, as it shouldn't fail the search - deps.searchSessionsClient.trackId(request, response.id, options).catch((trackErr) => { - this.logger.error(trackErr); - }); - }), - map(([response, requestWithId]) => { - return { - ...response, - isRestored: !!requestWithId.id, - }; - }) + switchMap((searchRequest) => + strategy.search(searchRequest, options, deps).pipe( + concatMap((response) => { + response = { + ...response, + isRestored: !!searchRequest.id, + }; + + if ( + options.sessionId && // if within search session + options.isStored && // and search session was saved (saved object exists) + response.id && // and async search has started + !(options.isRestore && searchRequest.id) // and not restoring already tracked search + ) { + // then track this search inside the search-session saved object + + // check if search was already tracked and extended, don't track again in this case + if (options.isSearchStored || isInternalSearchStored) { + return of({ + ...response, + isStored: true, + }); + } else { + return from( + deps.searchSessionsClient.trackId(request, response.id, options) + ).pipe( + tap(() => { + isInternalSearchStored = true; + }), + map(() => ({ + ...response, + isStored: true, + })), + catchError((e) => { + this.logger.error( + `Error while trying to track search id: ${e?.message}. This might lead to untracked long-running search.` + ); + return of(response); + }) + ); + } + } else { + return of(response); + } + }) + ) + ) ); return search$; @@ -521,6 +546,7 @@ export class SearchService implements Plugin { extendSession: this.extendSession.bind(this, deps), cancelSession: this.cancelSession.bind(this, deps), deleteSession: this.deleteSession.bind(this, deps), + getSessionStatus: searchSessionsClient.status, }; }; }; diff --git a/src/plugins/data/server/search/session/check_non_persisted_sessions.test.ts b/src/plugins/data/server/search/session/check_non_persisted_sessions.test.ts deleted file mode 100644 index edbef1938a82f..0000000000000 --- a/src/plugins/data/server/search/session/check_non_persisted_sessions.test.ts +++ /dev/null @@ -1,595 +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 { checkNonPersistedSessions as checkNonPersistedSessions$ } from './check_non_persisted_sessions'; -import { - SearchSessionStatus, - SearchSessionSavedObjectAttributes, - ENHANCED_ES_SEARCH_STRATEGY, - EQL_SEARCH_STRATEGY, -} from '../../../common'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { CheckSearchSessionsDeps, SearchStatus } from './types'; -import moment from 'moment'; -import { - SavedObjectsBulkUpdateObject, - SavedObjectsDeleteOptions, - SavedObjectsClientContract, -} from '@kbn/core/server'; -import { SearchSessionsConfigSchema } from '../../../config'; - -jest.useFakeTimers(); - -const checkNonPersistedSessions = ( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema -) => checkNonPersistedSessions$(deps, config).toPromise(); - -describe('checkNonPersistedSessions', () => { - let mockClient: any; - let savedObjectsClient: jest.Mocked; - const config: SearchSessionsConfigSchema = { - enabled: true, - pageSize: 5, - notTouchedInProgressTimeout: moment.duration(1, 'm'), - notTouchedTimeout: moment.duration(5, 'm'), - maxUpdateRetries: 3, - defaultExpiration: moment.duration(7, 'd'), - trackingInterval: moment.duration(10, 's'), - expireInterval: moment.duration(10, 'm'), - monitoringTaskTimeout: moment.duration(5, 'm'), - cleanupInterval: moment.duration(10, 's'), - management: {} as any, - }; - const mockLogger: any = { - debug: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - beforeEach(() => { - savedObjectsClient = savedObjectsClientMock.create(); - mockClient = { - asyncSearch: { - status: jest.fn(), - delete: jest.fn(), - }, - eql: { - status: jest.fn(), - delete: jest.fn(), - }, - }; - }); - - test('does nothing if there are no open sessions', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [], - total: 0, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - describe('delete', () => { - test('doesnt delete a non persisted, recently touched session', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - expires: moment().add(moment.duration(3, 'm')), - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(10, 's')), - idMapping: {}, - }, - }, - ], - total: 1, - } as any); - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - test('doesnt delete a non persisted, completed session, within on screen time frame', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.COMPLETE, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(1, 'm')), - expires: moment().add(moment.duration(3, 'm')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.COMPLETE, - }, - }, - }, - }, - ], - total: 1, - } as any); - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - test('deletes in space', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - namespaces: ['awesome'], - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - expires: moment().add(moment.duration(3, 'm')), - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(2, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - }, - }, - }, - }, - ], - total: 1, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.delete).toBeCalled(); - - const [, id, opts] = savedObjectsClient.delete.mock.calls[0]; - expect(id).toBe('123'); - expect((opts as SavedObjectsDeleteOptions).namespace).toBe('awesome'); - }); - - test('deletes a non persisted, abandoned session', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(2, 'm')), - expires: moment().add(moment.duration(3, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - }, - }, - }, - }, - ], - total: 1, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).toBeCalled(); - - expect(mockClient.asyncSearch.delete).toBeCalled(); - - const { id } = mockClient.asyncSearch.delete.mock.calls[0][0]; - expect(id).toBe('async-id'); - }); - - test('deletes a completed, not persisted session', async () => { - mockClient.asyncSearch.delete = jest.fn().mockResolvedValue(true); - - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.COMPLETE, - expires: moment().add(moment.duration(3, 'm')), - created: moment().subtract(moment.duration(30, 'm')), - touched: moment().subtract(moment.duration(6, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - status: SearchStatus.COMPLETE, - }, - 'eql-map-key': { - strategy: EQL_SEARCH_STRATEGY, - id: 'eql-async-id', - status: SearchStatus.COMPLETE, - }, - }, - }, - }, - ], - total: 1, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).toBeCalled(); - - expect(mockClient.asyncSearch.delete).toBeCalled(); - expect(mockClient.eql.delete).not.toBeCalled(); - - const { id } = mockClient.asyncSearch.delete.mock.calls[0][0]; - expect(id).toBe('async-id'); - }); - - test('ignores errors thrown while deleting async searches', async () => { - mockClient.asyncSearch.delete = jest.fn().mockRejectedValueOnce(false); - - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.COMPLETE, - expires: moment().add(moment.duration(3, 'm')), - created: moment().subtract(moment.duration(30, 'm')), - touched: moment().subtract(moment.duration(6, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - status: SearchStatus.COMPLETE, - }, - }, - }, - }, - ], - total: 1, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).toBeCalled(); - - expect(mockClient.asyncSearch.delete).toBeCalled(); - - const { id } = mockClient.asyncSearch.delete.mock.calls[0][0]; - expect(id).toBe('async-id'); - }); - - test("doesn't attempt to delete errored out async search", async () => { - mockClient.asyncSearch.delete = jest.fn(); - - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [ - { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.ERROR, - expires: moment().add(moment.duration(3, 'm')), - created: moment().subtract(moment.duration(30, 'm')), - touched: moment().subtract(moment.duration(6, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - status: SearchStatus.ERROR, - }, - }, - }, - }, - ], - total: 1, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).toBeCalled(); - expect(mockClient.asyncSearch.delete).not.toBeCalled(); - }); - }); - - describe('update', () => { - test('does nothing if the search is still running', async () => { - const so = { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(10, 's')), - expires: moment().add(moment.duration(3, 'm')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - }; - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [so], - total: 1, - } as any); - - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: true, - is_running: true, - }, - }); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - test("doesn't re-check completed or errored searches", async () => { - savedObjectsClient.bulkUpdate = jest.fn(); - savedObjectsClient.delete = jest.fn(); - const so = { - id: '123', - attributes: { - status: SearchSessionStatus.ERROR, - expires: moment().add(moment.duration(3, 'm')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.COMPLETE, - }, - 'another-search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.ERROR, - }, - }, - }, - }; - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [so], - total: 1, - } as any); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(mockClient.asyncSearch.status).not.toBeCalled(); - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - test('updates in space', async () => { - savedObjectsClient.bulkUpdate = jest.fn(); - const so = { - namespaces: ['awesome'], - attributes: { - status: SearchSessionStatus.IN_PROGRESS, - expires: moment().add(moment.duration(3, 'm')), - touched: '123', - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - }; - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [so], - total: 1, - } as any); - - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: false, - is_running: false, - completion_status: 200, - }, - }); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(mockClient.asyncSearch.status).toBeCalledWith({ id: 'search-id' }, { meta: true }); - const [updateInput] = savedObjectsClient.bulkUpdate.mock.calls[0]; - const updatedAttributes = updateInput[0] as SavedObjectsBulkUpdateObject; - expect(updatedAttributes.namespace).toBe('awesome'); - }); - - test('updates to complete if the search is done', async () => { - savedObjectsClient.bulkUpdate = jest.fn(); - const so = { - attributes: { - status: SearchSessionStatus.IN_PROGRESS, - expires: moment().add(moment.duration(3, 'm')), - touched: '123', - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - }; - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [so], - total: 1, - } as any); - - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: false, - is_running: false, - completion_status: 200, - }, - }); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - expect(mockClient.asyncSearch.status).toBeCalledWith({ id: 'search-id' }, { meta: true }); - const [updateInput] = savedObjectsClient.bulkUpdate.mock.calls[0]; - const updatedAttributes = updateInput[0].attributes as SearchSessionSavedObjectAttributes; - expect(updatedAttributes.status).toBe(SearchSessionStatus.COMPLETE); - expect(updatedAttributes.touched).not.toBe('123'); - expect(updatedAttributes.completed).not.toBeUndefined(); - expect(updatedAttributes.idMapping['search-hash'].status).toBe(SearchStatus.COMPLETE); - expect(updatedAttributes.idMapping['search-hash'].error).toBeUndefined(); - - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - test('updates to error if the search is errored', async () => { - savedObjectsClient.bulkUpdate = jest.fn(); - const so = { - attributes: { - expires: moment().add(moment.duration(3, 'm')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - }; - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [so], - total: 1, - } as any); - - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: false, - is_running: false, - completion_status: 500, - }, - }); - - await checkNonPersistedSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - const [updateInput] = savedObjectsClient.bulkUpdate.mock.calls[0]; - const updatedAttributes = updateInput[0].attributes as SearchSessionSavedObjectAttributes; - expect(updatedAttributes.status).toBe(SearchSessionStatus.ERROR); - expect(updatedAttributes.idMapping['search-hash'].status).toBe(SearchStatus.ERROR); - expect(updatedAttributes.idMapping['search-hash'].error).toBe( - 'Search completed with a 500 status' - ); - }); - }); -}); diff --git a/src/plugins/data/server/search/session/check_non_persisted_sessions.ts b/src/plugins/data/server/search/session/check_non_persisted_sessions.ts deleted file mode 100644 index f6314611afdbc..0000000000000 --- a/src/plugins/data/server/search/session/check_non_persisted_sessions.ts +++ /dev/null @@ -1,136 +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 { SavedObjectsFindResult } from '@kbn/core/server'; -import moment from 'moment'; -import { EMPTY } from 'rxjs'; -import { catchError, concatMap } from 'rxjs/operators'; -import { nodeBuilder, KueryNode } from '@kbn/es-query'; -import { - ENHANCED_ES_SEARCH_STRATEGY, - SEARCH_SESSION_TYPE, - SearchSessionSavedObjectAttributes, - SearchSessionStatus, -} from '../../../common'; -import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; -import { CheckSearchSessionsDeps, SearchStatus } from './types'; -import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status'; -import { SearchSessionsConfigSchema } from '../../../config'; - -export const SEARCH_SESSIONS_CLEANUP_TASK_TYPE = 'search_sessions_cleanup'; -export const SEARCH_SESSIONS_CLEANUP_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_CLEANUP_TASK_TYPE}`; - -function isSessionStale( - session: SavedObjectsFindResult, - config: SearchSessionsConfigSchema -) { - const curTime = moment(); - // Delete cancelled sessions immediately - if (session.attributes.status === SearchSessionStatus.CANCELLED) return true; - // Delete if a running session wasn't polled for in the last notTouchedInProgressTimeout OR - // if a completed \ errored \ canceled session wasn't saved for within notTouchedTimeout - return ( - (session.attributes.status === SearchSessionStatus.IN_PROGRESS && - curTime.diff(moment(session.attributes.touched), 'ms') > - config.notTouchedInProgressTimeout.asMilliseconds()) || - (session.attributes.status !== SearchSessionStatus.IN_PROGRESS && - curTime.diff(moment(session.attributes.touched), 'ms') > - config.notTouchedTimeout.asMilliseconds()) - ); -} - -function checkNonPersistedSessionsPage( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - filter: KueryNode, - page: number -) { - const { logger, client, savedObjectsClient } = deps; - logger.debug(`${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Fetching sessions from page ${page}`); - return getSearchSessionsPage$(deps, filter, config.pageSize, page).pipe( - concatMap(async (nonPersistedSearchSessions) => { - if (!nonPersistedSearchSessions.total) return nonPersistedSearchSessions; - - logger.debug( - `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Found ${nonPersistedSearchSessions.total} sessions, processing ${nonPersistedSearchSessions.saved_objects.length}` - ); - - const updatedSessions = await getAllSessionsStatusUpdates( - deps, - config, - nonPersistedSearchSessions - ); - const deletedSessionIds: string[] = []; - - await Promise.all( - nonPersistedSearchSessions.saved_objects.map(async (session) => { - if (isSessionStale(session, config)) { - // delete saved object to free up memory - // TODO: there's a potential rare edge case of deleting an object and then receiving a new trackId for that same session! - // Maybe we want to change state to deleted and cleanup later? - logger.debug(`Deleting stale session | ${session.id}`); - try { - deletedSessionIds.push(session.id); - await savedObjectsClient.delete(SEARCH_SESSION_TYPE, session.id, { - namespace: session.namespaces?.[0], - }); - } catch (e) { - logger.error( - `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Error while deleting session ${session.id}: ${e.message}` - ); - } - - // Send a delete request for each async search to ES - Object.keys(session.attributes.idMapping).map(async (searchKey: string) => { - const searchInfo = session.attributes.idMapping[searchKey]; - if (searchInfo.status === SearchStatus.ERROR) return; // skip attempting to delete async search in case we know it has errored out - - if (searchInfo.strategy === ENHANCED_ES_SEARCH_STRATEGY) { - try { - await client.asyncSearch.delete({ id: searchInfo.id }); - } catch (e) { - if (e.message !== 'resource_not_found_exception') { - logger.error( - `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Error while deleting async_search ${searchInfo.id}: ${e.message}` - ); - } - } - } - }); - } - }) - ); - - const nonDeletedSessions = updatedSessions.filter((updateSession) => { - return deletedSessionIds.indexOf(updateSession.id) === -1; - }); - - await bulkUpdateSessions(deps, nonDeletedSessions); - - return nonPersistedSearchSessions; - }) - ); -} - -export function checkNonPersistedSessions( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema -) { - const { logger } = deps; - - const filters = nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'false'); - - return checkSearchSessionsByPage(checkNonPersistedSessionsPage, deps, config, filters).pipe( - catchError((e) => { - logger.error( - `${SEARCH_SESSIONS_CLEANUP_TASK_TYPE} Error while processing sessions: ${e?.message}` - ); - return EMPTY; - }) - ); -} diff --git a/src/plugins/data/server/search/session/check_persisted_sessions.test.ts b/src/plugins/data/server/search/session/check_persisted_sessions.test.ts deleted file mode 100644 index 1e6de567a0d76..0000000000000 --- a/src/plugins/data/server/search/session/check_persisted_sessions.test.ts +++ /dev/null @@ -1,77 +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 { checkPersistedSessionsProgress } from './check_persisted_sessions'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import moment from 'moment'; -import { SavedObjectsClientContract } from '@kbn/core/server'; -import { SearchSessionsConfigSchema } from '../../../config'; - -describe('checkPersistedSessionsProgress', () => { - let mockClient: any; - let savedObjectsClient: jest.Mocked; - const config: SearchSessionsConfigSchema = { - enabled: true, - pageSize: 5, - notTouchedInProgressTimeout: moment.duration(1, 'm'), - notTouchedTimeout: moment.duration(5, 'm'), - maxUpdateRetries: 3, - defaultExpiration: moment.duration(7, 'd'), - trackingInterval: moment.duration(10, 's'), - cleanupInterval: moment.duration(10, 's'), - expireInterval: moment.duration(10, 'm'), - monitoringTaskTimeout: moment.duration(5, 'm'), - management: {} as any, - }; - const mockLogger: any = { - debug: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - beforeEach(() => { - savedObjectsClient = savedObjectsClientMock.create(); - mockClient = { - asyncSearch: { - status: jest.fn(), - delete: jest.fn(), - }, - eql: { - status: jest.fn(), - delete: jest.fn(), - }, - }; - }); - - test('fetches only running persisted sessions', async () => { - savedObjectsClient.find.mockResolvedValue({ - saved_objects: [], - total: 0, - } as any); - - await checkPersistedSessionsProgress( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config - ); - - const [findInput] = savedObjectsClient.find.mock.calls[0]; - - expect(findInput.filter.arguments[0].arguments[0].value).toBe( - 'search-session.attributes.persisted' - ); - expect(findInput.filter.arguments[0].arguments[1].value).toBe('true'); - expect(findInput.filter.arguments[1].arguments[0].value).toBe( - 'search-session.attributes.status' - ); - expect(findInput.filter.arguments[1].arguments[1].value).toBe('in_progress'); - }); -}); diff --git a/src/plugins/data/server/search/session/check_persisted_sessions.ts b/src/plugins/data/server/search/session/check_persisted_sessions.ts deleted file mode 100644 index ace921a56a052..0000000000000 --- a/src/plugins/data/server/search/session/check_persisted_sessions.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { EMPTY, Observable } from 'rxjs'; -import { catchError, concatMap } from 'rxjs/operators'; -import { nodeBuilder, KueryNode } from '@kbn/es-query'; -import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common'; -import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; -import { CheckSearchSessionsDeps, SearchSessionsResponse } from './types'; -import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status'; -import { SearchSessionsConfigSchema } from '../../../config'; - -export const SEARCH_SESSIONS_TASK_TYPE = 'search_sessions_monitor'; -export const SEARCH_SESSIONS_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_TASK_TYPE}`; - -function checkPersistedSessionsPage( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - filter: KueryNode, - page: number -): Observable { - const { logger } = deps; - logger.debug(`${SEARCH_SESSIONS_TASK_TYPE} Fetching sessions from page ${page}`); - return getSearchSessionsPage$(deps, filter, config.pageSize, page).pipe( - concatMap(async (persistedSearchSessions) => { - if (!persistedSearchSessions.total) return persistedSearchSessions; - - logger.debug( - `${SEARCH_SESSIONS_TASK_TYPE} Found ${persistedSearchSessions.total} sessions, processing ${persistedSearchSessions.saved_objects.length}` - ); - - const updatedSessions = await getAllSessionsStatusUpdates( - deps, - config, - persistedSearchSessions - ); - await bulkUpdateSessions(deps, updatedSessions); - - return persistedSearchSessions; - }) - ); -} - -export function checkPersistedSessionsProgress( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema -) { - const { logger } = deps; - - const persistedSessionsFilter = nodeBuilder.and([ - nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'true'), - nodeBuilder.is( - `${SEARCH_SESSION_TYPE}.attributes.status`, - SearchSessionStatus.IN_PROGRESS.toString() - ), - ]); - - return checkSearchSessionsByPage( - checkPersistedSessionsPage, - deps, - config, - persistedSessionsFilter - ).pipe( - catchError((e) => { - logger.error(`${SEARCH_SESSIONS_TASK_TYPE} Error while processing sessions: ${e?.message}`); - return EMPTY; - }) - ); -} diff --git a/src/plugins/data/server/search/session/expire_persisted_sessions.ts b/src/plugins/data/server/search/session/expire_persisted_sessions.ts deleted file mode 100644 index 1c7ad8ff3e346..0000000000000 --- a/src/plugins/data/server/search/session/expire_persisted_sessions.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 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 { EMPTY, Observable } from 'rxjs'; -import { catchError, concatMap } from 'rxjs/operators'; -import { nodeBuilder, KueryNode } from '@kbn/es-query'; -import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common'; -import { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; -import { CheckSearchSessionsDeps, SearchSessionsResponse } from './types'; -import { bulkUpdateSessions, getAllSessionsStatusUpdates } from './update_session_status'; -import { SearchSessionsConfigSchema } from '../../../config'; - -export const SEARCH_SESSIONS_EXPIRE_TASK_TYPE = 'search_sessions_expire'; -export const SEARCH_SESSIONS_EXPIRE_TASK_ID = `data_enhanced_${SEARCH_SESSIONS_EXPIRE_TASK_TYPE}`; - -function checkSessionExpirationPage( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - filter: KueryNode, - page: number -): Observable { - const { logger } = deps; - logger.debug(`${SEARCH_SESSIONS_EXPIRE_TASK_TYPE} Fetching sessions from page ${page}`); - return getSearchSessionsPage$(deps, filter, config.pageSize, page).pipe( - concatMap(async (searchSessions) => { - if (!searchSessions.total) return searchSessions; - - logger.debug( - `${SEARCH_SESSIONS_EXPIRE_TASK_TYPE} Found ${searchSessions.total} sessions, processing ${searchSessions.saved_objects.length}` - ); - - const updatedSessions = await getAllSessionsStatusUpdates(deps, config, searchSessions); - await bulkUpdateSessions(deps, updatedSessions); - - return searchSessions; - }) - ); -} - -export function checkPersistedCompletedSessionExpiration( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema -) { - const { logger } = deps; - - const persistedSessionsFilter = nodeBuilder.and([ - nodeBuilder.is(`${SEARCH_SESSION_TYPE}.attributes.persisted`, 'true'), - nodeBuilder.is( - `${SEARCH_SESSION_TYPE}.attributes.status`, - SearchSessionStatus.COMPLETE.toString() - ), - ]); - - return checkSearchSessionsByPage( - checkSessionExpirationPage, - deps, - config, - persistedSessionsFilter - ).pipe( - catchError((e) => { - logger.error( - `${SEARCH_SESSIONS_EXPIRE_TASK_TYPE} Error while processing sessions: ${e?.message}` - ); - return EMPTY; - }) - ); -} diff --git a/src/plugins/data/server/search/session/get_search_session_page.test.ts b/src/plugins/data/server/search/session/get_search_session_page.test.ts deleted file mode 100644 index 43a8f987dc8fc..0000000000000 --- a/src/plugins/data/server/search/session/get_search_session_page.test.ts +++ /dev/null @@ -1,282 +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 { checkSearchSessionsByPage, getSearchSessionsPage$ } from './get_search_session_page'; -import { ENHANCED_ES_SEARCH_STRATEGY, SearchSessionStatus } from '../../../common'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { SearchStatus } from './types'; -import moment from 'moment'; -import { SavedObjectsClientContract } from '@kbn/core/server'; -import { of, Subject, throwError } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { SearchSessionsConfigSchema } from '../../../config'; - -jest.useFakeTimers(); - -describe('checkSearchSessionsByPage', () => { - const mockClient = {} as any; - let savedObjectsClient: jest.Mocked; - const config: SearchSessionsConfigSchema = { - enabled: true, - pageSize: 5, - management: {} as any, - } as any; - const mockLogger: any = { - debug: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - const emptySO = { - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(10, 's')), - idMapping: {}, - }, - }; - - beforeEach(() => { - savedObjectsClient = savedObjectsClientMock.create(); - }); - - describe('getSearchSessionsPage$', () => { - test('sorting is by "touched"', async () => { - savedObjectsClient.find.mockResolvedValueOnce({ - saved_objects: [], - total: 0, - } as any); - - await getSearchSessionsPage$( - { - savedObjectsClient, - } as any, - { - type: 'literal', - }, - 1, - 1 - ); - - expect(savedObjectsClient.find).toHaveBeenCalledWith( - expect.objectContaining({ sortField: 'touched', sortOrder: 'asc' }) - ); - }); - }); - - describe('pagination', () => { - test('fetches one page if got empty response', async () => { - const checkFn = jest.fn().mockReturnValue(of(undefined)); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ).toPromise(); - - expect(checkFn).toHaveBeenCalledTimes(1); - }); - - test('fetches one page if got response with no saved objects', async () => { - const checkFn = jest.fn().mockReturnValue( - of({ - total: 0, - }) - ); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ).toPromise(); - - expect(checkFn).toHaveBeenCalledTimes(1); - }); - - test('fetches one page if less than page size object are returned', async () => { - const checkFn = jest.fn().mockReturnValue( - of({ - saved_objects: [emptySO, emptySO], - total: 5, - }) - ); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ).toPromise(); - - expect(checkFn).toHaveBeenCalledTimes(1); - }); - - test('fetches two pages if exactly page size objects are returned', async () => { - let i = 0; - - const checkFn = jest.fn().mockImplementation(() => - of({ - saved_objects: i++ === 0 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [], - total: 5, - page: i, - }) - ); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ).toPromise(); - - expect(checkFn).toHaveBeenCalledTimes(2); - - // validate that page number increases - const page1 = checkFn.mock.calls[0][3]; - const page2 = checkFn.mock.calls[1][3]; - expect(page1).toBe(1); - expect(page2).toBe(2); - }); - - test('fetches two pages if page size +1 objects are returned', async () => { - let i = 0; - - const checkFn = jest.fn().mockImplementation(() => - of({ - saved_objects: i++ === 0 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [emptySO], - total: i === 0 ? 5 : 1, - page: i, - }) - ); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ).toPromise(); - - expect(checkFn).toHaveBeenCalledTimes(2); - }); - - test('sessions fetched in the beginning are processed even if sessions in the end fail', async () => { - let i = 0; - - const checkFn = jest.fn().mockImplementation(() => { - if (++i === 2) { - return throwError('Fake find error...'); - } - return of({ - saved_objects: - i <= 5 - ? [ - i === 1 - ? { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(2, 'm')), - idMapping: { - 'map-key': { - strategy: ENHANCED_ES_SEARCH_STRATEGY, - id: 'async-id', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } - : emptySO, - emptySO, - emptySO, - emptySO, - emptySO, - ] - : [], - total: 25, - page: i, - }); - }); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ) - .toPromise() - .catch(() => {}); - - expect(checkFn).toHaveBeenCalledTimes(2); - }); - - test('fetching is abortable', async () => { - let i = 0; - const abort$ = new Subject(); - - const checkFn = jest.fn().mockImplementation(() => { - if (++i === 2) { - abort$.next(); - } - - return of({ - saved_objects: i <= 5 ? [emptySO, emptySO, emptySO, emptySO, emptySO] : [], - total: 25, - page: i, - }); - }); - - await checkSearchSessionsByPage( - checkFn, - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - config, - [] - ) - .pipe(takeUntil(abort$)) - .toPromise() - .catch(() => {}); - - jest.runAllTimers(); - - // if not for `abort$` then this would be called 6 times! - expect(checkFn).toHaveBeenCalledTimes(2); - }); - }); -}); diff --git a/src/plugins/data/server/search/session/get_search_session_page.ts b/src/plugins/data/server/search/session/get_search_session_page.ts deleted file mode 100644 index d98d513c9e73f..0000000000000 --- a/src/plugins/data/server/search/session/get_search_session_page.ts +++ /dev/null @@ -1,60 +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 { SavedObjectsClientContract, Logger } from '@kbn/core/server'; -import { from, Observable, EMPTY } from 'rxjs'; -import { concatMap } from 'rxjs/operators'; -import type { KueryNode } from '@kbn/es-query'; -import { SearchSessionSavedObjectAttributes, SEARCH_SESSION_TYPE } from '../../../common'; -import { CheckSearchSessionsDeps, CheckSearchSessionsFn } from './types'; -import { SearchSessionsConfigSchema } from '../../../config'; - -export interface GetSessionsDeps { - savedObjectsClient: SavedObjectsClientContract; - logger: Logger; -} - -export function getSearchSessionsPage$( - { savedObjectsClient }: GetSessionsDeps, - filter: KueryNode, - pageSize: number, - page: number -) { - return from( - savedObjectsClient.find({ - page, - perPage: pageSize, - type: SEARCH_SESSION_TYPE, - namespaces: ['*'], - // process older sessions first - sortField: 'touched', - sortOrder: 'asc', - filter, - }) - ); -} - -export const checkSearchSessionsByPage = ( - checkFn: CheckSearchSessionsFn, - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - filters: any, - nextPage = 1 -): Observable => - checkFn(deps, config, filters, nextPage).pipe( - concatMap((result) => { - if (!result || !result.saved_objects || result.saved_objects.length < config.pageSize) { - return EMPTY; - } else { - // TODO: while processing previous page session list might have been changed and we might skip a session, - // because it would appear now on a different "page". - // This isn't critical, as we would pick it up on a next task iteration, but maybe we could improve this somehow - return checkSearchSessionsByPage(checkFn, deps, config, filters, result.page + 1); - } - }) - ); diff --git a/src/plugins/data/server/search/session/get_search_status.ts b/src/plugins/data/server/search/session/get_search_status.ts index 3ded923376b18..fb34fff1c1d43 100644 --- a/src/plugins/data/server/search/session/get_search_status.ts +++ b/src/plugins/data/server/search/session/get_search_status.ts @@ -9,24 +9,25 @@ import { i18n } from '@kbn/i18n'; import type { TransportResult } from '@elastic/elasticsearch'; import { ElasticsearchClient } from '@kbn/core/server'; -import { SearchSessionRequestInfo } from '../../../common'; -import { AsyncSearchStatusResponse } from '../..'; +import { SearchSessionRequestStatus } from '../../../common'; import { SearchStatus } from './types'; +import { AsyncSearchStatusResponse } from '../..'; export async function getSearchStatus( - client: ElasticsearchClient, + internalClient: ElasticsearchClient, asyncId: string -): Promise> { +): Promise { // TODO: Handle strategies other than the default one // https://github.com/elastic/kibana/issues/127880 try { // @ts-expect-error start_time_in_millis: EpochMillis is string | number - const apiResponse: TransportResult = await client.asyncSearch.status( - { - id: asyncId, - }, - { meta: true } - ); + const apiResponse: TransportResult = + await internalClient.asyncSearch.status( + { + id: asyncId, + }, + { meta: true } + ); const response = apiResponse.body; if ((response.is_partial && !response.is_running) || response.completion_status >= 400) { return { diff --git a/src/plugins/data/server/search/session/get_session_status.test.ts b/src/plugins/data/server/search/session/get_session_status.test.ts index db75e322edda5..b7e323a15f065 100644 --- a/src/plugins/data/server/search/session/get_session_status.test.ts +++ b/src/plugins/data/server/search/session/get_session_status.test.ts @@ -6,72 +6,141 @@ * Side Public License, v 1. */ -import { SearchStatus } from './types'; +import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { getSessionStatus } from './get_session_status'; -import { SearchSessionStatus } from '../../../common'; +import { SearchSessionSavedObjectAttributes, SearchSessionStatus } from '../../../common'; import moment from 'moment'; import { SearchSessionsConfigSchema } from '../../../config'; +const mockInProgressSearchResponse = { + body: { + is_partial: true, + is_running: true, + }, +}; + +const mockErrorSearchResponse = { + body: { + is_partial: false, + is_running: false, + completion_status: 500, + }, +}; + +const mockCompletedSearchResponse = { + body: { + is_partial: false, + is_running: false, + completion_status: 200, + }, +}; + describe('getSessionStatus', () => { - const mockConfig = { - notTouchedInProgressTimeout: moment.duration(1, 'm'), - } as unknown as SearchSessionsConfigSchema; - test("returns an in_progress status if there's nothing inside the session", () => { + beforeEach(() => { + deps.internalClient.asyncSearch.status.mockReset(); + }); + + const mockConfig = {} as unknown as SearchSessionsConfigSchema; + const deps = { internalClient: elasticsearchServiceMock.createElasticsearchClient() }; + test("returns an in_progress status if there's nothing inside the session", async () => { const session: any = { idMapping: {}, touched: moment(), }; - expect(getSessionStatus(session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); + expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); }); - test("returns an error status if there's at least one error", () => { + test("returns an error status if there's at least one error", async () => { + deps.internalClient.asyncSearch.status.mockImplementation(async ({ id }): Promise => { + switch (id) { + case 'a': + return mockInProgressSearchResponse; + case 'b': + return mockErrorSearchResponse; + case 'c': + return mockCompletedSearchResponse; + default: + // eslint-disable-next-line no-console + console.error('Not mocked search id'); + throw new Error('Not mocked search id'); + } + }); const session: any = { idMapping: { - a: { status: SearchStatus.IN_PROGRESS }, - b: { status: SearchStatus.ERROR, error: 'Nope' }, - c: { status: SearchStatus.COMPLETE }, + a: { + id: 'a', + }, + b: { id: 'b' }, + c: { id: 'c' }, }, }; - expect(getSessionStatus(session, mockConfig)).toBe(SearchSessionStatus.ERROR); + expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.ERROR); }); - test('expires a empty session after a minute', () => { + test('expires a session if expired < now', async () => { const session: any = { idMapping: {}, - touched: moment().subtract(2, 'm'), + expires: moment().subtract(2, 'm'), }; - expect(getSessionStatus(session, mockConfig)).toBe(SearchSessionStatus.EXPIRED); + + expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.EXPIRED); }); - test('doesnt expire a full session after a minute', () => { + test('doesnt expire if expire > now', async () => { + deps.internalClient.asyncSearch.status.mockResolvedValue(mockInProgressSearchResponse as any); + const session: any = { idMapping: { - a: { status: SearchStatus.IN_PROGRESS }, + a: { id: 'a' }, }, - touched: moment().subtract(2, 'm'), + expires: moment().add(2, 'm'), }; - expect(getSessionStatus(session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); + expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); }); - test('returns a complete status if all are complete', () => { + test('returns cancelled status if session was cancelled', async () => { + const session: Partial = { + idMapping: { + a: { id: 'a', strategy: 'ese' }, + }, + isCanceled: true, + expires: moment().subtract(2, 'm').toISOString(), + }; + expect( + await getSessionStatus(deps, session as SearchSessionSavedObjectAttributes, mockConfig) + ).toBe(SearchSessionStatus.CANCELLED); + }); + + test('returns a complete status if all are complete', async () => { + deps.internalClient.asyncSearch.status.mockResolvedValue(mockCompletedSearchResponse as any); + const session: any = { idMapping: { - a: { status: SearchStatus.COMPLETE }, - b: { status: SearchStatus.COMPLETE }, - c: { status: SearchStatus.COMPLETE }, + a: { id: 'a' }, + b: { id: 'b' }, + c: { id: 'c' }, }, }; - expect(getSessionStatus(session, mockConfig)).toBe(SearchSessionStatus.COMPLETE); + expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.COMPLETE); }); - test('returns a running status if some are still running', () => { + test('returns a running status if some are still running', async () => { + deps.internalClient.asyncSearch.status.mockImplementation(async ({ id }): Promise => { + switch (id) { + case 'a': + return mockInProgressSearchResponse; + default: + return mockCompletedSearchResponse; + } + }); + const session: any = { idMapping: { - a: { status: SearchStatus.IN_PROGRESS }, - b: { status: SearchStatus.COMPLETE }, - c: { status: SearchStatus.IN_PROGRESS }, + a: { id: 'a' }, + b: { id: 'b' }, + c: { id: 'c' }, }, }; - expect(getSessionStatus(session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); + expect(await getSessionStatus(deps, session, mockConfig)).toBe(SearchSessionStatus.IN_PROGRESS); }); }); diff --git a/src/plugins/data/server/search/session/get_session_status.ts b/src/plugins/data/server/search/session/get_session_status.ts index 4614ea92318e9..b89b4c487c32c 100644 --- a/src/plugins/data/server/search/session/get_session_status.ts +++ b/src/plugins/data/server/search/session/get_session_status.ts @@ -7,25 +7,40 @@ */ import moment from 'moment'; +import { ElasticsearchClient } from '@kbn/core/server'; import { SearchSessionSavedObjectAttributes, SearchSessionStatus } from '../../../common'; import { SearchStatus } from './types'; import { SearchSessionsConfigSchema } from '../../../config'; +import { getSearchStatus } from './get_search_status'; -export function getSessionStatus( +export async function getSessionStatus( + deps: { internalClient: ElasticsearchClient }, session: SearchSessionSavedObjectAttributes, config: SearchSessionsConfigSchema -): SearchSessionStatus { - const searchStatuses = Object.values(session.idMapping); - const curTime = moment(); +): Promise { + if (session.isCanceled === true) { + return SearchSessionStatus.CANCELLED; + } + + const now = moment(); + + if (moment(session.expires).isBefore(now)) { + return SearchSessionStatus.EXPIRED; + } + + const searches = Object.values(session.idMapping); + const searchStatuses = await Promise.all( + searches.map(async (s) => { + const status = await getSearchStatus(deps.internalClient, s.id); + return { + ...s, + ...status, + }; + }) + ); + if (searchStatuses.some((item) => item.status === SearchStatus.ERROR)) { return SearchSessionStatus.ERROR; - } else if ( - searchStatuses.length === 0 && - curTime.diff(moment(session.touched), 'ms') > - moment.duration(config.notTouchedInProgressTimeout).asMilliseconds() - ) { - // Expire empty sessions that weren't touched for a minute - return SearchSessionStatus.EXPIRED; } else if ( searchStatuses.length > 0 && searchStatuses.every((item) => item.status === SearchStatus.COMPLETE) diff --git a/src/plugins/data/server/search/session/mocks.ts b/src/plugins/data/server/search/session/mocks.ts index 33715810060a9..339ef628356db 100644 --- a/src/plugins/data/server/search/session/mocks.ts +++ b/src/plugins/data/server/search/session/mocks.ts @@ -22,6 +22,7 @@ export function createSearchSessionsClientMock(): jest.Mocked ({ diff --git a/src/plugins/data/server/search/session/session_service.test.ts b/src/plugins/data/server/search/session/session_service.test.ts index 6565eaf11d3be..b44b9a08b8d38 100644 --- a/src/plugins/data/server/search/session/session_service.test.ts +++ b/src/plugins/data/server/search/session/session_service.test.ts @@ -11,17 +11,16 @@ import { SavedObjectsClientContract, SavedObjectsErrorHelpers, } from '@kbn/core/server'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { ElasticsearchClientMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; import { nodeBuilder } from '@kbn/es-query'; import { SearchSessionService } from './session_service'; import { createRequestHash } from './utils'; import moment from 'moment'; import { coreMock } from '@kbn/core/server/mocks'; import { ConfigSchema } from '../../../config'; -import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import type { AuthenticatedUser } from '@kbn/security-plugin/common/model'; import { SEARCH_SESSION_TYPE, SearchSessionStatus } from '../../../common'; -import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; +import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; const MAX_UPDATE_RETRIES = 3; @@ -29,8 +28,8 @@ const flushPromises = () => new Promise((resolve) => setImmediate(resolve)); describe('SearchSessionService', () => { let savedObjectsClient: jest.Mocked; + let elasticsearchClient: ElasticsearchClientMock; let service: SearchSessionService; - let mockTaskManager: jest.Mocked; const MOCK_STRATEGY = 'ese'; @@ -67,19 +66,14 @@ describe('SearchSessionService', () => { describe('Feature disabled', () => { beforeEach(async () => { savedObjectsClient = savedObjectsClientMock.create(); + elasticsearchClient = elasticsearchServiceMock.createElasticsearchClient(); const config: ConfigSchema = { search: { sessions: { enabled: false, - pageSize: 10000, - notTouchedInProgressTimeout: moment.duration(1, 'm'), notTouchedTimeout: moment.duration(2, 'm'), maxUpdateRetries: MAX_UPDATE_RETRIES, defaultExpiration: moment.duration(7, 'd'), - monitoringTaskTimeout: moment.duration(5, 'm'), - cleanupInterval: moment.duration(10, 's'), - trackingInterval: moment.duration(10, 's'), - expireInterval: moment.duration(10, 'm'), management: {} as any, }, }, @@ -90,23 +84,14 @@ describe('SearchSessionService', () => { error: jest.fn(), }; service = new SearchSessionService(mockLogger, config, '8.0.0'); - service.setup(coreMock.createSetup(), { taskManager: taskManagerMock.createSetup() }); - const coreStart = coreMock.createStart(); - mockTaskManager = taskManagerMock.createStart(); + service.setup(coreMock.createSetup(), {}); await flushPromises(); - await service.start(coreStart, { - taskManager: mockTaskManager, - }); }); afterEach(() => { service.stop(); }); - it('task is cleared, if exists', async () => { - expect(mockTaskManager.removeIfExists).toHaveBeenCalled(); - }); - it('trackId ignores', async () => { await service.trackId({ savedObjectsClient }, mockUser1, { params: {} }, '123', { sessionId: '321', @@ -148,19 +133,15 @@ describe('SearchSessionService', () => { describe('Feature enabled', () => { beforeEach(async () => { savedObjectsClient = savedObjectsClientMock.create(); + elasticsearchClient = elasticsearchServiceMock.createElasticsearchClient(); const config: ConfigSchema = { search: { sessions: { enabled: true, pageSize: 10000, - notTouchedInProgressTimeout: moment.duration(1, 'm'), notTouchedTimeout: moment.duration(2, 'm'), maxUpdateRetries: MAX_UPDATE_RETRIES, defaultExpiration: moment.duration(7, 'd'), - trackingInterval: moment.duration(10, 's'), - expireInterval: moment.duration(10, 'm'), - monitoringTaskTimeout: moment.duration(5, 'm'), - cleanupInterval: moment.duration(10, 's'), management: {} as any, }, }, @@ -171,24 +152,17 @@ describe('SearchSessionService', () => { error: jest.fn(), }; service = new SearchSessionService(mockLogger, config, '8.0.0'); - service.setup(coreMock.createSetup(), { taskManager: taskManagerMock.createSetup() }); + service.setup(coreMock.createSetup(), {}); const coreStart = coreMock.createStart(); - mockTaskManager = taskManagerMock.createStart(); + await flushPromises(); - await service.start(coreStart, { - taskManager: mockTaskManager, - }); + await service.start(coreStart, {}); }); afterEach(() => { service.stop(); }); - it('task is cleared and re-created', async () => { - expect(mockTaskManager.removeIfExists).toHaveBeenCalled(); - expect(mockTaskManager.ensureScheduled).toHaveBeenCalled(); - }); - describe('save', () => { it('throws if `name` is not provided', () => { expect(() => @@ -198,7 +172,9 @@ describe('SearchSessionService', () => { it('throws if `appId` is not provided', () => { expect( - service.save({ savedObjectsClient }, mockUser1, sessionId, { name: 'banana' }) + service.save({ savedObjectsClient }, mockUser1, sessionId, { + name: 'banana', + }) ).rejects.toMatchInlineSnapshot(`[Error: AppId is required]`); }); @@ -232,8 +208,6 @@ describe('SearchSessionService', () => { expect(type).toBe(SEARCH_SESSION_TYPE); expect(id).toBe(sessionId); expect(callAttributes).not.toHaveProperty('idMapping'); - expect(callAttributes).toHaveProperty('touched'); - expect(callAttributes).toHaveProperty('persisted', true); expect(callAttributes).toHaveProperty('name', 'banana'); expect(callAttributes).toHaveProperty('appId', 'nanana'); expect(callAttributes).toHaveProperty('locatorId', 'panama'); @@ -265,10 +239,8 @@ describe('SearchSessionService', () => { expect(type).toBe(SEARCH_SESSION_TYPE); expect(options?.id).toBe(sessionId); expect(callAttributes).toHaveProperty('idMapping', {}); - expect(callAttributes).toHaveProperty('touched'); expect(callAttributes).toHaveProperty('expires'); expect(callAttributes).toHaveProperty('created'); - expect(callAttributes).toHaveProperty('persisted', true); expect(callAttributes).toHaveProperty('name', 'banana'); expect(callAttributes).toHaveProperty('appId', 'nanana'); expect(callAttributes).toHaveProperty('locatorId', 'panama'); @@ -343,13 +315,20 @@ describe('SearchSessionService', () => { total: 1, per_page: 1, page: 0, + statuses: { + [mockSavedObject.id]: { status: SearchSessionStatus.IN_PROGRESS }, + }, }; savedObjectsClient.find.mockResolvedValue(mockResponse); const options = { page: 0, perPage: 5 }; - const response = await service.find({ savedObjectsClient }, mockUser1, options); + const response = await service.find( + { savedObjectsClient, internalElasticsearchClient: elasticsearchClient }, + mockUser1, + options + ); - expect(response).toBe(mockResponse); + expect(response).toEqual(mockResponse); const [[findOptions]] = savedObjectsClient.find.mock.calls; expect(findOptions).toMatchInlineSnapshot(` Object { @@ -424,17 +403,28 @@ describe('SearchSessionService', () => { total: 1, per_page: 1, page: 0, + statuses: { + [mockSavedObject.id]: { status: SearchSessionStatus.IN_PROGRESS }, + }, }; savedObjectsClient.find.mockResolvedValue(mockResponse); const options1 = { filter: 'foobar' }; - const response1 = await service.find({ savedObjectsClient }, mockUser1, options1); + const response1 = await service.find( + { savedObjectsClient, internalElasticsearchClient: elasticsearchClient }, + mockUser1, + options1 + ); const options2 = { filter: nodeBuilder.is('foo', 'bar') }; - const response2 = await service.find({ savedObjectsClient }, mockUser1, options2); + const response2 = await service.find( + { savedObjectsClient, internalElasticsearchClient: elasticsearchClient }, + mockUser1, + options2 + ); - expect(response1).toBe(mockResponse); - expect(response2).toBe(mockResponse); + expect(response1).toEqual(mockResponse); + expect(response2).toEqual(mockResponse); const [[findOptions1], [findOptions2]] = savedObjectsClient.find.mock.calls; expect(findOptions1).toMatchInlineSnapshot(` @@ -599,13 +589,20 @@ describe('SearchSessionService', () => { total: 1, per_page: 1, page: 0, + statuses: { + [mockSavedObject.id]: { status: SearchSessionStatus.IN_PROGRESS }, + }, }; savedObjectsClient.find.mockResolvedValue(mockResponse); const options = { page: 0, perPage: 5 }; - const response = await service.find({ savedObjectsClient }, null, options); + const response = await service.find( + { savedObjectsClient, internalElasticsearchClient: elasticsearchClient }, + null, + options + ); - expect(response).toBe(mockResponse); + expect(response).toEqual(mockResponse); const [[findOptions]] = savedObjectsClient.find.mock.calls; expect(findOptions).toMatchInlineSnapshot(` Object { @@ -642,7 +639,6 @@ describe('SearchSessionService', () => { expect(type).toBe(SEARCH_SESSION_TYPE); expect(id).toBe(sessionId); expect(callAttributes).toHaveProperty('name', attributes.name); - expect(callAttributes).toHaveProperty('touched'); }); it('throws if user conflicts', () => { @@ -675,7 +671,6 @@ describe('SearchSessionService', () => { expect(type).toBe(SEARCH_SESSION_TYPE); expect(id).toBe(sessionId); expect(callAttributes).toHaveProperty('name', 'new_name'); - expect(callAttributes).toHaveProperty('touched'); }); }); @@ -688,8 +683,7 @@ describe('SearchSessionService', () => { expect(type).toBe(SEARCH_SESSION_TYPE); expect(id).toBe(sessionId); - expect(callAttributes).toHaveProperty('status', SearchSessionStatus.CANCELLED); - expect(callAttributes).toHaveProperty('touched'); + expect(callAttributes).toHaveProperty('isCanceled', true); }); it('throws if user conflicts', () => { @@ -709,8 +703,7 @@ describe('SearchSessionService', () => { expect(type).toBe(SEARCH_SESSION_TYPE); expect(id).toBe(sessionId); - expect(callAttributes).toHaveProperty('status', SearchSessionStatus.CANCELLED); - expect(callAttributes).toHaveProperty('touched'); + expect(callAttributes).toHaveProperty('isCanceled', true); }); }); @@ -740,11 +733,9 @@ describe('SearchSessionService', () => { expect(callAttributes).toHaveProperty('idMapping', { [requestHash]: { id: searchId, - status: SearchSessionStatus.IN_PROGRESS, strategy: MOCK_STRATEGY, }, }); - expect(callAttributes).toHaveProperty('touched'); }); it('retries updating the saved object if there was a ES conflict 409', async () => { @@ -827,15 +818,12 @@ describe('SearchSessionService', () => { expect(callAttributes).toHaveProperty('idMapping', { [requestHash]: { id: searchId, - status: SearchSessionStatus.IN_PROGRESS, strategy: MOCK_STRATEGY, }, }); expect(callAttributes).toHaveProperty('expires'); expect(callAttributes).toHaveProperty('created'); - expect(callAttributes).toHaveProperty('touched'); expect(callAttributes).toHaveProperty('sessionId', sessionId); - expect(callAttributes).toHaveProperty('persisted', false); }); it('retries updating if update returned 404 and then update returned conflict 409 (first create race condition)', async () => { @@ -939,16 +927,13 @@ describe('SearchSessionService', () => { expect(callAttributes1).toHaveProperty('idMapping', { [requestHash1]: { id: searchId1, - status: SearchSessionStatus.IN_PROGRESS, strategy: MOCK_STRATEGY, }, [requestHash2]: { id: searchId2, - status: SearchSessionStatus.IN_PROGRESS, strategy: MOCK_STRATEGY, }, }); - expect(callAttributes1).toHaveProperty('touched'); const [type2, id2, callAttributes2] = savedObjectsClient.update.mock.calls[1]; expect(type2).toBe(SEARCH_SESSION_TYPE); @@ -956,11 +941,9 @@ describe('SearchSessionService', () => { expect(callAttributes2).toHaveProperty('idMapping', { [requestHash3]: { id: searchId3, - status: SearchSessionStatus.IN_PROGRESS, strategy: MOCK_STRATEGY, }, }); - expect(callAttributes2).toHaveProperty('touched'); }); }); diff --git a/src/plugins/data/server/search/session/session_service.ts b/src/plugins/data/server/search/session/session_service.ts index e46c9bc80a2cc..d82956d19f73f 100644 --- a/src/plugins/data/server/search/session/session_service.ts +++ b/src/plugins/data/server/search/session/session_service.ts @@ -8,67 +8,48 @@ import { notFound } from '@hapi/boom'; import { debounce } from 'lodash'; -import { nodeBuilder, fromKueryExpression } from '@kbn/es-query'; +import { fromKueryExpression, nodeBuilder } from '@kbn/es-query'; import { CoreSetup, CoreStart, KibanaRequest, - SavedObjectsClientContract, Logger, SavedObject, - SavedObjectsFindOptions, + SavedObjectsClientContract, SavedObjectsErrorHelpers, + SavedObjectsFindOptions, + ElasticsearchClient, } from '@kbn/core/server'; import type { AuthenticatedUser, SecurityPluginSetup } from '@kbn/security-plugin/server'; -import type { - TaskManagerSetupContract, - TaskManagerStartContract, -} from '@kbn/task-manager-plugin/server'; import { + ENHANCED_ES_SEARCH_STRATEGY, IKibanaSearchRequest, ISearchOptions, - ENHANCED_ES_SEARCH_STRATEGY, SEARCH_SESSION_TYPE, SearchSessionRequestInfo, SearchSessionSavedObjectAttributes, - SearchSessionStatus, + SearchSessionsFindResponse, + SearchSessionStatusResponse, } from '../../../common'; import { ISearchSessionService, NoSearchIdInSessionError } from '../..'; import { createRequestHash } from './utils'; import { ConfigSchema, SearchSessionsConfigSchema } from '../../../config'; -import { - registerSearchSessionsTask, - scheduleSearchSessionsTask, - unscheduleSearchSessionsTask, -} from './setup_task'; -import { SearchStatus } from './types'; -import { - checkPersistedSessionsProgress, - SEARCH_SESSIONS_TASK_ID, - SEARCH_SESSIONS_TASK_TYPE, -} from './check_persisted_sessions'; -import { - SEARCH_SESSIONS_CLEANUP_TASK_TYPE, - checkNonPersistedSessions, - SEARCH_SESSIONS_CLEANUP_TASK_ID, -} from './check_non_persisted_sessions'; -import { - SEARCH_SESSIONS_EXPIRE_TASK_TYPE, - SEARCH_SESSIONS_EXPIRE_TASK_ID, - checkPersistedCompletedSessionExpiration, -} from './expire_persisted_sessions'; +import { getSessionStatus } from './get_session_status'; export interface SearchSessionDependencies { savedObjectsClient: SavedObjectsClientContract; } + +export interface SearchSessionStatusDependencies extends SearchSessionDependencies { + internalElasticsearchClient: ElasticsearchClient; +} + interface SetupDependencies { - taskManager: TaskManagerSetupContract; security?: SecurityPluginSetup; } -interface StartDependencies { - taskManager: TaskManagerStartContract; -} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface StartDependencies {} const DEBOUNCE_UPDATE_OR_CREATE_WAIT = 1000; const DEBOUNCE_UPDATE_OR_CREATE_MAX_WAIT = 5000; @@ -101,83 +82,17 @@ export class SearchSessionService implements ISearchSessionService { public setup(core: CoreSetup, deps: SetupDependencies) { this.security = deps.security; - const taskDeps = { - config: this.config, - taskManager: deps.taskManager, - logger: this.logger, - }; - - registerSearchSessionsTask( - core, - taskDeps, - SEARCH_SESSIONS_TASK_TYPE, - 'persisted session progress', - checkPersistedSessionsProgress - ); - - registerSearchSessionsTask( - core, - taskDeps, - SEARCH_SESSIONS_CLEANUP_TASK_TYPE, - 'non persisted session cleanup', - checkNonPersistedSessions - ); - - registerSearchSessionsTask( - core, - taskDeps, - SEARCH_SESSIONS_EXPIRE_TASK_TYPE, - 'complete session expiration', - checkPersistedCompletedSessionExpiration - ); this.setupCompleted = true; } - public async start(core: CoreStart, deps: StartDependencies) { + public start(core: CoreStart, deps: StartDependencies) { if (!this.setupCompleted) throw new Error('SearchSessionService setup() must be called before start()'); - - return this.setupMonitoring(core, deps); } public stop() {} - private setupMonitoring = async (core: CoreStart, deps: StartDependencies) => { - const taskDeps = { - config: this.config, - taskManager: deps.taskManager, - logger: this.logger, - }; - - if (this.sessionConfig.enabled) { - scheduleSearchSessionsTask( - taskDeps, - SEARCH_SESSIONS_TASK_ID, - SEARCH_SESSIONS_TASK_TYPE, - this.sessionConfig.trackingInterval - ); - - scheduleSearchSessionsTask( - taskDeps, - SEARCH_SESSIONS_CLEANUP_TASK_ID, - SEARCH_SESSIONS_CLEANUP_TASK_TYPE, - this.sessionConfig.cleanupInterval - ); - - scheduleSearchSessionsTask( - taskDeps, - SEARCH_SESSIONS_EXPIRE_TASK_ID, - SEARCH_SESSIONS_EXPIRE_TASK_TYPE, - this.sessionConfig.expireInterval - ); - } else { - unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_TASK_ID); - unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_CLEANUP_TASK_ID); - unscheduleSearchSessionsTask(taskDeps, SEARCH_SESSIONS_EXPIRE_TASK_ID); - } - }; - private processUpdateOrCreateBatchQueue = debounce( () => { const queue = [...this.updateOrCreateBatchQueue]; @@ -304,7 +219,6 @@ export class SearchSessionService implements ISearchSessionService { locatorId, initialState, restoreState, - persisted: true, }); }; @@ -324,14 +238,11 @@ export class SearchSessionService implements ISearchSessionService { SEARCH_SESSION_TYPE, { sessionId, - status: SearchSessionStatus.IN_PROGRESS, expires: new Date( Date.now() + this.sessionConfig.defaultExpiration.asMilliseconds() ).toISOString(), created: new Date().toISOString(), - touched: new Date().toISOString(), idMapping: {}, - persisted: false, version: this.version, realmType, realmName, @@ -353,14 +264,15 @@ export class SearchSessionService implements ISearchSessionService { sessionId ); this.throwOnUserConflict(user, session); + return session; }; - public find = ( - { savedObjectsClient }: SearchSessionDependencies, + public find = async ( + { savedObjectsClient, internalElasticsearchClient }: SearchSessionStatusDependencies, user: AuthenticatedUser | null, options: Omit - ) => { + ): Promise => { const userFilters = user === null ? [] @@ -378,11 +290,31 @@ export class SearchSessionService implements ISearchSessionService { const filterKueryNode = typeof options.filter === 'string' ? fromKueryExpression(options.filter) : options.filter; const filter = nodeBuilder.and(userFilters.concat(filterKueryNode ?? [])); - return savedObjectsClient.find({ + const findResponse = await savedObjectsClient.find({ ...options, filter, type: SEARCH_SESSION_TYPE, }); + + const sessionStatuses = await Promise.all( + findResponse.saved_objects.map(async (so) => { + const sessionStatus = await getSessionStatus( + { internalClient: internalElasticsearchClient }, + so.attributes, + this.sessionConfig + ); + + return sessionStatus; + }) + ); + + return { + ...findResponse, + statuses: sessionStatuses.reduce((res, status, index) => { + res[findResponse.saved_objects[index].id] = { status }; + return res; + }, {} as Record), + }; }; public update = async ( @@ -399,7 +331,6 @@ export class SearchSessionService implements ISearchSessionService { sessionId, { ...attributes, - touched: new Date().toISOString(), } ); }; @@ -419,9 +350,9 @@ export class SearchSessionService implements ISearchSessionService { user: AuthenticatedUser | null, sessionId: string ) => { - this.logger.debug(`delete | ${sessionId}`); + this.logger.debug(`cancel | ${sessionId}`); return this.update(deps, user, sessionId, { - status: SearchSessionStatus.CANCELLED, + isCanceled: true, }); }; @@ -445,8 +376,9 @@ export class SearchSessionService implements ISearchSessionService { user: AuthenticatedUser | null, searchRequest: IKibanaSearchRequest, searchId: string, - { sessionId, strategy = ENHANCED_ES_SEARCH_STRATEGY }: ISearchOptions + options: ISearchOptions ) => { + const { sessionId, strategy = ENHANCED_ES_SEARCH_STRATEGY } = options; if (!this.sessionConfig.enabled || !sessionId || !searchId) return; this.logger.debug(`trackId | ${sessionId} | ${searchId}`); @@ -454,10 +386,9 @@ export class SearchSessionService implements ISearchSessionService { if (searchRequest.params) { const requestHash = createRequestHash(searchRequest.params); - const searchInfo = { + const searchInfo: SearchSessionRequestInfo = { id: searchId, strategy, - status: SearchStatus.IN_PROGRESS, }; idMapping = { [requestHash]: searchInfo }; } @@ -471,6 +402,7 @@ export class SearchSessionService implements ISearchSessionService { sessionId: string ) { const searchSession = await this.get(deps, user, sessionId); + const searchIdMapping = new Map(); Object.values(searchSession.attributes.idMapping).forEach((requestInfo) => { searchIdMapping.set(requestInfo.id, requestInfo.strategy); @@ -478,6 +410,23 @@ export class SearchSessionService implements ISearchSessionService { return searchIdMapping; } + public async status( + deps: SearchSessionStatusDependencies, + user: AuthenticatedUser | null, + sessionId: string + ): Promise { + this.logger.debug(`status | ${sessionId}`); + const session = await this.get(deps, user, sessionId); + + const sessionStatus = await getSessionStatus( + { internalClient: deps.internalElasticsearchClient }, + session.attributes, + this.sessionConfig + ); + + return { status: sessionStatus }; + } + /** * Look up an existing search ID that matches the given request in the given session so that the * request can continue rather than restart. @@ -510,13 +459,15 @@ export class SearchSessionService implements ISearchSessionService { return session.attributes.idMapping[requestHash].id; }; - public asScopedProvider = ({ savedObjects }: CoreStart) => { + public asScopedProvider = ({ savedObjects, elasticsearch }: CoreStart) => { return (request: KibanaRequest) => { const user = this.security?.authc.getCurrentUser(request) ?? null; const savedObjectsClient = savedObjects.getScopedClient(request, { includedHiddenTypes: [SEARCH_SESSION_TYPE], }); - const deps = { savedObjectsClient }; + + const internalElasticsearchClient = elasticsearch.client.asScoped(request).asInternalUser; + const deps = { savedObjectsClient, internalElasticsearchClient }; return { getId: this.getId.bind(this, deps, user), trackId: this.trackId.bind(this, deps, user), @@ -528,6 +479,7 @@ export class SearchSessionService implements ISearchSessionService { extend: this.extend.bind(this, deps, user), cancel: this.cancel.bind(this, deps, user), delete: this.delete.bind(this, deps, user), + status: this.status.bind(this, deps, user), getConfig: () => this.config.search.sessions, }; }; diff --git a/src/plugins/data/server/search/session/setup_task.ts b/src/plugins/data/server/search/session/setup_task.ts deleted file mode 100644 index 5fe44b0901b79..0000000000000 --- a/src/plugins/data/server/search/session/setup_task.ts +++ /dev/null @@ -1,121 +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 { Duration } from 'moment'; -import { filter, takeUntil } from 'rxjs/operators'; -import { BehaviorSubject } from 'rxjs'; -import type { RunContext, TaskRunCreatorFunction } from '@kbn/task-manager-plugin/server'; -import { CoreSetup, SavedObjectsClient } from '@kbn/core/server'; -import { SEARCH_SESSION_TYPE } from '../../../common'; -import { - SearchSessionTaskSetupDeps, - SearchSessionTaskStartDeps, - SearchSessionTaskFn, -} from './types'; - -export function searchSessionTaskRunner( - core: CoreSetup, - deps: SearchSessionTaskSetupDeps, - title: string, - checkFn: SearchSessionTaskFn -): TaskRunCreatorFunction { - const { logger, config } = deps; - return ({ taskInstance }: RunContext) => { - const aborted$ = new BehaviorSubject(false); - return { - async run() { - try { - const sessionConfig = config.search.sessions; - const [coreStart] = await core.getStartServices(); - if (!sessionConfig.enabled) { - logger.debug(`Search sessions are disabled. Skipping task ${title}.`); - return; - } - if (aborted$.getValue()) return; - - const internalRepo = coreStart.savedObjects.createInternalRepository([ - SEARCH_SESSION_TYPE, - ]); - const internalSavedObjectsClient = new SavedObjectsClient(internalRepo); - await checkFn( - { - logger, - client: coreStart.elasticsearch.client.asInternalUser, - savedObjectsClient: internalSavedObjectsClient, - }, - sessionConfig - ) - .pipe(takeUntil(aborted$.pipe(filter((aborted) => aborted)))) - .toPromise(); - - return { - state: {}, - }; - } catch (e) { - logger.error(`An error occurred. Skipping task ${title}.`); - } - }, - cancel: async () => { - aborted$.next(true); - }, - }; - }; -} - -export function registerSearchSessionsTask( - core: CoreSetup, - deps: SearchSessionTaskSetupDeps, - taskType: string, - title: string, - checkFn: SearchSessionTaskFn -) { - deps.taskManager.registerTaskDefinitions({ - [taskType]: { - title, - createTaskRunner: searchSessionTaskRunner(core, deps, title, checkFn), - timeout: `${deps.config.search.sessions.monitoringTaskTimeout.asSeconds()}s`, - }, - }); -} - -export async function unscheduleSearchSessionsTask( - { taskManager, logger }: SearchSessionTaskStartDeps, - taskId: string -) { - try { - await taskManager.removeIfExists(taskId); - logger.debug(`${taskId} cleared`); - } catch (e) { - logger.error(`${taskId} Error clearing task ${e.message}`); - } -} - -export async function scheduleSearchSessionsTask( - { taskManager, logger }: SearchSessionTaskStartDeps, - taskId: string, - taskType: string, - interval: Duration -) { - await taskManager.removeIfExists(taskId); - - try { - await taskManager.ensureScheduled({ - id: taskId, - taskType, - schedule: { - interval: `${interval.asSeconds()}s`, - }, - state: {}, - params: {}, - }); - - logger.debug(`${taskId} scheduled to run`); - } catch (e) { - logger.error(`${taskId} Error scheduling task ${e.message}`); - } -} diff --git a/src/plugins/data/server/search/session/types.ts b/src/plugins/data/server/search/session/types.ts index e39a33774f073..76d5f30028736 100644 --- a/src/plugins/data/server/search/session/types.ts +++ b/src/plugins/data/server/search/session/types.ts @@ -6,26 +6,23 @@ * Side Public License, v 1. */ -import { Observable } from 'rxjs'; import { CoreStart, KibanaRequest, SavedObject, SavedObjectsFindOptions, - SavedObjectsFindResponse, SavedObjectsUpdateResponse, - ElasticsearchClient, - Logger, - SavedObjectsClientContract, } from '@kbn/core/server'; -import type { - TaskManagerSetupContract, - TaskManagerStartContract, -} from '@kbn/task-manager-plugin/server'; -import { KueryNode } from '@kbn/es-query'; -import { SearchSessionSavedObjectAttributes } from '../../../common'; -import { IKibanaSearchRequest, ISearchOptions } from '../../../common/search'; -import { SearchSessionsConfigSchema, ConfigSchema } from '../../../config'; +import { + IKibanaSearchRequest, + ISearchOptions, + SearchSessionsFindResponse, + SearchSessionSavedObjectAttributes, + SearchSessionStatusResponse, +} from '../../../common/search'; +import { SearchSessionsConfigSchema } from '../../../config'; + +export { SearchStatus } from '../../../common/search'; export interface IScopedSearchSessionsClient { getId: (request: IKibanaSearchRequest, options: ISearchOptions) => Promise; @@ -40,9 +37,7 @@ export interface IScopedSearchSessionsClient { attributes: Partial ) => Promise | undefined>; get: (sessionId: string) => Promise>; - find: ( - options: Omit - ) => Promise>; + find: (options: Omit) => Promise; update: ( sessionId: string, attributes: Partial @@ -53,50 +48,10 @@ export interface IScopedSearchSessionsClient { sessionId: string, expires: Date ) => Promise>; + status: (sessionId: string) => Promise; getConfig: () => SearchSessionsConfigSchema | null; } export interface ISearchSessionService { asScopedProvider: (core: CoreStart) => (request: KibanaRequest) => IScopedSearchSessionsClient; } - -export enum SearchStatus { - IN_PROGRESS = 'in_progress', - ERROR = 'error', - COMPLETE = 'complete', -} - -export interface CheckSearchSessionsDeps { - savedObjectsClient: SavedObjectsClientContract; - client: ElasticsearchClient; - logger: Logger; -} - -export interface SearchSessionTaskSetupDeps { - taskManager: TaskManagerSetupContract; - logger: Logger; - config: ConfigSchema; -} - -export interface SearchSessionTaskStartDeps { - taskManager: TaskManagerStartContract; - logger: Logger; - config: ConfigSchema; -} - -export type SearchSessionTaskFn = ( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema -) => Observable; - -export type SearchSessionsResponse = SavedObjectsFindResponse< - SearchSessionSavedObjectAttributes, - unknown ->; - -export type CheckSearchSessionsFn = ( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - filter: KueryNode, - page: number -) => Observable; diff --git a/src/plugins/data/server/search/session/update_session_status.test.ts b/src/plugins/data/server/search/session/update_session_status.test.ts deleted file mode 100644 index 38e8ec6cad150..0000000000000 --- a/src/plugins/data/server/search/session/update_session_status.test.ts +++ /dev/null @@ -1,327 +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 { bulkUpdateSessions, updateSessionStatus } from './update_session_status'; -import { SearchSessionStatus, SearchSessionSavedObjectAttributes } from '../../../common'; -import { savedObjectsClientMock } from '@kbn/core/server/mocks'; -import { SearchStatus } from './types'; -import moment from 'moment'; -import { - SavedObjectsBulkUpdateObject, - SavedObjectsClientContract, - SavedObjectsFindResult, -} from '@kbn/core/server'; - -describe('bulkUpdateSessions', () => { - let mockClient: any; - const mockConfig: any = {}; - let savedObjectsClient: jest.Mocked; - const mockLogger: any = { - debug: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - beforeEach(() => { - savedObjectsClient = savedObjectsClientMock.create(); - mockClient = { - asyncSearch: { - status: jest.fn(), - delete: jest.fn(), - }, - eql: { - status: jest.fn(), - delete: jest.fn(), - }, - }; - }); - - describe('updateSessionStatus', () => { - test('updates expired session', async () => { - const so: SavedObjectsFindResult = { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - expires: moment().subtract(moment.duration(5, 'd')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } as any; - - const updated = await updateSessionStatus( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - mockConfig, - so - ); - - expect(updated).toBeTruthy(); - expect(so.attributes.status).toBe(SearchSessionStatus.EXPIRED); - }); - - test('does nothing if the search is still running', async () => { - const so = { - id: '123', - attributes: { - persisted: false, - status: SearchSessionStatus.IN_PROGRESS, - created: moment().subtract(moment.duration(3, 'm')), - touched: moment().subtract(moment.duration(10, 's')), - expires: moment().add(moment.duration(5, 'd')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } as any; - - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: true, - is_running: true, - }, - }); - - const updated = await updateSessionStatus( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - mockConfig, - so - ); - - expect(updated).toBeFalsy(); - expect(so.attributes.status).toBe(SearchSessionStatus.IN_PROGRESS); - }); - - test("doesn't re-check completed or errored searches", async () => { - const so = { - id: '123', - attributes: { - expires: moment().add(moment.duration(5, 'd')), - status: SearchSessionStatus.ERROR, - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.COMPLETE, - }, - 'another-search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.ERROR, - }, - }, - }, - } as any; - - const updated = await updateSessionStatus( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - mockConfig, - so - ); - - expect(updated).toBeFalsy(); - expect(mockClient.asyncSearch.status).not.toBeCalled(); - }); - - test('updates to complete if the search is done', async () => { - savedObjectsClient.bulkUpdate = jest.fn(); - const so = { - attributes: { - status: SearchSessionStatus.IN_PROGRESS, - touched: '123', - expires: moment().add(moment.duration(5, 'd')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } as any; - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: false, - is_running: false, - completion_status: 200, - }, - }); - - const updated = await updateSessionStatus( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - mockConfig, - so - ); - - expect(updated).toBeTruthy(); - - expect(mockClient.asyncSearch.status).toBeCalledWith({ id: 'search-id' }, { meta: true }); - expect(so.attributes.status).toBe(SearchSessionStatus.COMPLETE); - expect(so.attributes.status).toBe(SearchSessionStatus.COMPLETE); - expect(so.attributes.touched).not.toBe('123'); - expect(so.attributes.completed).not.toBeUndefined(); - expect(so.attributes.idMapping['search-hash'].status).toBe(SearchStatus.COMPLETE); - expect(so.attributes.idMapping['search-hash'].error).toBeUndefined(); - }); - - test('updates to error if the search is errored', async () => { - savedObjectsClient.bulkUpdate = jest.fn(); - const so = { - attributes: { - expires: moment().add(moment.duration(5, 'd')), - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } as any; - - mockClient.asyncSearch.status.mockResolvedValue({ - body: { - is_partial: false, - is_running: false, - completion_status: 500, - }, - }); - - const updated = await updateSessionStatus( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - mockConfig, - so - ); - - expect(updated).toBeTruthy(); - expect(so.attributes.status).toBe(SearchSessionStatus.ERROR); - expect(so.attributes.touched).not.toBe('123'); - expect(so.attributes.idMapping['search-hash'].status).toBe(SearchStatus.ERROR); - expect(so.attributes.idMapping['search-hash'].error).toBe( - 'Search completed with a 500 status' - ); - }); - }); - - describe('bulkUpdateSessions', () => { - test('does nothing if there are no open sessions', async () => { - await bulkUpdateSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - [] - ); - - expect(savedObjectsClient.bulkUpdate).not.toBeCalled(); - expect(savedObjectsClient.delete).not.toBeCalled(); - }); - - test('updates in space', async () => { - const so = { - namespaces: ['awesome'], - attributes: { - expires: moment().add(moment.duration(5, 'd')), - status: SearchSessionStatus.IN_PROGRESS, - touched: '123', - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } as any; - - savedObjectsClient.bulkUpdate = jest.fn().mockResolvedValue({ - saved_objects: [so], - }); - - await bulkUpdateSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - [so] - ); - - const [updateInput] = savedObjectsClient.bulkUpdate.mock.calls[0]; - const updatedAttributes = updateInput[0] as SavedObjectsBulkUpdateObject; - expect(updatedAttributes.namespace).toBe('awesome'); - }); - - test('logs failures', async () => { - const so = { - namespaces: ['awesome'], - attributes: { - expires: moment().add(moment.duration(5, 'd')), - status: SearchSessionStatus.IN_PROGRESS, - touched: '123', - idMapping: { - 'search-hash': { - id: 'search-id', - strategy: 'cool', - status: SearchStatus.IN_PROGRESS, - }, - }, - }, - } as any; - - savedObjectsClient.bulkUpdate = jest.fn().mockResolvedValue({ - saved_objects: [ - { - error: 'nope', - }, - ], - }); - - await bulkUpdateSessions( - { - savedObjectsClient, - client: mockClient, - logger: mockLogger, - }, - [so] - ); - - expect(savedObjectsClient.bulkUpdate).toBeCalledTimes(1); - expect(mockLogger.error).toBeCalledTimes(1); - }); - }); -}); diff --git a/src/plugins/data/server/search/session/update_session_status.ts b/src/plugins/data/server/search/session/update_session_status.ts deleted file mode 100644 index e8405eb5427b0..0000000000000 --- a/src/plugins/data/server/search/session/update_session_status.ts +++ /dev/null @@ -1,132 +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 { SavedObjectsFindResult, SavedObjectsUpdateResponse } from '@kbn/core/server'; -import { SearchSessionsConfigSchema } from '../../../config'; -import { - SearchSessionRequestInfo, - SearchSessionSavedObjectAttributes, - SearchSessionStatus, -} from '../../../common'; -import { getSearchStatus } from './get_search_status'; -import { getSessionStatus } from './get_session_status'; -import { CheckSearchSessionsDeps, SearchSessionsResponse, SearchStatus } from './types'; -import { isSearchSessionExpired } from './utils'; - -export async function updateSessionStatus( - { logger, client }: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - session: SavedObjectsFindResult -) { - let sessionUpdated = false; - const isExpired = isSearchSessionExpired(session); - - if (!isExpired) { - // Check statuses of all running searches - await Promise.all( - Object.keys(session.attributes.idMapping).map(async (searchKey: string) => { - const updateSearchRequest = ( - currentStatus: Pick - ) => { - sessionUpdated = true; - session.attributes.idMapping[searchKey] = { - ...session.attributes.idMapping[searchKey], - ...currentStatus, - }; - }; - - const searchInfo = session.attributes.idMapping[searchKey]; - if (searchInfo.status === SearchStatus.IN_PROGRESS) { - try { - const currentStatus = await getSearchStatus(client, searchInfo.id); - - if (currentStatus.status !== searchInfo.status) { - logger.debug(`search ${searchInfo.id} | status changed to ${currentStatus.status}`); - updateSearchRequest(currentStatus); - } - } catch (e) { - logger.error(e); - updateSearchRequest({ - status: SearchStatus.ERROR, - error: e.message || e.meta.error?.caused_by?.reason, - }); - } - } - }) - ); - } - - // And only then derive the session's status - const sessionStatus = isExpired - ? SearchSessionStatus.EXPIRED - : getSessionStatus(session.attributes, config); - if (sessionStatus !== session.attributes.status) { - const now = new Date().toISOString(); - session.attributes.status = sessionStatus; - session.attributes.touched = now; - if (sessionStatus === SearchSessionStatus.COMPLETE) { - session.attributes.completed = now; - } else if (session.attributes.completed) { - session.attributes.completed = null; - } - sessionUpdated = true; - } - - return sessionUpdated; -} - -export async function getAllSessionsStatusUpdates( - deps: CheckSearchSessionsDeps, - config: SearchSessionsConfigSchema, - searchSessions: SearchSessionsResponse -) { - const updatedSessions = new Array>(); - - await Promise.all( - searchSessions.saved_objects.map(async (session) => { - const updated = await updateSessionStatus(deps, config, session); - - if (updated) { - updatedSessions.push(session); - } - }) - ); - - return updatedSessions; -} - -export async function bulkUpdateSessions( - { logger, savedObjectsClient }: CheckSearchSessionsDeps, - updatedSessions: Array> -) { - if (updatedSessions.length) { - // If there's an error, we'll try again in the next iteration, so there's no need to check the output. - const updatedResponse = await savedObjectsClient.bulkUpdate( - updatedSessions.map((session) => ({ - ...session, - namespace: session.namespaces?.[0], - })) - ); - - const success: Array> = []; - const fail: Array> = []; - - updatedResponse.saved_objects.forEach((savedObjectResponse) => { - if ('error' in savedObjectResponse) { - fail.push(savedObjectResponse); - logger.error( - `Error while updating search session ${savedObjectResponse?.id}: ${savedObjectResponse.error?.message}` - ); - } else { - success.push(savedObjectResponse); - } - }); - - logger.debug(`Updating search sessions: success: ${success.length}, fail: ${fail.length}`); - } -} diff --git a/src/plugins/data/server/search/strategies/common/async_utils.test.ts b/src/plugins/data/server/search/strategies/common/async_utils.test.ts index 7c90a0fd4c124..9771a042f1872 100644 --- a/src/plugins/data/server/search/strategies/common/async_utils.test.ts +++ b/src/plugins/data/server/search/strategies/common/async_utils.test.ts @@ -21,7 +21,7 @@ const getMockSearchSessionsConfig = ({ describe('request utils', () => { describe('getCommonDefaultAsyncSubmitParams', () => { - test('Uses `keep_alive` from default params if no `sessionId` is provided', async () => { + test('Uses short `keep_alive` if no `sessionId` is provided', async () => { const mockConfig = getMockSearchSessionsConfig({ defaultExpiration: moment.duration(3, 'd'), }); @@ -29,13 +29,24 @@ describe('request utils', () => { expect(params).toHaveProperty('keep_alive', '1m'); }); - test('Uses `keep_alive` from config if enabled', async () => { + test('Uses short `keep_alive` if sessions enabled but no yet saved', async () => { const mockConfig = getMockSearchSessionsConfig({ defaultExpiration: moment.duration(3, 'd'), }); const params = getCommonDefaultAsyncSubmitParams(mockConfig, { sessionId: 'foo', }); + expect(params).toHaveProperty('keep_alive', '1m'); + }); + + test('Uses `keep_alive` from config if sessions enabled and session is saved', async () => { + const mockConfig = getMockSearchSessionsConfig({ + defaultExpiration: moment.duration(3, 'd'), + }); + const params = getCommonDefaultAsyncSubmitParams(mockConfig, { + sessionId: 'foo', + isStored: true, + }); expect(params).toHaveProperty('keep_alive', '259200000ms'); }); @@ -89,12 +100,51 @@ describe('request utils', () => { expect(params).toHaveProperty('keep_alive', '1m'); }); - test('Has no `keep_alive` if `sessionId` is provided', async () => { + test('Has short `keep_alive` if `sessionId` is provided', async () => { const mockConfig = getMockSearchSessionsConfig({ defaultExpiration: moment.duration(3, 'd'), enabled: true, }); const params = getCommonDefaultAsyncGetParams(mockConfig, { sessionId: 'foo' }); + expect(params).toHaveProperty('keep_alive', '1m'); + }); + + test('Has `keep_alive` from config if `sessionId` is provided and session is stored', async () => { + const mockConfig = getMockSearchSessionsConfig({ + defaultExpiration: moment.duration(3, 'd'), + enabled: true, + }); + const params = getCommonDefaultAsyncGetParams(mockConfig, { + sessionId: 'foo', + isStored: true, + }); + expect(params).toHaveProperty('keep_alive', '259200000ms'); + }); + + test("Don't extend keepAlive if search has already been extended", async () => { + const mockConfig = getMockSearchSessionsConfig({ + defaultExpiration: moment.duration(3, 'd'), + enabled: true, + }); + const params = getCommonDefaultAsyncGetParams(mockConfig, { + sessionId: 'foo', + isStored: true, + isSearchStored: true, + }); + expect(params).not.toHaveProperty('keep_alive'); + }); + + test("Don't extend keepAlive if search is being restored", async () => { + const mockConfig = getMockSearchSessionsConfig({ + defaultExpiration: moment.duration(3, 'd'), + enabled: true, + }); + const params = getCommonDefaultAsyncGetParams(mockConfig, { + sessionId: 'foo', + isStored: true, + isSearchStored: false, + isRestore: true, + }); expect(params).not.toHaveProperty('keep_alive'); }); diff --git a/src/plugins/data/server/search/strategies/common/async_utils.ts b/src/plugins/data/server/search/strategies/common/async_utils.ts index 46483ca3f3279..c0af68f915bd8 100644 --- a/src/plugins/data/server/search/strategies/common/async_utils.ts +++ b/src/plugins/data/server/search/strategies/common/async_utils.ts @@ -25,9 +25,10 @@ export function getCommonDefaultAsyncSubmitParams( > { const useSearchSessions = searchSessionsConfig?.enabled && !!options.sessionId; - const keepAlive = useSearchSessions - ? `${searchSessionsConfig!.defaultExpiration.asMilliseconds()}ms` - : '1m'; + const keepAlive = + useSearchSessions && options.isStored + ? `${searchSessionsConfig!.defaultExpiration.asMilliseconds()}ms` + : '1m'; return { // Wait up to 100ms for the response to return @@ -51,9 +52,13 @@ export function getCommonDefaultAsyncGetParams( return { // Wait up to 100ms for the response to return wait_for_completion_timeout: '100ms', - ...(useSearchSessions - ? // Don't change the expiration of search requests that are tracked in a search session - undefined + ...(useSearchSessions && options.isStored + ? // Use session's keep_alive if search belongs to a stored session + options.isSearchStored || options.isRestore // if search was already stored and extended, then no need to extend keepAlive + ? {} + : { + keep_alive: `${searchSessionsConfig!.defaultExpiration.asMilliseconds()}ms`, + } : { // We still need to do polling for searches not within the context of a search session or when search session disabled keep_alive: '1m', diff --git a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts index 409c84a4638f7..c2c42f1ff8963 100644 --- a/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts +++ b/src/plugins/data/server/search/strategies/ese_search/ese_search_strategy.test.ts @@ -205,7 +205,7 @@ describe('ES search strategy', () => { }); describe('with sessionId', () => { - it('makes a POST request with params (long keepalive)', async () => { + it('Submit search with session id that is not saved creates a search with short keep_alive', async () => { mockSubmitCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'logstash-*', body: { query: {} } }; @@ -218,10 +218,26 @@ describe('ES search strategy', () => { expect(request.index).toEqual(params.index); expect(request.body).toEqual(params.body); + expect(request).toHaveProperty('keep_alive', '1m'); + }); + + it('Submit search with session id and session is saved creates a search with long keep_alive', async () => { + mockSubmitCaller.mockResolvedValueOnce(mockAsyncResponse); + + const params = { index: 'logstash-*', body: { query: {} } }; + const esSearch = await enhancedEsSearchStrategyProvider(mockLegacyConfig$, mockLogger); + + await esSearch.search({ params }, { sessionId: '1', isStored: true }, mockDeps).toPromise(); + + expect(mockSubmitCaller).toBeCalled(); + const request = mockSubmitCaller.mock.calls[0][0]; + expect(request.index).toEqual(params.index); + expect(request.body).toEqual(params.body); + expect(request).toHaveProperty('keep_alive', '604800000ms'); }); - it('makes a GET request to async search without keepalive', async () => { + it('makes a GET request to async search with short keepalive, if session is not saved', async () => { mockGetCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'logstash-*', body: { query: {} } }; @@ -229,6 +245,44 @@ describe('ES search strategy', () => { await esSearch.search({ id: 'foo', params }, { sessionId: '1' }, mockDeps).toPromise(); + expect(mockGetCaller).toBeCalled(); + const request = mockGetCaller.mock.calls[0][0]; + expect(request.id).toEqual('foo'); + expect(request).toHaveProperty('wait_for_completion_timeout'); + expect(request).toHaveProperty('keep_alive', '1m'); + }); + + it('makes a GET request to async search with long keepalive, if session is saved', async () => { + mockGetCaller.mockResolvedValueOnce(mockAsyncResponse); + + const params = { index: 'logstash-*', body: { query: {} } }; + const esSearch = await enhancedEsSearchStrategyProvider(mockLegacyConfig$, mockLogger); + + await esSearch + .search({ id: 'foo', params }, { sessionId: '1', isStored: true }, mockDeps) + .toPromise(); + + expect(mockGetCaller).toBeCalled(); + const request = mockGetCaller.mock.calls[0][0]; + expect(request.id).toEqual('foo'); + expect(request).toHaveProperty('wait_for_completion_timeout'); + expect(request).toHaveProperty('keep_alive', '604800000ms'); + }); + + it('makes a GET request to async search with no keepalive, if session is session saved and search is stored', async () => { + mockGetCaller.mockResolvedValueOnce(mockAsyncResponse); + + const params = { index: 'logstash-*', body: { query: {} } }; + const esSearch = await enhancedEsSearchStrategyProvider(mockLegacyConfig$, mockLogger); + + await esSearch + .search( + { id: 'foo', params }, + { sessionId: '1', isSearchStored: true, isStored: true }, + mockDeps + ) + .toPromise(); + expect(mockGetCaller).toBeCalled(); const request = mockGetCaller.mock.calls[0][0]; expect(request.id).toEqual('foo'); diff --git a/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts b/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts index 878806d9b3559..b908a1df4f0ec 100644 --- a/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts +++ b/src/plugins/data/server/search/strategies/ese_search/request_utils.test.ts @@ -60,7 +60,7 @@ describe('request utils', () => { expect(params).toHaveProperty('keep_alive', '1m'); }); - test('Uses `keep_alive` from config if enabled', async () => { + test('Uses `keep_alive` from config if enabled and session is stored', async () => { const mockUiSettingsClient = getMockUiSettingsClient({ [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: false, }); @@ -69,6 +69,7 @@ describe('request utils', () => { }); const params = await getDefaultAsyncSubmitParams(mockUiSettingsClient, mockConfig, { sessionId: 'foo', + isStored: true, }); expect(params).toHaveProperty('keep_alive', '259200000ms'); }); @@ -132,12 +133,16 @@ describe('request utils', () => { expect(params).toHaveProperty('keep_alive', '1m'); }); - test('Has no `keep_alive` if `sessionId` is provided', async () => { + test('Has no `keep_alive` if `sessionId` is provided and search already stored', async () => { const mockConfig = getMockSearchSessionsConfig({ defaultExpiration: moment.duration(3, 'd'), enabled: true, }); - const params = getDefaultAsyncGetParams(mockConfig, { sessionId: 'foo' }); + const params = getDefaultAsyncGetParams(mockConfig, { + sessionId: 'foo', + isStored: true, + isSearchStored: true, + }); expect(params).not.toHaveProperty('keep_alive'); }); diff --git a/src/plugins/data/server/search/strategies/sql_search/request_utils.test.ts b/src/plugins/data/server/search/strategies/sql_search/request_utils.test.ts index 9944de7be17be..d37bcfb0655f8 100644 --- a/src/plugins/data/server/search/strategies/sql_search/request_utils.test.ts +++ b/src/plugins/data/server/search/strategies/sql_search/request_utils.test.ts @@ -29,12 +29,13 @@ describe('request utils', () => { expect(params).toHaveProperty('keep_alive', '1m'); }); - test('Uses `keep_alive` from config if enabled', async () => { + test('Uses `keep_alive` from config if enabled and session is stored', async () => { const mockConfig = getMockSearchSessionsConfig({ defaultExpiration: moment.duration(3, 'd'), }); const params = getDefaultAsyncSubmitParams(mockConfig, { sessionId: 'foo', + isStored: true, }); expect(params).toHaveProperty('keep_alive', '259200000ms'); }); @@ -89,12 +90,16 @@ describe('request utils', () => { expect(params).toHaveProperty('keep_alive', '1m'); }); - test('Has no `keep_alive` if `sessionId` is provided', async () => { + test('Has no `keep_alive` if `sessionId` is provided, search and session are stored', async () => { const mockConfig = getMockSearchSessionsConfig({ defaultExpiration: moment.duration(3, 'd'), enabled: true, }); - const params = getDefaultAsyncGetParams(mockConfig, { sessionId: 'foo' }); + const params = getDefaultAsyncGetParams(mockConfig, { + sessionId: 'foo', + isStored: true, + isSearchStored: true, + }); expect(params).not.toHaveProperty('keep_alive'); }); diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 2d2a10300ee69..50fc29334d22c 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -89,6 +89,7 @@ export interface IScopedSearchClient extends ISearchClient { cancelSession: IScopedSearchSessionsClient['cancel']; deleteSession: IScopedSearchSessionsClient['delete']; extendSession: IScopedSearchSessionsClient['extend']; + getSessionStatus: IScopedSearchSessionsClient['status']; } export interface ISearchStart< diff --git a/src/plugins/data_view_editor/public/components/data_view_editor_flyout_content.tsx b/src/plugins/data_view_editor/public/components/data_view_editor_flyout_content.tsx index 08a13c7f43d48..510719d6c266e 100644 --- a/src/plugins/data_view_editor/public/components/data_view_editor_flyout_content.tsx +++ b/src/plugins/data_view_editor/public/components/data_view_editor_flyout_content.tsx @@ -7,7 +7,14 @@ */ import React, { useState, useEffect, useCallback, useRef } from 'react'; -import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiLoadingSpinner } from '@elastic/eui'; +import { + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiLoadingSpinner, + EuiLink, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import memoizeOne from 'memoize-one'; import { @@ -67,6 +74,7 @@ export interface Props { defaultTypeIsRollup?: boolean; requireTimestampField?: boolean; editData?: DataView; + showManagementLink?: boolean; allowAdHoc: boolean; } @@ -85,11 +93,14 @@ const IndexPatternEditorFlyoutContentComponent = ({ requireTimestampField = false, editData, allowAdHoc, + showManagementLink, }: Props) => { const { - services: { http, dataViews, uiSettings, overlays }, + services: { application, http, dataViews, uiSettings, overlays }, } = useKibana(); + const canSave = dataViews.getCanSaveSync(); + const { form } = useForm({ // Prefill with data if editData exists defaultValue: { @@ -376,6 +387,17 @@ const IndexPatternEditorFlyoutContentComponent = ({

{editData ? editorTitleEditMode : editorTitle}

+ {showManagementLink && editData && editData.id && ( + + {i18n.translate('indexPatternEditor.goToManagementPage', { + defaultMessage: 'View on data view management page', + })} + + )}
{indexPatternTypeSelect} @@ -425,7 +447,9 @@ const IndexPatternEditorFlyoutContentComponent = ({ }} submitDisabled={form.isSubmitted && !form.isValid} isEdit={!!editData} + isPersisted={Boolean(editData && editData.isPersisted())} allowAdHoc={allowAdHoc} + canSave={canSave} /> diff --git a/src/plugins/data_view_editor/public/components/data_view_flyout_content_container.tsx b/src/plugins/data_view_editor/public/components/data_view_flyout_content_container.tsx index 35801d0a9dcf3..b74c9acc8b2cd 100644 --- a/src/plugins/data_view_editor/public/components/data_view_flyout_content_container.tsx +++ b/src/plugins/data_view_editor/public/components/data_view_flyout_content_container.tsx @@ -20,6 +20,7 @@ const IndexPatternFlyoutContentContainer = ({ requireTimestampField = false, editData, allowAdHocDataView, + showManagementLink, }: DataViewEditorProps) => { const { services: { dataViews, notifications }, @@ -68,6 +69,7 @@ const IndexPatternFlyoutContentContainer = ({ defaultTypeIsRollup={defaultTypeIsRollup} requireTimestampField={requireTimestampField} editData={editData} + showManagementLink={showManagementLink} allowAdHoc={allowAdHocDataView || false} /> ); diff --git a/src/plugins/data_view_editor/public/components/footer/footer.tsx b/src/plugins/data_view_editor/public/components/footer/footer.tsx index 01d954fb29bdb..024885e91d548 100644 --- a/src/plugins/data_view_editor/public/components/footer/footer.tsx +++ b/src/plugins/data_view_editor/public/components/footer/footer.tsx @@ -22,7 +22,9 @@ interface FooterProps { onSubmit: (isAdHoc?: boolean) => void; submitDisabled: boolean; isEdit: boolean; + isPersisted: boolean; allowAdHoc: boolean; + canSave: boolean; } const closeButtonLabel = i18n.translate('indexPatternEditor.editor.flyoutCloseButtonLabel', { @@ -37,11 +39,26 @@ const editButtonLabel = i18n.translate('indexPatternEditor.editor.flyoutEditButt defaultMessage: 'Save', }); +const editUnpersistedButtonLabel = i18n.translate( + 'indexPatternEditor.editor.flyoutEditUnpersistedButtonLabel', + { + defaultMessage: 'Continue to use without saving', + } +); + const exploreButtonLabel = i18n.translate('indexPatternEditor.editor.flyoutExploreButtonLabel', { defaultMessage: 'Use without saving', }); -export const Footer = ({ onCancel, onSubmit, submitDisabled, isEdit, allowAdHoc }: FooterProps) => { +export const Footer = ({ + onCancel, + onSubmit, + submitDisabled, + isEdit, + allowAdHoc, + isPersisted, + canSave, +}: FooterProps) => { const submitPersisted = () => { onSubmit(false); }; @@ -81,17 +98,23 @@ export const Footer = ({ onCancel, onSubmit, submitDisabled, isEdit, allowAdHoc )} - - - {isEdit ? editButtonLabel : saveButtonLabel} - - + {(canSave || (isEdit && !isPersisted)) && ( + + + {isEdit + ? isPersisted + ? editButtonLabel + : editUnpersistedButtonLabel + : saveButtonLabel} + + + )} diff --git a/src/plugins/data_view_editor/public/open_editor.tsx b/src/plugins/data_view_editor/public/open_editor.tsx index b422de8e40ce2..29ea140daef4b 100644 --- a/src/plugins/data_view_editor/public/open_editor.tsx +++ b/src/plugins/data_view_editor/public/open_editor.tsx @@ -35,6 +35,7 @@ export const getEditorOpener = notifications, application, dataViews, + overlays, searchClient, }); @@ -46,6 +47,7 @@ export const getEditorOpener = defaultTypeIsRollup = false, requireTimestampField = false, allowAdHocDataView = false, + editData, }: DataViewEditorProps): CloseEditor => { const closeEditor = () => { if (overlayRef) { @@ -72,9 +74,11 @@ export const getEditorOpener = closeEditor(); onCancel(); }} + editData={editData} defaultTypeIsRollup={defaultTypeIsRollup} requireTimestampField={requireTimestampField} allowAdHocDataView={allowAdHocDataView} + showManagementLink={Boolean(editData && editData.isPersisted())} /> , diff --git a/src/plugins/data_view_editor/public/plugin.tsx b/src/plugins/data_view_editor/public/plugin.tsx index b0186b838987b..232958fbb2c21 100644 --- a/src/plugins/data_view_editor/public/plugin.tsx +++ b/src/plugins/data_view_editor/public/plugin.tsx @@ -21,7 +21,7 @@ export class DataViewEditorPlugin } public start(core: CoreStart, plugins: StartPlugins) { - const { application, uiSettings, docLinks, http, notifications } = core; + const { application, uiSettings, docLinks, http, notifications, overlays } = core; const { data, dataViews } = plugins; return { @@ -48,6 +48,7 @@ export class DataViewEditorPlugin http, notifications, application, + overlays, dataViews, searchClient: data.search.search, }} diff --git a/src/plugins/data_view_editor/public/types.ts b/src/plugins/data_view_editor/public/types.ts index 4500e522119d5..b5e506db4d3e9 100644 --- a/src/plugins/data_view_editor/public/types.ts +++ b/src/plugins/data_view_editor/public/types.ts @@ -13,6 +13,7 @@ import { NotificationsStart, DocLinksStart, HttpSetup, + OverlayStart, } from '@kbn/core/public'; import { EuiComboBoxOptionOption } from '@elastic/eui'; @@ -31,6 +32,7 @@ export interface DataViewEditorContext { http: HttpSetup; notifications: NotificationsStart; application: ApplicationStart; + overlays: OverlayStart; dataViews: DataViewsPublicPluginStart; searchClient: DataPublicPluginStart['search']['search']; } @@ -62,6 +64,11 @@ export interface DataViewEditorProps { * if set to true user is presented with an option to create ad-hoc dataview without a saved object. */ allowAdHocDataView?: boolean; + + /** + * if set to true a link to the management page is shown + */ + showManagementLink?: boolean; } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/src/plugins/data_views/README.mdx b/src/plugins/data_views/README.mdx index 6d2ef4c97bb33..930ee4e76b6a9 100644 --- a/src/plugins/data_views/README.mdx +++ b/src/plugins/data_views/README.mdx @@ -1,17 +1,16 @@ --- -id: kibDataPlugin -slug: /kibana-dev-docs/services/data-plugin -title: Data services -image: https://source.unsplash.com/400x175/?Search -description: The data plugin contains services for searching, querying and filtering. -date: 2020-12-02 -tags: ['kibana', 'dev', 'contributor', 'api docs'] +id: kibDataViewsPlugin +slug: /kibana-dev-docs/services/data-views-plugin +title: Data Views services +description: The data views plugin contains services for dealing with Kibana's Data Views. +date: 2022-10-05 +tags: ['kibana', 'dev', 'contributor', 'api docs', 'data views', 'has data'] --- # Data Views The data views API provides a consistent method of structuring and formatting documents -and field lists across the various Kibana apps. Its typically used in conjunction with +and field lists across the various Kibana apps. It's typically used in conjunction with for composing queries. *Note: Kibana index patterns are currently being renamed to data views. There will be some naming inconsistencies until the transition is complete.* diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx index de3b30810859f..274cb85cc3535 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_sidebar_responsive.tsx @@ -182,7 +182,8 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) const { dataViewFieldEditor, dataViewEditor } = services; const { availableFields$ } = props; - const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView()); + const canEditDataView = + Boolean(dataViewEditor?.userPermissions.editDataView()) || !selectedDataView?.isPersisted(); useEffect( () => { @@ -241,25 +242,19 @@ export function DiscoverSidebarResponsive(props: DiscoverSidebarResponsiveProps) ] ); - const createNewDataView = useMemo( - () => - canEditDataView - ? () => { - const ref = dataViewEditor.openEditor({ - onSave: async (dataView) => { - onDataViewCreated(dataView); - }, - }); - if (setDataViewEditorRef) { - setDataViewEditorRef(ref); - } - if (closeFlyout) { - closeFlyout(); - } - } - : undefined, - [canEditDataView, dataViewEditor, setDataViewEditorRef, closeFlyout, onDataViewCreated] - ); + const createNewDataView = useCallback(() => { + const ref = dataViewEditor.openEditor({ + onSave: async (dataView) => { + onDataViewCreated(dataView); + }, + }); + if (setDataViewEditorRef) { + setDataViewEditorRef(ref); + } + if (closeFlyout) { + closeFlyout(); + } + }, [dataViewEditor, setDataViewEditorRef, closeFlyout, onDataViewCreated]); if (!selectedDataView) { return null; diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx index 82f3b1aadadbf..66f06169256ab 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 @@ -68,7 +68,8 @@ export const DiscoverTopNav = ({ const services = useDiscoverServices(); const { dataViewEditor, navigation, dataViewFieldEditor, data, uiSettings, dataViews } = services; - const canEditDataView = Boolean(dataViewEditor?.userPermissions.editDataView()); + const canEditDataView = + Boolean(dataViewEditor?.userPermissions.editDataView()) || !dataView.isPersisted(); const closeFieldEditor = useRef<() => void | undefined>(); const closeDataViewEditor = useRef<() => void | undefined>(); @@ -124,22 +125,16 @@ export const DiscoverTopNav = ({ [editField, canEditDataView] ); - const createNewDataView = useMemo( - () => - canEditDataView - ? () => { - closeDataViewEditor.current = dataViewEditor.openEditor({ - onSave: async (dataViewToSave) => { - if (dataViewToSave.id) { - onChangeDataView(dataViewToSave.id); - } - }, - allowAdHocDataView: true, - }); - } - : undefined, - [canEditDataView, dataViewEditor, onChangeDataView] - ); + const createNewDataView = useCallback(() => { + closeDataViewEditor.current = dataViewEditor.openEditor({ + onSave: async (dataViewToSave) => { + if (dataViewToSave.id) { + onChangeDataView(dataViewToSave.id); + } + }, + allowAdHocDataView: true, + }); + }, [dataViewEditor, onChangeDataView]); const onCreateDefaultAdHocDataView = useCallback( async (pattern: string) => { diff --git a/src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx b/src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx index 3d7ee2c52e37c..1d9eab7e1d8e4 100644 --- a/src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx +++ b/src/plugins/discover/public/components/discover_grid/build_edit_field_button.tsx @@ -29,7 +29,8 @@ export const buildEditFieldButton = ({ } const { canEdit: canEditField } = getFieldCapabilities(dataView, field); - const canEditDataView = Boolean(services.dataViewEditor?.userPermissions?.editDataView()); + const canEditDataView = + Boolean(services.dataViewEditor?.userPermissions?.editDataView()) || !dataView.isPersisted(); if (!canEditField || !canEditDataView) { return null; diff --git a/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx b/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx index 61f45ce84e3c3..1d479bd9b4c1c 100644 --- a/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx +++ b/src/plugins/expressions/public/react_expression_renderer/react_expression_renderer.tsx @@ -57,7 +57,9 @@ export function ReactExpressionRenderer({ return (
{isEmpty && } - {isLoading && } + {isLoading && ( + + )} {!isLoading && error && renderError?.(error.message, error)}
diff --git a/src/plugins/guided_onboarding/common/index.ts b/src/plugins/guided_onboarding/common/constants.ts similarity index 100% rename from src/plugins/guided_onboarding/common/index.ts rename to src/plugins/guided_onboarding/common/constants.ts diff --git a/src/plugins/guided_onboarding/common/types.ts b/src/plugins/guided_onboarding/common/types.ts new file mode 100644 index 0000000000000..412154ede98b0 --- /dev/null +++ b/src/plugins/guided_onboarding/common/types.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 type GuideId = 'observability' | 'security' | 'search'; + +export type ObservabilityStepIds = 'add_data' | 'view_dashboard' | 'tour_observability'; +export type SecurityStepIds = 'add_data' | 'rules' | 'alerts' | 'cases'; +export type SearchStepIds = 'add_data' | 'browse_docs' | 'search_experience'; + +export type GuideStepIds = ObservabilityStepIds | SecurityStepIds | SearchStepIds; + +/** + * Allowed states for a guide: + * in_progress: Guide has been started + * ready_to_complete: All steps have been completed, but the "Continue using Elastic" button has not been clicked + * complete: All steps and the guide have been completed + */ +export type GuideStatus = 'in_progress' | 'ready_to_complete' | 'complete'; + +/** + * Allowed states for each step in a guide: + * inactive: Step has not started + * active: Step is ready to start (i.e., the guide has been started) + * in_progress: Step has been started and is in progress + * complete: Step has been completed + */ +export type StepStatus = 'inactive' | 'active' | 'in_progress' | 'complete'; + +export interface GuideStep { + id: GuideStepIds; + status: StepStatus; +} + +export interface GuideState { + guideId: GuideId; + status: GuideStatus; + isActive?: boolean; // Drives the current guide shown in the dropdown panel + steps: GuideStep[]; +} diff --git a/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx b/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx index 5eaf24163d2ae..3506c15fcba35 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.test.tsx @@ -13,18 +13,39 @@ import { applicationServiceMock } from '@kbn/core-application-browser-mocks'; import { httpServiceMock } from '@kbn/core/public/mocks'; import { HttpSetup } from '@kbn/core/public'; -import { apiService } from '../services/api'; import { guidesConfig } from '../constants/guides_config'; +import type { GuideState } from '../../common/types'; +import { apiService } from '../services/api'; import { GuidePanel } from './guide_panel'; import { registerTestBed, TestBed } from '@kbn/test-jest-helpers'; const applicationMock = applicationServiceMock.createStartContract(); +const mockActiveSearchGuideState: GuideState = { + guideId: 'search', + isActive: true, + status: 'in_progress', + steps: [ + { + id: 'add_data', + status: 'active', + }, + { + id: 'browse_docs', + status: 'inactive', + }, + { + id: 'search_experience', + status: 'inactive', + }, + ], +}; + const getGuidePanel = () => () => { return ; }; -describe('GuidePanel', () => { +describe('Guided setup', () => { let httpClient: jest.Mocked; let testBed: TestBed; @@ -32,7 +53,7 @@ describe('GuidePanel', () => { httpClient = httpServiceMock.createStartContract({ basePath: '/base/path' }); // Set default state on initial request (no active guides) httpClient.get.mockResolvedValue({ - state: { activeGuide: 'unset', activeStep: 'unset' }, + state: [], }); apiService.setup(httpClient); @@ -48,29 +69,164 @@ describe('GuidePanel', () => { jest.restoreAllMocks(); }); - test('it should be disabled in there is no active guide', async () => { - const { exists } = testBed; - expect(exists('disabledGuideButton')).toBe(true); - expect(exists('guideButton')).toBe(false); - expect(exists('guidePanel')).toBe(false); + describe('Button component', () => { + test('should be disabled in there is no active guide', async () => { + const { exists } = testBed; + expect(exists('disabledGuideButton')).toBe(true); + expect(exists('guideButton')).toBe(false); + expect(exists('guidePanel')).toBe(false); + }); + + test('should be enabled if there is an active guide', async () => { + const { exists, component, find } = testBed; + + await act(async () => { + // Enable the "search" guide + await apiService.updateGuideState(mockActiveSearchGuideState, true); + }); + + component.update(); + + expect(exists('disabledGuideButton')).toBe(false); + expect(exists('guideButton')).toBe(true); + expect(find('guideButton').text()).toEqual('Setup guide'); + }); + + test('should show the step number in the button label if a step is active', async () => { + const { component, find } = testBed; + + const mockInProgressSearchGuideState: GuideState = { + ...mockActiveSearchGuideState, + steps: [ + { + id: mockActiveSearchGuideState.steps[0].id, + status: 'in_progress', + }, + mockActiveSearchGuideState.steps[1], + mockActiveSearchGuideState.steps[2], + ], + }; + + await act(async () => { + await apiService.updateGuideState(mockInProgressSearchGuideState, true); + }); + + component.update(); + + expect(find('guideButton').text()).toEqual('Setup guide: step 1'); + }); }); - test('it should be enabled if there is an active guide', async () => { - const { exists, component, find } = testBed; + describe('Panel component', () => { + test('should be enabled if a guide is activated', async () => { + const { exists, component, find } = testBed; - await act(async () => { - // Enable the "search" guide - await apiService.updateGuideState({ - activeGuide: 'search', - activeStep: guidesConfig.search.steps[0].id, + await act(async () => { + // Enable the "search" guide + await apiService.updateGuideState(mockActiveSearchGuideState, true); }); + + component.update(); + + expect(exists('guidePanel')).toBe(true); + expect(exists('guideProgress')).toBe(false); + expect(find('guidePanelStep').length).toEqual(guidesConfig.search.steps.length); }); - component.update(); + test('should show the progress bar if the first step has been completed', async () => { + const { component, exists } = testBed; - expect(exists('disabledGuideButton')).toBe(false); - expect(exists('guideButton')).toBe(true); - expect(exists('guidePanel')).toBe(true); - expect(find('guidePanelStep').length).toEqual(guidesConfig.search.steps.length); + const mockInProgressSearchGuideState: GuideState = { + ...mockActiveSearchGuideState, + steps: [ + { + id: mockActiveSearchGuideState.steps[0].id, + status: 'complete', + }, + mockActiveSearchGuideState.steps[1], + mockActiveSearchGuideState.steps[2], + ], + }; + + await act(async () => { + await apiService.updateGuideState(mockInProgressSearchGuideState, true); + }); + + component.update(); + + expect(exists('guidePanel')).toBe(true); + expect(exists('guideProgress')).toBe(true); + }); + + test('should show the "Continue using Elastic" button when all steps has been completed', async () => { + const { component, exists } = testBed; + + const readyToCompleteGuideState: GuideState = { + guideId: 'search', + status: 'ready_to_complete', + isActive: true, + steps: [ + { + id: 'add_data', + status: 'complete', + }, + { + id: 'browse_docs', + status: 'complete', + }, + { + id: 'search_experience', + status: 'complete', + }, + ], + }; + + await act(async () => { + await apiService.updateGuideState(readyToCompleteGuideState, true); + }); + + component.update(); + + expect(exists('useElasticButton')).toBe(true); + }); + + describe('Steps', () => { + test('should show "Start" button label if step has not been started', async () => { + const { component, find } = testBed; + + await act(async () => { + // Enable the "search" guide + await apiService.updateGuideState(mockActiveSearchGuideState, true); + }); + + component.update(); + + expect(find('activeStepButtonLabel').text()).toEqual('Start'); + }); + + test('should show "Continue" button label if step is in progress', async () => { + const { component, find } = testBed; + + const mockInProgressSearchGuideState: GuideState = { + ...mockActiveSearchGuideState, + steps: [ + { + id: mockActiveSearchGuideState.steps[0].id, + status: 'in_progress', + }, + mockActiveSearchGuideState.steps[1], + mockActiveSearchGuideState.steps[2], + ], + }; + + await act(async () => { + await apiService.updateGuideState(mockInProgressSearchGuideState, true); + }); + + component.update(); + + expect(find('activeStepButtonLabel').text()).toEqual('Continue'); + }); + }); }); }); diff --git a/src/plugins/guided_onboarding/public/components/guide_panel.tsx b/src/plugins/guided_onboarding/public/components/guide_panel.tsx index f32f55e42b340..bf57d502918d2 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect } from 'react'; import { EuiFlyout, EuiFlyoutBody, @@ -30,7 +30,9 @@ import { ApplicationStart } from '@kbn/core-application-browser'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { guidesConfig } from '../constants/guides_config'; -import type { GuideConfig, StepStatus, GuidedOnboardingState, StepConfig } from '../types'; +import type { GuideState, GuideStepIds } from '../../common/types'; +import type { GuideConfig, StepConfig } from '../types'; + import type { ApiService } from '../services/api'; import { GuideStep } from './guide_panel_step'; @@ -41,47 +43,48 @@ interface GuidePanelProps { application: ApplicationStart; } -const getConfig = (state?: GuidedOnboardingState): GuideConfig | undefined => { - if (state?.activeGuide && state.activeGuide !== 'unset') { - return guidesConfig[state.activeGuide]; +const getConfig = (state?: GuideState): GuideConfig | undefined => { + if (state) { + return guidesConfig[state.guideId]; } return undefined; }; -const getCurrentStep = ( - steps?: StepConfig[], - state?: GuidedOnboardingState -): number | undefined => { - if (steps && state?.activeStep) { - const activeStepIndex = steps.findIndex((step: StepConfig) => step.id === state.activeStep); - if (activeStepIndex > -1) { - return activeStepIndex + 1; - } +const getStepNumber = (state?: GuideState): number | undefined => { + let stepNumber: number | undefined; - return undefined; - } -}; + state?.steps.forEach((step, stepIndex) => { + // If the step is in_progress, show that step number + if (step.status === 'in_progress') { + stepNumber = stepIndex + 1; + } -const getStepStatus = (steps: StepConfig[], stepIndex: number, activeStep?: string): StepStatus => { - const activeStepIndex = steps.findIndex((step: StepConfig) => step.id === activeStep); + // If the step is active, show the previous step number + if (step.status === 'active') { + stepNumber = stepIndex; + } + }); - if (activeStepIndex < stepIndex) { - return 'incomplete'; - } + return stepNumber; +}; - if (activeStepIndex === stepIndex) { - return 'in_progress'; +const getProgress = (state?: GuideState): number => { + if (state) { + return state.steps.reduce((acc, currentVal) => { + if (currentVal.status === 'complete') { + acc = acc + 1; + } + return acc; + }, 0); } - - return 'complete'; + return 0; }; export const GuidePanel = ({ api, application }: GuidePanelProps) => { const { euiTheme } = useEuiTheme(); const [isGuideOpen, setIsGuideOpen] = useState(false); - const [guideState, setGuideState] = useState(undefined); - const isFirstRender = useRef(true); + const [guideState, setGuideState] = useState(undefined); const styles = getGuidePanelStyles(euiTheme); @@ -89,10 +92,10 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { setIsGuideOpen((prevIsGuideOpen) => !prevIsGuideOpen); }; - const navigateToStep = (step: StepConfig) => { - setIsGuideOpen(false); - if (step.location) { - application.navigateToApp(step.location.appID, { path: step.location.path }); + const navigateToStep = async (stepId: GuideStepIds, stepLocation: StepConfig['location']) => { + await api.startGuideStep(guideState!.guideId, stepId); + if (stepLocation) { + application.navigateToApp(stepLocation.appID, { path: stepLocation.path }); } }; @@ -101,22 +104,25 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { application.navigateToApp('home', { path: '#getting_started' }); }; + const completeGuide = async () => { + await api.completeGuide(guideState!.guideId); + }; + useEffect(() => { - const subscription = api.fetchGuideState$().subscribe((newState) => { - if ( - guideState?.activeGuide !== newState.activeGuide || - guideState?.activeStep !== newState.activeStep - ) { - if (isFirstRender.current) { - isFirstRender.current = false; - } else { - setIsGuideOpen(true); - } + const subscription = api.fetchActiveGuideState$().subscribe((newGuideState) => { + if (newGuideState) { + setGuideState(newGuideState); } - setGuideState(newState); }); return () => subscription.unsubscribe(); - }, [api, guideState?.activeGuide, guideState?.activeStep]); + }, [api]); + + useEffect(() => { + const subscription = api.isGuidePanelOpen$.subscribe((isGuidePanelOpen) => { + setIsGuideOpen(isGuidePanelOpen); + }); + return () => subscription.unsubscribe(); + }, [api]); const guideConfig = getConfig(guideState); @@ -139,16 +145,17 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { ); } - const currentStep = getCurrentStep(guideConfig.steps, guideState); + const stepNumber = getStepNumber(guideState); + const stepsCompleted = getProgress(guideState); return ( <> - {currentStep + {Boolean(stepNumber) ? i18n.translate('guidedOnboarding.guidedSetupStepButtonLabel', { - defaultMessage: 'Setup guide: Step {currentStep}', + defaultMessage: 'Setup guide: step {stepNumber}', values: { - currentStep, + stepNumber, }, }) : i18n.translate('guidedOnboarding.guidedSetupButtonLabel', { @@ -203,46 +210,61 @@ export const GuidePanel = ({ api, application }: GuidePanelProps) => { )} - - - {/* - TODO: Progress bar should only show after the first step has been started - We need to make changes to the state itself in order to support this - */} - - - + {/* Progress bar should only show after the first step has been complete */} + {stepsCompleted > 0 && ( + <> + + + + + + )} {guideConfig?.steps.map((step, index, steps) => { const accordionId = htmlIdGenerator(`accordion${index}`)(); - const stepStatus = getStepStatus(steps, index, guideState?.activeStep); - - return ( - - ); + const stepState = guideState?.steps[index]; + + if (stepState) { + return ( + + ); + } })} + + {guideState?.status === 'ready_to_complete' && ( + + + + {i18n.translate('guidedOnboarding.dropdownPanel.elasticButtonLabel', { + defaultMessage: 'Continue using Elastic', + })} + + + + )}
diff --git a/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts b/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts index 498059564e6ea..8d34d45b7a53c 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts +++ b/src/plugins/guided_onboarding/public/components/guide_panel_step.styles.ts @@ -8,18 +8,25 @@ import { EuiThemeComputed } from '@elastic/eui'; import { css } from '@emotion/react'; +import { StepStatus } from '../../common/types'; -export const getGuidePanelStepStyles = (euiTheme: EuiThemeComputed) => ({ +export const getGuidePanelStepStyles = (euiTheme: EuiThemeComputed, stepStatus: StepStatus) => ({ stepNumber: css` width: 24px; height: 24px; border-radius: 50%; - border: 2px solid ${euiTheme.colors.success}; + border: 2px solid + ${stepStatus === 'inactive' ? euiTheme.colors.lightShade : euiTheme.colors.success}; font-weight: ${euiTheme.font.weight.medium}; text-align: center; line-height: 1.4; + color: ${stepStatus === 'inactive' ? euiTheme.colors.subduedText : euiTheme.colors.text}; `, stepTitle: css` - font-weight: ${euiTheme.font.weight.bold}; + font-weight: ${euiTheme.font.weight.semiBold}; + color: ${stepStatus === 'inactive' ? euiTheme.colors.subduedText : euiTheme.colors.text}; + .euiAccordion-isOpen & { + color: ${euiTheme.colors.title}; + } `, }); diff --git a/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx b/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx index e6a300b6b6742..c05ad6ec310c7 100644 --- a/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx +++ b/src/plugins/guided_onboarding/public/components/guide_panel_step.tsx @@ -20,7 +20,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { StepStatus, StepConfig } from '../types'; +import type { StepStatus, GuideStepIds } from '../../common/types'; +import type { StepConfig } from '../types'; import { getGuidePanelStepStyles } from './guide_panel_step.styles'; interface GuideStepProps { @@ -28,7 +29,7 @@ interface GuideStepProps { stepStatus: StepStatus; stepConfig: StepConfig; stepNumber: number; - navigateToStep: (step: StepConfig) => void; + navigateToStep: (stepId: GuideStepIds, stepLocation: StepConfig['location']) => void; } export const GuideStep = ({ @@ -39,10 +40,10 @@ export const GuideStep = ({ navigateToStep, }: GuideStepProps) => { const { euiTheme } = useEuiTheme(); - const styles = getGuidePanelStepStyles(euiTheme); + const styles = getGuidePanelStepStyles(euiTheme, stepStatus); - const buttonContent = ( - + const stepTitleContent = ( + {stepStatus === 'complete' ? ( @@ -60,38 +61,49 @@ export const GuideStep = ({ return (
- - <> - + {stepStatus === 'complete' ? ( + <>{stepTitleContent} + ) : ( + + <> + - -
    - {stepConfig.descriptionList.map((description, index) => { - return
  • {description}
  • ; - })} -
-
+ +
    + {stepConfig.descriptionList.map((description, index) => { + return
  • {description}
  • ; + })} +
+
- - {stepStatus === 'in_progress' && ( - - - navigateToStep(stepConfig)} fill> - {/* TODO: Support for conditional "Continue" button label if user revists a step - https://github.com/elastic/kibana/issues/139752 */} - {i18n.translate('guidedOnboarding.dropdownPanel.startStepButtonLabel', { - defaultMessage: 'Start', - })} - - - - )} - -
+ + {(stepStatus === 'in_progress' || stepStatus === 'active') && ( + + + navigateToStep(stepConfig.id, stepConfig.location)} + fill + data-test-subj="activeStepButtonLabel" + > + {stepStatus === 'active' + ? i18n.translate('guidedOnboarding.dropdownPanel.startStepButtonLabel', { + defaultMessage: 'Start', + }) + : i18n.translate('guidedOnboarding.dropdownPanel.continueStepButtonLabel', { + defaultMessage: 'Continue', + })} + + + + )} + +
+ )}
diff --git a/src/plugins/guided_onboarding/public/constants/guides_config.ts b/src/plugins/guided_onboarding/public/constants/guides_config/index.ts similarity index 92% rename from src/plugins/guided_onboarding/public/constants/guides_config.ts rename to src/plugins/guided_onboarding/public/constants/guides_config/index.ts index 0cbee9d4b12b6..9ce81cf9d4698 100644 --- a/src/plugins/guided_onboarding/public/constants/guides_config.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { GuidesConfig } from '../types'; +import type { GuidesConfig } from '../../types'; import { securityConfig } from './security'; import { observabilityConfig } from './observability'; import { searchConfig } from './search'; diff --git a/src/plugins/guided_onboarding/public/constants/observability.ts b/src/plugins/guided_onboarding/public/constants/guides_config/observability.ts similarity index 97% rename from src/plugins/guided_onboarding/public/constants/observability.ts rename to src/plugins/guided_onboarding/public/constants/guides_config/observability.ts index 3f96ad1268173..91b69490131b3 100644 --- a/src/plugins/guided_onboarding/public/constants/observability.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/observability.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { GuideConfig } from '../types'; +import type { GuideConfig } from '../../types'; export const observabilityConfig: GuideConfig = { title: 'Observe my infrastructure', diff --git a/src/plugins/guided_onboarding/public/constants/search.ts b/src/plugins/guided_onboarding/public/constants/guides_config/search.ts similarity index 93% rename from src/plugins/guided_onboarding/public/constants/search.ts rename to src/plugins/guided_onboarding/public/constants/guides_config/search.ts index 1f2a26b5f0b93..57d81fdfe1301 100644 --- a/src/plugins/guided_onboarding/public/constants/search.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/search.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { GuideConfig } from '../types'; +import type { GuideConfig } from '../../types'; export const searchConfig: GuideConfig = { title: 'Search my data', @@ -50,6 +50,10 @@ export const searchConfig: GuideConfig = { 'Nullam ligula enim, malesuada a finibus vel, cursus sed risus.', 'Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', ], + location: { + appID: 'guidedOnboardingExample', + path: 'stepThree', + }, }, ], }; diff --git a/src/plugins/guided_onboarding/public/constants/security.ts b/src/plugins/guided_onboarding/public/constants/guides_config/security.ts similarity index 92% rename from src/plugins/guided_onboarding/public/constants/security.ts rename to src/plugins/guided_onboarding/public/constants/guides_config/security.ts index 2c19e7acc2bed..769d95f978edc 100644 --- a/src/plugins/guided_onboarding/public/constants/security.ts +++ b/src/plugins/guided_onboarding/public/constants/guides_config/security.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import type { GuideConfig } from '../types'; +import type { GuideConfig } from '../../types'; export const securityConfig: GuideConfig = { title: 'Get started with SIEM', @@ -21,6 +21,11 @@ export const securityConfig: GuideConfig = { 'Nullam ligula enim, malesuada a finibus vel, cursus sed risus.', 'Vivamus pretium, elit dictum lacinia aliquet, libero nibh dictum enim, a rhoncus leo magna in sapien.', ], + integration: 'endpoint', + location: { + appID: 'integrations', + path: '/browse/security', + }, }, { id: 'rules', diff --git a/src/plugins/guided_onboarding/public/index.ts b/src/plugins/guided_onboarding/public/index.ts index 5b950b190c375..08ae777bb360f 100755 --- a/src/plugins/guided_onboarding/public/index.ts +++ b/src/plugins/guided_onboarding/public/index.ts @@ -12,9 +12,8 @@ import { GuidedOnboardingPlugin } from './plugin'; export function plugin(ctx: PluginInitializerContext) { return new GuidedOnboardingPlugin(ctx); } -export type { - GuidedOnboardingPluginSetup, - GuidedOnboardingPluginStart, - GuidedOnboardingState, - UseCase, -} from './types'; +export type { GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart } from './types'; + +export type { GuideId, GuideStepIds, GuideState, GuideStep } from '../common/types'; + +export { guidesConfig } from './constants/guides_config'; diff --git a/src/plugins/guided_onboarding/public/mocks.tsx b/src/plugins/guided_onboarding/public/mocks.tsx new file mode 100644 index 0000000000000..dff111fba67c8 --- /dev/null +++ b/src/plugins/guided_onboarding/public/mocks.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { BehaviorSubject } from 'rxjs'; +import { GuidedOnboardingPluginStart } from '.'; + +const apiServiceMock: jest.Mocked = { + guidedOnboardingApi: { + setup: jest.fn(), + fetchActiveGuideState$: () => new BehaviorSubject(undefined), + fetchAllGuidesState: jest.fn(), + updateGuideState: jest.fn(), + activateGuide: jest.fn(), + completeGuide: jest.fn(), + isGuideStepActive$: () => new BehaviorSubject(false), + startGuideStep: jest.fn(), + completeGuideStep: jest.fn(), + isGuidedOnboardingActiveForIntegration$: () => new BehaviorSubject(false), + completeGuidedOnboardingForIntegration: jest.fn(), + }, +}; + +export const guidedOnboardingMock = { + createSetup: () => {}, + createStart: () => apiServiceMock, +}; diff --git a/src/plugins/guided_onboarding/public/plugin.tsx b/src/plugins/guided_onboarding/public/plugin.tsx index 902acaa899e3a..f74e19a03300f 100755 --- a/src/plugins/guided_onboarding/public/plugin.tsx +++ b/src/plugins/guided_onboarding/public/plugin.tsx @@ -20,7 +20,7 @@ import { } from '@kbn/core/public'; import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; -import { +import type { ClientConfigType, GuidedOnboardingPluginSetup, GuidedOnboardingPluginStart, diff --git a/src/plugins/guided_onboarding/public/services/api.mocks.ts b/src/plugins/guided_onboarding/public/services/api.mocks.ts new file mode 100644 index 0000000000000..19dd67c7d7b1b --- /dev/null +++ b/src/plugins/guided_onboarding/public/services/api.mocks.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 { GuideState } from '../../common/types'; + +export const searchAddDataActiveState: GuideState = { + guideId: 'search', + isActive: true, + status: 'in_progress', + steps: [ + { + id: 'add_data', + status: 'active', + }, + { + id: 'browse_docs', + status: 'inactive', + }, + { + id: 'search_experience', + status: 'inactive', + }, + ], +}; + +export const searchAddDataInProgressState: GuideState = { + isActive: true, + status: 'in_progress', + steps: [ + { + id: 'add_data', + status: 'in_progress', + }, + { + id: 'browse_docs', + status: 'inactive', + }, + { + id: 'search_experience', + status: 'inactive', + }, + ], + guideId: 'search', +}; + +export const securityAddDataInProgressState: GuideState = { + guideId: 'security', + status: 'in_progress', + isActive: true, + steps: [ + { + id: 'add_data', + status: 'in_progress', + }, + { + id: 'rules', + status: 'inactive', + }, + ], +}; + +export const securityRulesActivesState: GuideState = { + guideId: 'security', + isActive: true, + status: 'in_progress', + steps: [ + { + id: 'add_data', + status: 'complete', + }, + { + id: 'rules', + status: 'active', + }, + ], +}; + +export const noGuideActiveState: GuideState = { + guideId: 'security', + status: 'in_progress', + isActive: false, + steps: [ + { + id: 'add_data', + status: 'in_progress', + }, + { + id: 'rules', + status: 'inactive', + }, + ], +}; diff --git a/src/plugins/guided_onboarding/public/services/api.test.ts b/src/plugins/guided_onboarding/public/services/api.test.ts index 9f5e20cb9f89d..fad2a01d79891 100644 --- a/src/plugins/guided_onboarding/public/services/api.test.ts +++ b/src/plugins/guided_onboarding/public/services/api.test.ts @@ -10,15 +10,21 @@ import { HttpSetup } from '@kbn/core/public'; import { httpServiceMock } from '@kbn/core/public/mocks'; import { firstValueFrom, Subscription } from 'rxjs'; -import { API_BASE_PATH } from '../../common'; -import { ApiService } from './api'; -import { GuidedOnboardingState } from '..'; +import { API_BASE_PATH } from '../../common/constants'; import { guidesConfig } from '../constants/guides_config'; +import type { GuideState } from '../../common/types'; +import { ApiService } from './api'; +import { + noGuideActiveState, + searchAddDataActiveState, + securityAddDataInProgressState, + securityRulesActivesState, +} from './api.mocks'; const searchGuide = 'search'; const firstStep = guidesConfig[searchGuide].steps[0].id; -const secondStep = guidesConfig[searchGuide].steps[1].id; -const lastStep = guidesConfig[searchGuide].steps[2].id; +const endpointIntegration = 'endpoint'; +const kubernetesIntegration = 'kubernetes'; describe('GuidedOnboarding ApiService', () => { let httpClient: jest.Mocked; @@ -28,7 +34,7 @@ describe('GuidedOnboarding ApiService', () => { beforeEach(() => { httpClient = httpServiceMock.createStartContract({ basePath: '/base/path' }); httpClient.get.mockResolvedValue({ - state: { activeGuide: searchGuide, activeStep: firstStep }, + state: [securityAddDataInProgressState], }); apiService = new ApiService(); apiService.setup(httpClient); @@ -41,40 +47,67 @@ describe('GuidedOnboarding ApiService', () => { jest.restoreAllMocks(); }); - describe('fetchGuideState$', () => { + describe('fetchActiveGuideState$', () => { it('sends a request to the get API', () => { - subscription = apiService.fetchGuideState$().subscribe(); + subscription = apiService.fetchActiveGuideState$().subscribe(); expect(httpClient.get).toHaveBeenCalledTimes(1); - expect(httpClient.get).toHaveBeenCalledWith(`${API_BASE_PATH}/state`); + expect(httpClient.get).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { + query: { active: true }, + }); }); it('broadcasts the updated state', async () => { - await apiService.updateGuideState({ - activeGuide: searchGuide, - activeStep: secondStep, - }); + await apiService.activateGuide(searchGuide); + + const state = await firstValueFrom(apiService.fetchActiveGuideState$()); + expect(state).toEqual(searchAddDataActiveState); + }); + }); - const state = await firstValueFrom(apiService.fetchGuideState$()); - expect(state).toEqual({ activeGuide: searchGuide, activeStep: secondStep }); + describe('fetchAllGuidesState', () => { + it('sends a request to the get API', async () => { + await apiService.fetchAllGuidesState(); + expect(httpClient.get).toHaveBeenCalledTimes(1); + expect(httpClient.get).toHaveBeenCalledWith(`${API_BASE_PATH}/state`); }); }); describe('updateGuideState', () => { it('sends a request to the put API', async () => { - const state = { - activeGuide: searchGuide, - activeStep: secondStep, + const updatedState: GuideState = { + ...searchAddDataActiveState, + steps: [ + { + id: searchAddDataActiveState.steps[0].id, + status: 'in_progress', // update the first step status + }, + searchAddDataActiveState.steps[1], + searchAddDataActiveState.steps[2], + ], }; - await apiService.updateGuideState(state as GuidedOnboardingState); + await apiService.updateGuideState(updatedState, false); expect(httpClient.put).toHaveBeenCalledTimes(1); expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { - body: JSON.stringify(state), + body: JSON.stringify(updatedState), }); }); }); describe('isGuideStepActive$', () => { - it('returns true if the step is active', async (done) => { + it('returns true if the step has been started', async (done) => { + const updatedState: GuideState = { + ...searchAddDataActiveState, + steps: [ + { + id: searchAddDataActiveState.steps[0].id, + status: 'in_progress', + }, + searchAddDataActiveState.steps[1], + searchAddDataActiveState.steps[2], + ], + }; + await apiService.updateGuideState(updatedState, false); + subscription = apiService .isGuideStepActive$(searchGuide, firstStep) .subscribe((isStepActive) => { @@ -84,9 +117,10 @@ describe('GuidedOnboarding ApiService', () => { }); }); - it('returns false if the step is not active', async (done) => { + it('returns false if the step is not been started', async (done) => { + await apiService.updateGuideState(searchAddDataActiveState, false); subscription = apiService - .isGuideStepActive$(searchGuide, secondStep) + .isGuideStepActive$(searchGuide, firstStep) .subscribe((isStepActive) => { if (!isStepActive) { done(); @@ -95,39 +129,268 @@ describe('GuidedOnboarding ApiService', () => { }); }); - describe('completeGuideStep', () => { - it(`completes the step when it's active`, async () => { - await apiService.completeGuideStep(searchGuide, firstStep); + describe('activateGuide', () => { + it('activates a new guide', async () => { + await apiService.activateGuide(searchGuide); + + expect(httpClient.put).toHaveBeenCalledTimes(1); + expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { + body: JSON.stringify({ + isActive: true, + status: 'in_progress', + steps: [ + { + id: 'add_data', + status: 'active', + }, + { + id: 'browse_docs', + status: 'inactive', + }, + { + id: 'search_experience', + status: 'inactive', + }, + ], + guideId: searchGuide, + }), + }); + }); + + it('reactivates a guide that has already been started', async () => { + await apiService.activateGuide(searchGuide, searchAddDataActiveState); + expect(httpClient.put).toHaveBeenCalledTimes(1); - // this assertion depends on the guides config, we are checking for the next step + expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { + body: JSON.stringify(searchAddDataActiveState), + }); + }); + }); + + describe('completeGuide', () => { + const readyToCompleteGuideState: GuideState = { + ...searchAddDataActiveState, + steps: [ + { + id: 'add_data', + status: 'complete', + }, + { + id: 'browse_docs', + status: 'complete', + }, + { + id: 'search_experience', + status: 'complete', + }, + ], + }; + + beforeEach(async () => { + await apiService.updateGuideState(readyToCompleteGuideState, false); + }); + + it('updates the selected guide and marks it as complete', async () => { + await apiService.completeGuide(searchGuide); + + expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { + body: JSON.stringify({ + ...readyToCompleteGuideState, + isActive: false, + status: 'complete', + }), + }); + }); + + it('returns undefined if the selected guide is not active', async () => { + const completedState = await apiService.completeGuide('observability'); // not active + expect(completedState).not.toBeDefined(); + }); + + it('returns undefined if the selected guide has uncompleted steps', async () => { + const incompleteGuideState: GuideState = { + ...searchAddDataActiveState, + steps: [ + { + id: 'add_data', + status: 'complete', + }, + { + id: 'browse_docs', + status: 'complete', + }, + { + id: 'search_experience', + status: 'in_progress', + }, + ], + }; + await apiService.updateGuideState(incompleteGuideState, false); + + const completedState = await apiService.completeGuide(searchGuide); + expect(completedState).not.toBeDefined(); + }); + }); + + describe('startGuideStep', () => { + beforeEach(async () => { + await apiService.updateGuideState(searchAddDataActiveState, false); + }); + + it('updates the selected step and marks it as in_progress', async () => { + await apiService.startGuideStep(searchGuide, firstStep); + expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { body: JSON.stringify({ - activeGuide: searchGuide, - activeStep: secondStep, + ...searchAddDataActiveState, + isActive: true, + status: 'in_progress', + steps: [ + { + id: searchAddDataActiveState.steps[0].id, + status: 'in_progress', + }, + searchAddDataActiveState.steps[1], + searchAddDataActiveState.steps[2], + ], }), }); }); - it(`completes the guide when the last step is active`, async () => { + it('returns undefined if the selected guide is not active', async () => { + const startState = await apiService.startGuideStep('observability', 'add_data'); // not active + expect(startState).not.toBeDefined(); + }); + }); + + describe('completeGuideStep', () => { + it(`completes the step when it's in progress`, async () => { + const updatedState: GuideState = { + ...searchAddDataActiveState, + steps: [ + { + id: searchAddDataActiveState.steps[0].id, + status: 'in_progress', // Mark a step as in_progress in order to test the "completeGuideStep" behavior + }, + searchAddDataActiveState.steps[1], + searchAddDataActiveState.steps[2], + ], + }; + await apiService.updateGuideState(updatedState, false); + + await apiService.completeGuideStep(searchGuide, firstStep); + + // Once on update, once on complete + expect(httpClient.put).toHaveBeenCalledTimes(2); + // Verify the completed step now has a "complete" status, and the subsequent step is "active" + expect(httpClient.put).toHaveBeenLastCalledWith(`${API_BASE_PATH}/state`, { + body: JSON.stringify({ + ...updatedState, + steps: [ + { + id: searchAddDataActiveState.steps[0].id, + status: 'complete', + }, + { + id: searchAddDataActiveState.steps[1].id, + status: 'active', + }, + searchAddDataActiveState.steps[2], + ], + }), + }); + }); + + it('returns undefined if the selected guide is not active', async () => { + const startState = await apiService.completeGuideStep('observability', 'add_data'); // not active + expect(startState).not.toBeDefined(); + }); + + it('does nothing if the step is not in progress', async () => { + await apiService.updateGuideState(searchAddDataActiveState, false); + + await apiService.completeGuideStep(searchGuide, firstStep); + // Expect only 1 call from updateGuideState() + expect(httpClient.put).toHaveBeenCalledTimes(1); + }); + }); + + describe('isGuidedOnboardingActiveForIntegration$', () => { + it('returns true if the integration is part of the active step', async (done) => { httpClient.get.mockResolvedValue({ - // this state depends on the guides config - state: { activeGuide: searchGuide, activeStep: lastStep }, + state: [securityAddDataInProgressState], }); apiService.setup(httpClient); + subscription = apiService + .isGuidedOnboardingActiveForIntegration$(endpointIntegration) + .subscribe((isIntegrationInGuideStep) => { + if (isIntegrationInGuideStep) { + done(); + } + }); + }); + + it('returns false if another integration is part of the active step', async (done) => { + httpClient.get.mockResolvedValue({ + state: [securityAddDataInProgressState], + }); + apiService.setup(httpClient); + subscription = apiService + .isGuidedOnboardingActiveForIntegration$(kubernetesIntegration) + .subscribe((isIntegrationInGuideStep) => { + if (!isIntegrationInGuideStep) { + done(); + } + }); + }); - await apiService.completeGuideStep(searchGuide, lastStep); + it('returns false if no guide is active', async (done) => { + httpClient.get.mockResolvedValue({ + state: [noGuideActiveState], + }); + apiService.setup(httpClient); + subscription = apiService + .isGuidedOnboardingActiveForIntegration$(endpointIntegration) + .subscribe((isIntegrationInGuideStep) => { + if (!isIntegrationInGuideStep) { + done(); + } + }); + }); + }); + + describe('completeGuidedOnboardingForIntegration', () => { + it(`completes the step if it's active for the integration`, async () => { + httpClient.get.mockResolvedValue({ + state: [securityAddDataInProgressState], + }); + apiService.setup(httpClient); + + await apiService.completeGuidedOnboardingForIntegration(endpointIntegration); expect(httpClient.put).toHaveBeenCalledTimes(1); - // this assertion depends on the guides config, we are checking for the last step + // this assertion depends on the guides config expect(httpClient.put).toHaveBeenCalledWith(`${API_BASE_PATH}/state`, { - body: JSON.stringify({ - activeGuide: searchGuide, - activeStep: 'completed', - }), + body: JSON.stringify(securityRulesActivesState), }); }); - it(`does nothing if the step is not active`, async () => { - await apiService.completeGuideStep(searchGuide, secondStep); + it(`does nothing if the step has a different integration`, async () => { + httpClient.get.mockResolvedValue({ + state: [securityAddDataInProgressState], + }); + apiService.setup(httpClient); + + await apiService.completeGuidedOnboardingForIntegration(kubernetesIntegration); + expect(httpClient.put).not.toHaveBeenCalled(); + }); + + it(`does nothing if no guide is active`, async () => { + httpClient.get.mockResolvedValue({ + state: [noGuideActiveState], + }); + apiService.setup(httpClient); + + await apiService.completeGuidedOnboardingForIntegration(endpointIntegration); expect(httpClient.put).not.toHaveBeenCalled(); }); }); diff --git a/src/plugins/guided_onboarding/public/services/api.ts b/src/plugins/guided_onboarding/public/services/api.ts index b99975c3a837a..9ffe13bbbb63f 100644 --- a/src/plugins/guided_onboarding/public/services/api.ts +++ b/src/plugins/guided_onboarding/public/services/api.ts @@ -9,31 +9,48 @@ import { HttpSetup } from '@kbn/core/public'; import { BehaviorSubject, map, from, concatMap, of, Observable, firstValueFrom } from 'rxjs'; -import { API_BASE_PATH } from '../../common'; -import { GuidedOnboardingState, UseCase } from '../types'; -import { getNextStep, isLastStep } from './helpers'; +import { GuidedOnboardingApi } from '../types'; +import { + getGuideConfig, + getInProgressStepId, + isIntegrationInGuideStep, + isLastStep, +} from './helpers'; +import { API_BASE_PATH } from '../../common/constants'; +import type { GuideState, GuideId, GuideStep, GuideStepIds } from '../../common/types'; -export class ApiService { +export class ApiService implements GuidedOnboardingApi { private client: HttpSetup | undefined; - private onboardingGuideState$!: BehaviorSubject; + private onboardingGuideState$!: BehaviorSubject; + public isGuidePanelOpen$: BehaviorSubject = new BehaviorSubject(false); public setup(httpClient: HttpSetup): void { this.client = httpClient; - this.onboardingGuideState$ = new BehaviorSubject(undefined); + this.onboardingGuideState$ = new BehaviorSubject(undefined); } /** - * An Observable with the guided onboarding state. + * An Observable with the active guide state. * Initially the state is fetched from the backend. * Subsequently, the observable is updated automatically, when the state changes. */ - public fetchGuideState$(): Observable { + public fetchActiveGuideState$(): Observable { // TODO add error handling if this.client has not been initialized or request fails return this.onboardingGuideState$.pipe( concatMap((state) => state === undefined - ? from(this.client!.get<{ state: GuidedOnboardingState }>(`${API_BASE_PATH}/state`)).pipe( - map((response) => response.state) + ? from( + this.client!.get<{ state: GuideState[] }>(`${API_BASE_PATH}/state`, { + query: { + active: true, + }, + }) + ).pipe( + map((response) => { + // There should only be 1 active guide + const hasState = response.state.length === 1; + return hasState ? response.state[0] : undefined; + }) ) : of(state) ) @@ -41,25 +58,45 @@ export class ApiService { } /** - * Updates the state of the guided onboarding - * @param {GuidedOnboardingState} newState the new state of the guided onboarding - * @return {Promise} a promise with the updated state or undefined if the update fails + * Async operation to fetch state for all guides + * This is useful for the onboarding landing page, + * where all guides are displayed with their corresponding status + */ + public async fetchAllGuidesState(): Promise<{ state: GuideState[] } | undefined> { + if (!this.client) { + throw new Error('ApiService has not be initialized.'); + } + + try { + return await this.client.get<{ state: GuideState[] }>(`${API_BASE_PATH}/state`); + } catch (error) { + // TODO handle error + // eslint-disable-next-line no-console + console.error(error); + } + } + + /** + * Updates the SO with the updated guide state and refreshes the observables + * This is largely used internally and for tests + * @param {GuideState} guideState the updated guide state + * @param {boolean} panelState boolean to determine whether the dropdown panel should open or not + * @return {Promise} a promise with the updated guide state */ public async updateGuideState( - newState: GuidedOnboardingState - ): Promise<{ state: GuidedOnboardingState } | undefined> { + newState: GuideState, + panelState: boolean + ): Promise<{ state: GuideState } | undefined> { if (!this.client) { throw new Error('ApiService has not be initialized.'); } try { - const response = await this.client.put<{ state: GuidedOnboardingState }>( - `${API_BASE_PATH}/state`, - { - body: JSON.stringify(newState), - } - ); + const response = await this.client.put<{ state: GuideState }>(`${API_BASE_PATH}/state`, { + body: JSON.stringify(newState), + }); this.onboardingGuideState$.next(newState); + this.isGuidePanelOpen$.next(panelState); return response; } catch (error) { // TODO handle error @@ -69,49 +106,238 @@ export class ApiService { } /** - * An observable with the boolean value if the step is active. - * Returns true, if the passed params identify the guide step that is currently active. + * Activates a guide by guideId + * This is useful for the onboarding landing page, when a user selects a guide to start or continue + * @param {GuideId} guideId the id of the guide (one of search, observability, security) + * @param {GuideState} guide (optional) the selected guide state, if it exists (i.e., if a user is continuing a guide) + * @return {Promise} a promise with the updated guide state + */ + public async activateGuide( + guideId: GuideId, + guide?: GuideState + ): Promise<{ state: GuideState } | undefined> { + // If we already have the guide state (i.e., user has already started the guide at some point), + // simply pass it through so they can continue where they left off, and update the guide to active + if (guide) { + return await this.updateGuideState( + { + ...guide, + isActive: true, + }, + true + ); + } + + // If this is the 1st-time attempt, we need to create the default state + const guideConfig = getGuideConfig(guideId); + + if (guideConfig) { + const updatedSteps: GuideStep[] = guideConfig.steps.map((step, stepIndex) => { + const isFirstStep = stepIndex === 0; + return { + id: step.id, + // Only the first step should be activated when activating a new guide + status: isFirstStep ? 'active' : 'inactive', + }; + }); + + const updatedGuide: GuideState = { + isActive: true, + status: 'in_progress', + steps: updatedSteps, + guideId, + }; + + return await this.updateGuideState(updatedGuide, true); + } + } + + /** + * Completes a guide + * Updates the overall guide status to 'complete', and marks it as inactive + * This is useful for the dropdown panel, when the user clicks the "Continue using Elastic" button after completing all steps + * @param {GuideId} guideId the id of the guide (one of search, observability, security) + * @return {Promise} a promise with the updated guide state + */ + public async completeGuide(guideId: GuideId): Promise<{ state: GuideState } | undefined> { + const guideState = await firstValueFrom(this.fetchActiveGuideState$()); + + // For now, returning undefined if consumer attempts to complete a guide that is not active + if (guideState?.guideId !== guideId) { + return undefined; + } + + // All steps should be complete at this point + // However, we do a final check here as a safeguard + const allStepsComplete = + Boolean(guideState.steps.find((step) => step.status !== 'complete')) === false; + + if (allStepsComplete) { + const updatedGuide: GuideState = { + ...guideState, + isActive: false, + status: 'complete', + }; + + return await this.updateGuideState(updatedGuide, false); + } + } + + /** + * An observable with the boolean value if the step is in progress (i.e., user clicked "Start" on a step). + * Returns true, if the passed params identify the guide step that is currently in progress. * Returns false otherwise. - * @param {string} guideID the id of the guide (one of search, observability, security) - * @param {string} stepID the id of the step in the guide + * @param {GuideId} guideId the id of the guide (one of search, observability, security) + * @param {GuideStepIds} stepId the id of the step in the guide * @return {Observable} an observable with the boolean value */ - public isGuideStepActive$(guideID: string, stepID: string): Observable { - return this.fetchGuideState$().pipe( - map((state) => { - return state ? state.activeGuide === guideID && state.activeStep === stepID : false; + public isGuideStepActive$(guideId: GuideId, stepId: GuideStepIds): Observable { + return this.fetchActiveGuideState$().pipe( + map((activeGuideState) => { + // Return false right away if the guide itself is not active + if (activeGuideState?.guideId !== guideId) { + return false; + } + + // If the guide is active, next check the step + const selectedStep = activeGuideState.steps.find((step) => step.id === stepId); + return selectedStep ? selectedStep.status === 'in_progress' : false; }) ); } + /** + * Updates the selected step to 'in_progress' state + * This is useful for the dropdown panel, when the user clicks the "Start" button for the active step + * @param {GuideId} guideId the id of the guide (one of search, observability, security) + * @param {GuideStepIds} stepId the id of the step + * @return {Promise} a promise with the updated guide state + */ + public async startGuideStep( + guideId: GuideId, + stepId: GuideStepIds + ): Promise<{ state: GuideState } | undefined> { + const guideState = await firstValueFrom(this.fetchActiveGuideState$()); + + // For now, returning undefined if consumer attempts to start a step for a guide that isn't active + if (guideState?.guideId !== guideId) { + return undefined; + } + + const updatedSteps: GuideStep[] = guideState.steps.map((step) => { + // Mark the current step as in_progress + if (step.id === stepId) { + return { + id: step.id, + status: 'in_progress', + }; + } + + // All other steps return as-is + return step; + }); + + const currentGuide: GuideState = { + guideId, + isActive: true, + status: 'in_progress', + steps: updatedSteps, + }; + + return await this.updateGuideState(currentGuide, false); + } + /** * Completes the guide step identified by the passed params. * A noop if the passed step is not active. - * Completes the current guide, if the step is the last one in the guide. - * @param {string} guideID the id of the guide (one of search, observability, security) - * @param {string} stepID the id of the step in the guide + * @param {GuideId} guideId the id of the guide (one of search, observability, security) + * @param {GuideStepIds} stepId the id of the step in the guide * @return {Promise} a promise with the updated state or undefined if the operation fails */ public async completeGuideStep( - guideID: string, - stepID: string - ): Promise<{ state: GuidedOnboardingState } | undefined> { - const isStepActive = await firstValueFrom(this.isGuideStepActive$(guideID, stepID)); - if (isStepActive) { - if (isLastStep(guideID, stepID)) { - await this.updateGuideState({ activeGuide: guideID as UseCase, activeStep: 'completed' }); - } else { - const nextStepID = getNextStep(guideID, stepID); - if (nextStepID !== undefined) { - await this.updateGuideState({ - activeGuide: guideID as UseCase, - activeStep: nextStepID, - }); + guideId: GuideId, + stepId: GuideStepIds + ): Promise<{ state: GuideState } | undefined> { + const guideState = await firstValueFrom(this.fetchActiveGuideState$()); + + // For now, returning undefined if consumer attempts to complete a step for a guide that isn't active + if (guideState?.guideId !== guideId) { + return undefined; + } + + const currentStepIndex = guideState.steps.findIndex((step) => step.id === stepId); + const currentStep = guideState.steps[currentStepIndex]; + const isCurrentStepInProgress = currentStep ? currentStep.status === 'in_progress' : false; + + if (isCurrentStepInProgress) { + const updatedSteps: GuideStep[] = guideState.steps.map((step, stepIndex) => { + const isCurrentStep = step.id === currentStep!.id; + const isNextStep = stepIndex === currentStepIndex + 1; + + // Mark the current step as complete + if (isCurrentStep) { + return { + id: step.id, + status: 'complete', + }; } - } + + // Update the next step to active status + if (isNextStep) { + return { + id: step.id, + status: 'active', + }; + } + + // All other steps return as-is + return step; + }); + + const currentGuide: GuideState = { + guideId, + isActive: true, + status: isLastStep(guideId, stepId) ? 'ready_to_complete' : 'in_progress', + steps: updatedSteps, + }; + + return await this.updateGuideState(currentGuide, true); } + return undefined; } + + /** + * An observable with the boolean value if the guided onboarding is currently active for the integration. + * Returns true, if the passed integration is used in the current guide's step. + * Returns false otherwise. + * @param {string} integration the integration (package name) to check for in the guided onboarding config + * @return {Observable} an observable with the boolean value + */ + public isGuidedOnboardingActiveForIntegration$(integration?: string): Observable { + return this.fetchActiveGuideState$().pipe( + map((state) => { + return state ? isIntegrationInGuideStep(state, integration) : false; + }) + ); + } + + public async completeGuidedOnboardingForIntegration( + integration?: string + ): Promise<{ state: GuideState } | undefined> { + if (integration) { + const currentState = await firstValueFrom(this.fetchActiveGuideState$()); + if (currentState) { + const inProgressStepId = getInProgressStepId(currentState); + if (inProgressStepId) { + const isIntegrationStepActive = isIntegrationInGuideStep(currentState, integration); + if (isIntegrationStepActive) { + return await this.completeGuideStep(currentState?.guideId, inProgressStepId); + } + } + } + } + } } export const apiService = new ApiService(); diff --git a/src/plugins/guided_onboarding/public/services/helpers.test.ts b/src/plugins/guided_onboarding/public/services/helpers.test.ts index 6e1a3cc3e0049..586566fe9488b 100644 --- a/src/plugins/guided_onboarding/public/services/helpers.test.ts +++ b/src/plugins/guided_onboarding/public/services/helpers.test.ts @@ -7,12 +7,16 @@ */ import { guidesConfig } from '../constants/guides_config'; -import { getNextStep, isLastStep } from './helpers'; +import { isIntegrationInGuideStep, isLastStep } from './helpers'; +import { + noGuideActiveState, + securityAddDataInProgressState, + securityRulesActivesState, +} from './api.mocks'; const searchGuide = 'search'; const firstStep = guidesConfig[searchGuide].steps[0].id; -const secondStep = guidesConfig[searchGuide].steps[1].id; -const lastStep = guidesConfig[searchGuide].steps[2].id; +const lastStep = guidesConfig[searchGuide].steps[guidesConfig[searchGuide].steps.length - 1].id; describe('GuidedOnboarding ApiService helpers', () => { // this test suite depends on the guides config @@ -28,20 +32,26 @@ describe('GuidedOnboarding ApiService helpers', () => { }); }); - describe('getNextStep', () => { - it('returns id of the next step', () => { - const result = getNextStep(searchGuide, firstStep); - expect(result).toEqual(secondStep); + describe('isIntegrationInGuideStep', () => { + it('return true if the integration is defined in the guide step config', () => { + const result = isIntegrationInGuideStep(securityAddDataInProgressState, 'endpoint'); + expect(result).toBe(true); }); - - it('returns undefined if the params are not part of the config', () => { - const result = getNextStep('some_guide', 'some_step'); - expect(result).toBeUndefined(); + it('returns false if a different integration is defined in the guide step', () => { + const result = isIntegrationInGuideStep(securityAddDataInProgressState, 'kubernetes'); + expect(result).toBe(false); }); - - it(`returns undefined if it's the last step`, () => { - const result = getNextStep(searchGuide, lastStep); - expect(result).toBeUndefined(); + it('returns false if no integration is defined in the guide step', () => { + const result = isIntegrationInGuideStep(securityRulesActivesState, 'endpoint'); + expect(result).toBe(false); + }); + it('returns false if no guide is active', () => { + const result = isIntegrationInGuideStep(noGuideActiveState, 'endpoint'); + expect(result).toBe(false); + }); + it('returns false if no integration passed', () => { + const result = isIntegrationInGuideStep(securityAddDataInProgressState); + expect(result).toBe(false); }); }); }); diff --git a/src/plugins/guided_onboarding/public/services/helpers.ts b/src/plugins/guided_onboarding/public/services/helpers.ts index 3eb0bfca9b751..0e738646c558d 100644 --- a/src/plugins/guided_onboarding/public/services/helpers.ts +++ b/src/plugins/guided_onboarding/public/services/helpers.ts @@ -6,12 +6,13 @@ * Side Public License, v 1. */ +import type { GuideId, GuideState, GuideStepIds } from '../../common/types'; import { guidesConfig } from '../constants/guides_config'; -import { GuideConfig, StepConfig, UseCase } from '../types'; +import { GuideConfig, StepConfig } from '../types'; export const getGuideConfig = (guideID?: string): GuideConfig | undefined => { if (guideID && Object.keys(guidesConfig).includes(guideID)) { - return guidesConfig[guideID as UseCase]; + return guidesConfig[guideID as GuideId]; } }; @@ -33,10 +34,25 @@ export const isLastStep = (guideID: string, stepID: string): boolean => { return false; }; -export const getNextStep = (guideID: string, stepID: string): string | undefined => { - const guide = getGuideConfig(guideID); - const activeStepIndex = getStepIndex(guideID, stepID); - if (activeStepIndex > -1 && guide?.steps[activeStepIndex + 1]) { - return guide?.steps[activeStepIndex + 1].id; +export const getInProgressStepId = (state: GuideState): GuideStepIds | undefined => { + const inProgressStep = state.steps.find((step) => step.status === 'in_progress'); + return inProgressStep ? inProgressStep.id : undefined; +}; + +const getInProgressStepConfig = (state: GuideState): StepConfig | undefined => { + const inProgressStepId = getInProgressStepId(state); + if (inProgressStepId) { + const config = getGuideConfig(state.guideId); + if (config) { + return config.steps.find((step) => step.id === inProgressStepId); + } } }; + +export const isIntegrationInGuideStep = (state: GuideState, integration?: string): boolean => { + if (state.isActive) { + const stepConfig = getInProgressStepConfig(state); + return stepConfig ? stepConfig.integration === integration : false; + } + return false; +}; diff --git a/src/plugins/guided_onboarding/public/types.ts b/src/plugins/guided_onboarding/public/types.ts index 7925fa8ae69d7..dbc300bf0d43d 100755 --- a/src/plugins/guided_onboarding/public/types.ts +++ b/src/plugins/guided_onboarding/public/types.ts @@ -6,25 +6,56 @@ * Side Public License, v 1. */ +import { Observable } from 'rxjs'; import { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public'; -import { ApiService } from './services/api'; +import { HttpSetup } from '@kbn/core/public'; +import { GuideId, GuideState, GuideStepIds, StepStatus } from '../common/types'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface GuidedOnboardingPluginSetup {} export interface GuidedOnboardingPluginStart { - guidedOnboardingApi?: ApiService; + guidedOnboardingApi?: GuidedOnboardingApi; } export interface AppPluginStartDependencies { navigation: NavigationPublicPluginStart; } -export type UseCase = 'observability' | 'security' | 'search'; -export type StepStatus = 'incomplete' | 'complete' | 'in_progress'; +export interface ClientConfigType { + ui: boolean; +} + +export interface GuidedOnboardingApi { + setup: (httpClient: HttpSetup) => void; + fetchActiveGuideState$: () => Observable; + fetchAllGuidesState: () => Promise<{ state: GuideState[] } | undefined>; + updateGuideState: ( + newState: GuideState, + panelState: boolean + ) => Promise<{ state: GuideState } | undefined>; + activateGuide: ( + guideId: GuideId, + guide?: GuideState + ) => Promise<{ state: GuideState } | undefined>; + completeGuide: (guideId: GuideId) => Promise<{ state: GuideState } | undefined>; + isGuideStepActive$: (guideId: GuideId, stepId: GuideStepIds) => Observable; + startGuideStep: ( + guideId: GuideId, + stepId: GuideStepIds + ) => Promise<{ state: GuideState } | undefined>; + completeGuideStep: ( + guideId: GuideId, + stepId: GuideStepIds + ) => Promise<{ state: GuideState } | undefined>; + isGuidedOnboardingActiveForIntegration$: (integration?: string) => Observable; + completeGuidedOnboardingForIntegration: ( + integration?: string + ) => Promise<{ state: GuideState } | undefined>; +} export interface StepConfig { - id: string; + id: GuideStepIds; title: string; descriptionList: string[]; location?: { @@ -32,8 +63,8 @@ export interface StepConfig { path: string; }; status?: StepStatus; + integration?: string; } - export interface GuideConfig { title: string; description: string; @@ -45,14 +76,5 @@ export interface GuideConfig { } export type GuidesConfig = { - [key in UseCase]: GuideConfig; + [key in GuideId]: GuideConfig; }; - -export interface GuidedOnboardingState { - activeGuide: UseCase | 'unset'; - activeStep: string | 'unset' | 'completed'; -} - -export interface ClientConfigType { - ui: boolean; -} diff --git a/src/plugins/guided_onboarding/server/routes/index.ts b/src/plugins/guided_onboarding/server/routes/index.ts index e4e4fcaae5054..cce5aad08b1e5 100755 --- a/src/plugins/guided_onboarding/server/routes/index.ts +++ b/src/plugins/guided_onboarding/server/routes/index.ts @@ -7,92 +7,154 @@ */ import { schema } from '@kbn/config-schema'; -import { IRouter, SavedObjectsClient } from '@kbn/core/server'; -import { - guidedSetupDefaultState, - guidedSetupSavedObjectsId, - guidedSetupSavedObjectsType, -} from '../saved_objects'; - -const doesGuidedSetupExist = async (savedObjectsClient: SavedObjectsClient): Promise => { - return savedObjectsClient - .find({ type: guidedSetupSavedObjectsType }) - .then((foundSavedObjects) => foundSavedObjects.total > 0); +import type { IRouter, SavedObjectsClient } from '@kbn/core/server'; +import type { GuideState } from '../../common/types'; +import { guidedSetupSavedObjectsType } from '../saved_objects'; + +const findGuideById = async (savedObjectsClient: SavedObjectsClient, guideId: string) => { + return savedObjectsClient.find({ + type: guidedSetupSavedObjectsType, + search: `"${guideId}"`, + searchFields: ['guideId'], + }); +}; + +const findActiveGuide = async (savedObjectsClient: SavedObjectsClient) => { + return savedObjectsClient.find({ + type: guidedSetupSavedObjectsType, + search: 'true', + searchFields: ['isActive'], + }); +}; + +const findAllGuides = async (savedObjectsClient: SavedObjectsClient) => { + return savedObjectsClient.find({ type: guidedSetupSavedObjectsType }); }; export function defineRoutes(router: IRouter) { + // Fetch all guides state; optionally pass the query param ?active=true to only return the active guide router.get( { path: '/api/guided_onboarding/state', - validate: false, + validate: { + query: schema.object({ + active: schema.maybe(schema.boolean()), + }), + }, }, async (context, request, response) => { const coreContext = await context.core; const soClient = coreContext.savedObjects.client as SavedObjectsClient; - const stateExists = await doesGuidedSetupExist(soClient); - if (stateExists) { - const guidedSetupSO = await soClient.get( - guidedSetupSavedObjectsType, - guidedSetupSavedObjectsId - ); + const existingGuides = + request.query.active === true + ? await findActiveGuide(soClient) + : await findAllGuides(soClient); + + if (existingGuides.total > 0) { + const guidesState = existingGuides.saved_objects.map((guide) => guide.attributes); return response.ok({ - body: { state: guidedSetupSO.attributes }, + body: { state: guidesState }, }); } else { + // If no SO exists, we assume state hasn't been stored yet and return an empty array return response.ok({ - body: { state: guidedSetupDefaultState }, + body: { state: [] }, }); } } ); + // Update the guide state for the passed guideId; + // will also check any existing active guides and update them to an "inactive" state router.put( { path: '/api/guided_onboarding/state', validate: { body: schema.object({ - activeGuide: schema.maybe(schema.string()), - activeStep: schema.maybe(schema.string()), + status: schema.string(), + guideId: schema.string(), + isActive: schema.boolean(), + steps: schema.arrayOf( + schema.object({ + status: schema.string(), + id: schema.string(), + }) + ), }), }, }, async (context, request, response) => { - const activeGuide = request.body.activeGuide; - const activeStep = request.body.activeStep; - const attributes = { - activeGuide: activeGuide ?? 'unset', - activeStep: activeStep ?? 'unset', - }; + const updatedGuideState = request.body; + const coreContext = await context.core; - const soClient = coreContext.savedObjects.client as SavedObjectsClient; + const savedObjectsClient = coreContext.savedObjects.client as SavedObjectsClient; - const stateExists = await doesGuidedSetupExist(soClient); + const selectedGuideSO = await findGuideById(savedObjectsClient, updatedGuideState.guideId); + + // If the SO already exists, update it, else create a new SO + if (selectedGuideSO.total > 0) { + const updatedGuides = []; + const selectedGuide = selectedGuideSO.saved_objects[0]; + + updatedGuides.push({ + type: guidedSetupSavedObjectsType, + id: selectedGuide.id, + attributes: { + ...updatedGuideState, + }, + }); + + // If we are activating a new guide, we need to check if there is a different, existing active guide + // If yes, we need to mark it as inactive (only 1 guide can be active at a time) + if (updatedGuideState.isActive) { + const activeGuideSO = await findActiveGuide(savedObjectsClient); + + if (activeGuideSO.total > 0) { + const activeGuide = activeGuideSO.saved_objects[0]; + if (activeGuide.attributes.guideId !== updatedGuideState.guideId) { + updatedGuides.push({ + type: guidedSetupSavedObjectsType, + id: activeGuide.id, + attributes: { + ...activeGuide.attributes, + isActive: false, + }, + }); + } + } + } + + const updatedGuidesResponse = await savedObjectsClient.bulkUpdate(updatedGuides); - if (stateExists) { - const updatedGuidedSetupSO = await soClient.update( - guidedSetupSavedObjectsType, - guidedSetupSavedObjectsId, - attributes - ); return response.ok({ - body: { state: updatedGuidedSetupSO.attributes }, + body: { + state: updatedGuidesResponse, + }, }); } else { - const guidedSetupSO = await soClient.create( - guidedSetupSavedObjectsType, - { - ...guidedSetupDefaultState, - ...attributes, - }, - { - id: guidedSetupSavedObjectsId, + // If we are activating a new guide, we need to check if there is an existing active guide + // If yes, we need to mark it as inactive (only 1 guide can be active at a time) + if (updatedGuideState.isActive) { + const activeGuideSO = await findActiveGuide(savedObjectsClient); + + if (activeGuideSO.total > 0) { + const activeGuide = activeGuideSO.saved_objects[0]; + await savedObjectsClient.update(guidedSetupSavedObjectsType, activeGuide.id, { + ...activeGuide.attributes, + isActive: false, + }); } + } + + const createdGuideResponse = await savedObjectsClient.create( + guidedSetupSavedObjectsType, + updatedGuideState ); return response.ok({ body: { - state: guidedSetupSO.attributes, + state: createdGuideResponse, }, }); } diff --git a/src/plugins/guided_onboarding/server/saved_objects/guided_setup.ts b/src/plugins/guided_onboarding/server/saved_objects/guided_setup.ts index 2576148868597..6fe0a90339f69 100644 --- a/src/plugins/guided_onboarding/server/saved_objects/guided_setup.ts +++ b/src/plugins/guided_onboarding/server/saved_objects/guided_setup.ts @@ -8,12 +8,8 @@ import { SavedObjectsType } from '@kbn/core/server'; -export const guidedSetupSavedObjectsType = 'guided-setup-state'; -export const guidedSetupSavedObjectsId = 'guided-setup-state-id'; -export const guidedSetupDefaultState = { - activeGuide: 'unset', - activeStep: 'unset', -}; +export const guidedSetupSavedObjectsType = 'guided-onboarding-guide-state'; + export const guidedSetupSavedObjects: SavedObjectsType = { name: guidedSetupSavedObjectsType, hidden: false, @@ -22,11 +18,11 @@ export const guidedSetupSavedObjects: SavedObjectsType = { mappings: { dynamic: false, properties: { - activeGuide: { + guideId: { type: 'keyword', }, - activeStep: { - type: 'keyword', + isActive: { + type: 'boolean', }, }, }, diff --git a/src/plugins/guided_onboarding/server/saved_objects/index.ts b/src/plugins/guided_onboarding/server/saved_objects/index.ts index 2fa5366cc2b9e..58195618a0ec4 100644 --- a/src/plugins/guided_onboarding/server/saved_objects/index.ts +++ b/src/plugins/guided_onboarding/server/saved_objects/index.ts @@ -6,9 +6,4 @@ * Side Public License, v 1. */ -export { - guidedSetupSavedObjects, - guidedSetupSavedObjectsType, - guidedSetupSavedObjectsId, - guidedSetupDefaultState, -} from './guided_setup'; +export { guidedSetupSavedObjects, guidedSetupSavedObjectsType } from './guided_setup'; diff --git a/src/plugins/home/kibana.json b/src/plugins/home/kibana.json index 02b33e814e2a1..72b4d6cb8fd0b 100644 --- a/src/plugins/home/kibana.json +++ b/src/plugins/home/kibana.json @@ -8,6 +8,6 @@ "server": true, "ui": true, "requiredPlugins": ["dataViews", "share", "urlForwarding"], - "optionalPlugins": ["usageCollection", "customIntegrations"], + "optionalPlugins": ["usageCollection", "customIntegrations", "cloud"], "requiredBundles": ["kibanaReact"] } diff --git a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp index f6720bf0e3e51..a48a4a05318bb 100644 Binary files a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp and b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard.webp differ diff --git a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp index b9263441d1f22..cccee38594e9c 100644 Binary files a/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp and b/src/plugins/home/public/assets/sample_data_resources/ecommerce/dashboard_dark.webp differ diff --git a/src/plugins/home/public/assets/sample_data_resources/flights/dashboard.webp b/src/plugins/home/public/assets/sample_data_resources/flights/dashboard.webp index f73ae849befc9..2c50c8a1471e9 100644 Binary files a/src/plugins/home/public/assets/sample_data_resources/flights/dashboard.webp and b/src/plugins/home/public/assets/sample_data_resources/flights/dashboard.webp differ diff --git a/src/plugins/home/public/assets/sample_data_resources/flights/dashboard_dark.webp b/src/plugins/home/public/assets/sample_data_resources/flights/dashboard_dark.webp index 3cea45093ddac..0c3769a3c8268 100644 Binary files a/src/plugins/home/public/assets/sample_data_resources/flights/dashboard_dark.webp and b/src/plugins/home/public/assets/sample_data_resources/flights/dashboard_dark.webp differ diff --git a/src/plugins/home/public/assets/sample_data_resources/logs/dashboard.webp b/src/plugins/home/public/assets/sample_data_resources/logs/dashboard.webp index c5b2250190ae0..8defebcc5fbbb 100644 Binary files a/src/plugins/home/public/assets/sample_data_resources/logs/dashboard.webp and b/src/plugins/home/public/assets/sample_data_resources/logs/dashboard.webp differ diff --git a/src/plugins/home/public/assets/sample_data_resources/logs/dashboard_dark.webp b/src/plugins/home/public/assets/sample_data_resources/logs/dashboard_dark.webp index 0c5ff2f6cd9f1..6f4dad0dad1f9 100644 Binary files a/src/plugins/home/public/assets/sample_data_resources/logs/dashboard_dark.webp and b/src/plugins/home/public/assets/sample_data_resources/logs/dashboard_dark.webp differ diff --git a/src/plugins/home/public/plugin.test.ts b/src/plugins/home/public/plugin.test.ts index 12243944ef0f0..a6c6012a28ed6 100644 --- a/src/plugins/home/public/plugin.test.ts +++ b/src/plugins/home/public/plugin.test.ts @@ -11,6 +11,7 @@ import { HomePublicPlugin } from './plugin'; import { coreMock } from '@kbn/core/public/mocks'; import { urlForwardingPluginMock } from '@kbn/url-forwarding-plugin/public/mocks'; import { SharePluginSetup } from '@kbn/share-plugin/public'; +import { cloudMock } from '@kbn/cloud-plugin/public/mocks'; const mockInitializerContext = coreMock.createPluginInitializerContext(); const mockShare = {} as SharePluginSetup; @@ -24,14 +25,11 @@ describe('HomePublicPlugin', () => { }); describe('setup', () => { - test('registers tutorial directory to feature catalogue', async () => { - const setup = await new HomePublicPlugin(mockInitializerContext).setup( - coreMock.createSetup() as any, - { - share: mockShare, - urlForwarding: urlForwardingPluginMock.createSetupContract(), - } - ); + test('registers tutorial directory to feature catalogue', () => { + const setup = new HomePublicPlugin(mockInitializerContext).setup(coreMock.createSetup(), { + share: mockShare, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); expect(setup).toHaveProperty('featureCatalogue'); expect(setup.featureCatalogue.register).toHaveBeenCalledTimes(1); expect(setup.featureCatalogue.register).toHaveBeenCalledWith( @@ -44,53 +42,73 @@ describe('HomePublicPlugin', () => { ); }); - test('wires up and returns registry', async () => { - const setup = await new HomePublicPlugin(mockInitializerContext).setup( - coreMock.createSetup() as any, - { - share: mockShare, - urlForwarding: urlForwardingPluginMock.createSetupContract(), - } - ); + test('wires up and returns registry', () => { + const setup = new HomePublicPlugin(mockInitializerContext).setup(coreMock.createSetup(), { + share: mockShare, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); expect(setup).toHaveProperty('featureCatalogue'); expect(setup.featureCatalogue).toHaveProperty('register'); }); - test('wires up and returns environment service', async () => { - const setup = await new HomePublicPlugin(mockInitializerContext).setup( - coreMock.createSetup() as any, - { - share: {} as SharePluginSetup, - urlForwarding: urlForwardingPluginMock.createSetupContract(), - } - ); + test('wires up and returns environment service', () => { + const setup = new HomePublicPlugin(mockInitializerContext).setup(coreMock.createSetup(), { + share: {} as SharePluginSetup, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); expect(setup).toHaveProperty('environment'); expect(setup.environment).toHaveProperty('update'); }); - test('wires up and returns tutorial service', async () => { - const setup = await new HomePublicPlugin(mockInitializerContext).setup( - coreMock.createSetup() as any, - { - share: mockShare, - urlForwarding: urlForwardingPluginMock.createSetupContract(), - } - ); + test('wires up and returns tutorial service', () => { + const setup = new HomePublicPlugin(mockInitializerContext).setup(coreMock.createSetup(), { + share: mockShare, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); expect(setup).toHaveProperty('tutorials'); expect(setup.tutorials).toHaveProperty('setVariable'); }); - test('wires up and returns welcome service', async () => { - const setup = await new HomePublicPlugin(mockInitializerContext).setup( - coreMock.createSetup() as any, - { - share: mockShare, - urlForwarding: urlForwardingPluginMock.createSetupContract(), - } - ); + test('wires up and returns welcome service', () => { + const setup = new HomePublicPlugin(mockInitializerContext).setup(coreMock.createSetup(), { + share: mockShare, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); expect(setup).toHaveProperty('welcomeScreen'); expect(setup.welcomeScreen).toHaveProperty('registerOnRendered'); expect(setup.welcomeScreen).toHaveProperty('registerTelemetryNoticeRenderer'); }); + + test('sets the cloud environment variable when the cloud plugin is present but isCloudEnabled: false', () => { + const cloud = { ...cloudMock.createSetup(), isCloudEnabled: false }; + const plugin = new HomePublicPlugin(mockInitializerContext); + const setup = plugin.setup(coreMock.createSetup(), { + cloud, + share: mockShare, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); + expect(setup.environment.update).toHaveBeenCalledTimes(1); + expect(setup.environment.update).toHaveBeenCalledWith({ cloud: false }); + expect(setup.tutorials.setVariable).toHaveBeenCalledTimes(0); + }); + + test('when cloud is enabled, it sets the cloud environment and the tutorials variable "cloud"', () => { + const cloud = { ...cloudMock.createSetup(), isCloudEnabled: true }; + const plugin = new HomePublicPlugin(mockInitializerContext); + const setup = plugin.setup(coreMock.createSetup(), { + cloud, + share: mockShare, + urlForwarding: urlForwardingPluginMock.createSetupContract(), + }); + expect(setup.environment.update).toHaveBeenCalledTimes(1); + expect(setup.environment.update).toHaveBeenCalledWith({ cloud: true }); + expect(setup.tutorials.setVariable).toHaveBeenCalledTimes(1); + expect(setup.tutorials.setVariable).toHaveBeenCalledWith('cloud', { + id: 'mock-cloud-id', + baseUrl: 'base-url', + deploymentUrl: 'deployment-url', + profileUrl: 'profile-url', + }); + }); }); }); diff --git a/src/plugins/home/public/plugin.ts b/src/plugins/home/public/plugin.ts index 642a8d575e078..e27ddf107a5ee 100644 --- a/src/plugins/home/public/plugin.ts +++ b/src/plugins/home/public/plugin.ts @@ -20,6 +20,7 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { UrlForwardingSetup, UrlForwardingStart } from '@kbn/url-forwarding-plugin/public'; import { AppNavLinkStatus } from '@kbn/core/public'; import { SharePluginSetup } from '@kbn/share-plugin/public'; +import type { CloudSetup } from '@kbn/cloud-plugin/public'; import { PLUGIN_ID, HOME_APP_BASE_PATH } from '../common/constants'; import { setServices } from './application/kibana_services'; import { ConfigSchema } from '../config'; @@ -42,6 +43,7 @@ export interface HomePluginStartDependencies { } export interface HomePluginSetupDependencies { + cloud?: CloudSetup; share: SharePluginSetup; usageCollection?: UsageCollectionSetup; urlForwarding: UrlForwardingSetup; @@ -66,7 +68,7 @@ export class HomePublicPlugin public setup( core: CoreSetup, - { share, urlForwarding, usageCollection }: HomePluginSetupDependencies + { cloud, share, urlForwarding, usageCollection }: HomePluginSetupDependencies ): HomePublicPluginSetup { core.application.register({ id: PLUGIN_ID, @@ -127,10 +129,25 @@ export class HomePublicPlugin order: 500, }); + const environment = { ...this.environmentService.setup() }; + const tutorials = { ...this.tutorialService.setup() }; + if (cloud) { + environment.update({ cloud: cloud.isCloudEnabled }); + if (cloud.isCloudEnabled) { + tutorials.setVariable('cloud', { + id: cloud.cloudId, + baseUrl: cloud.baseUrl, + // Cloud's API already provides the full URLs + profileUrl: cloud.profileUrl?.replace(cloud.baseUrl ?? '', ''), + deploymentUrl: cloud.deploymentUrl?.replace(cloud.baseUrl ?? '', ''), + }); + } + } + return { featureCatalogue, - environment: { ...this.environmentService.setup() }, - tutorials: { ...this.tutorialService.setup() }, + environment, + tutorials, addData: { ...this.addDataService.setup() }, welcomeScreen: { ...this.welcomeService.setup() }, }; diff --git a/src/plugins/home/public/services/environment/environment.mock.ts b/src/plugins/home/public/services/environment/environment.mock.ts index 713a59ceac7bf..f2d4747d44d6a 100644 --- a/src/plugins/home/public/services/environment/environment.mock.ts +++ b/src/plugins/home/public/services/environment/environment.mock.ts @@ -18,14 +18,13 @@ const createSetupMock = (): jest.Mocked => { const createMock = (): jest.Mocked> => { const service = { - setup: jest.fn(), + setup: jest.fn(createSetupMock), getEnvironment: jest.fn(() => ({ cloud: false, apmUi: false, ml: false, })), }; - service.setup.mockImplementation(createSetupMock); return service; }; diff --git a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts index ad334470205aa..d90d6855879bb 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/ecommerce/saved_objects.ts @@ -189,44 +189,6 @@ export const getSavedObjects = (): SavedObject[] => [ updated_at: '2021-08-05T12:43:35.817Z', version: 'WzE3MSwxXQ==', }, - { - attributes: { - description: '', - kibanaSavedObjectMeta: { - searchSourceJSON: '{"query":{"query":"","language":"kuery"},"filter":[]}', - }, - title: '[eCommerce] Controls', - uiStateJSON: '{}', - version: 1, - visState: - '{"title":"[eCommerce] Controls","type":"input_control_vis","params":{"controls":[{"id":"1536977437774","fieldName":"manufacturer.keyword","parent":"","label":"Manufacturer","type":"list","options":{"type":"terms","multiselect":true,"dynamicOptions":true,"size":5,"order":"desc"},"indexPatternRefName":"control_0_index_pattern"},{"id":"1536977465554","fieldName":"category.keyword","parent":"","label":"Category","type":"list","options":{"type":"terms","multiselect":true,"dynamicOptions":true,"size":5,"order":"desc"},"indexPatternRefName":"control_1_index_pattern"},{"id":"1536977596163","fieldName":"total_quantity","parent":"","label":"Quantity","type":"range","options":{"decimalPlaces":0,"step":1},"indexPatternRefName":"control_2_index_pattern"}],"updateFiltersOnChange":false,"useTimeFilter":true,"pinFilters":false},"aggs":[]}', - }, - coreMigrationVersion: '8.0.0', - id: 'c3378480-f5ea-11eb-a78e-83aac3c38a60', - migrationVersion: { - visualization: '7.14.0', - }, - references: [ - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'control_0_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'control_1_index_pattern', - type: 'index-pattern', - }, - { - id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - name: 'control_2_index_pattern', - type: 'index-pattern', - }, - ], - type: 'visualization', - updated_at: '2021-08-05T12:43:41.128Z', - version: 'WzE3NiwxXQ==', - }, { attributes: { state: { @@ -1285,113 +1247,132 @@ export const getSavedObjects = (): SavedObject[] => [ version: 'WzIzMywxXQ==', }, { + id: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', + type: 'dashboard', + namespaces: ['default'], + updated_at: '2022-09-26T17:19:19.470Z', + version: 'WzQ1MTgsMV0=', attributes: { + title: i18n.translate('home.sampleData.ecommerceSpec.revenueDashboardTitle', { + defaultMessage: '[eCommerce] Revenue Dashboard', + }), + hits: 0, description: i18n.translate('home.sampleData.ecommerceSpec.revenueDashboardDescription', { defaultMessage: 'Analyze mock eCommerce orders and revenue', }), - hits: 0, - kibanaSavedObjectMeta: { - searchSourceJSON: '{"query":{"language":"kuery","query":""},"filter":[]}', - }, - optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', panelsJSON: - '[{"version":"8.0.0-SNAPSHOT","type":"visualization","gridData":{"x":0,"y":22,"w":24,"h":10,"i":"5"},"panelIndex":"5","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_5"},{"version":"8.0.0-SNAPSHOT","type":"visualization","gridData":{"x":36,"y":15,"w":12,"h":7,"i":"7"},"panelIndex":"7","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_7"},{"version":"8.0.0-SNAPSHOT","type":"search","gridData":{"x":0,"y":55,"w":48,"h":18,"i":"10"},"panelIndex":"10","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_10"},{"version":"8.0.0-SNAPSHOT","type":"map","gridData":{"x":0,"y":32,"w":24,"h":14,"i":"11"},"panelIndex":"11","embeddableConfig":{"isLayerTOCOpen":false,"enhancements":{},"mapCenter":{"lat":45.88578,"lon":-15.07605,"zoom":2.11},"mapBuffer":{"minLon":-135,"minLat":0,"maxLon":90,"maxLat":66.51326},"openTOCDetails":[],"hiddenLayers":[]},"panelRefName":"panel_11"},{"version":"8.0.0-SNAPSHOT","type":"visualization","gridData":{"x":0,"y":0,"w":18,"h":7,"i":"a71cf076-6895-491c-8878-63592e429ed5"},"panelIndex":"a71cf076-6895-491c-8878-63592e429ed5","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_a71cf076-6895-491c-8878-63592e429ed5"},{"version":"8.0.0-SNAPSHOT","type":"visualization","gridData":{"x":18,"y":0,"w":30,"h":7,"i":"adc0a2f4-481c-45eb-b422-0ea59a3e5163"},"panelIndex":"adc0a2f4-481c-45eb-b422-0ea59a3e5163","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_adc0a2f4-481c-45eb-b422-0ea59a3e5163"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":0,"y":7,"w":24,"h":8,"i":"7077b79f-2a99-4fcb-bbd4-456982843278"},"panelIndex":"7077b79f-2a99-4fcb-bbd4-456982843278","embeddableConfig":{"enhancements":{},"hidePanelTitles":false},"title":"% of target revenue ($10k)","panelRefName":"panel_7077b79f-2a99-4fcb-bbd4-456982843278"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":24,"y":7,"w":12,"h":8,"i":"19a3c101-ad2e-4421-a71b-a4734ec1f03e"},"panelIndex":"19a3c101-ad2e-4421-a71b-a4734ec1f03e","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_19a3c101-ad2e-4421-a71b-a4734ec1f03e"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":36,"y":7,"w":12,"h":8,"i":"491469e7-7d24-4216-aeb3-bca00e5c8c1b"},"panelIndex":"491469e7-7d24-4216-aeb3-bca00e5c8c1b","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_491469e7-7d24-4216-aeb3-bca00e5c8c1b"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":0,"y":15,"w":24,"h":7,"i":"a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef"},"panelIndex":"a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":24,"y":15,"w":12,"h":7,"i":"da51079b-952f-43dc-96e6-6f9415a3708b"},"panelIndex":"da51079b-952f-43dc-96e6-6f9415a3708b","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_da51079b-952f-43dc-96e6-6f9415a3708b"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":24,"y":22,"w":24,"h":10,"i":"64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b"},"panelIndex":"64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":24,"y":32,"w":24,"h":14,"i":"bd330ede-2eef-4e2a-8100-22a21abf5038"},"panelIndex":"bd330ede-2eef-4e2a-8100-22a21abf5038","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_bd330ede-2eef-4e2a-8100-22a21abf5038"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":0,"y":46,"w":24,"h":9,"i":"b897d4be-cf83-46fb-a111-c7fbec9ef403"},"panelIndex":"b897d4be-cf83-46fb-a111-c7fbec9ef403","embeddableConfig":{"hidePanelTitles":false,"enhancements":{}},"title":"Top products this week","panelRefName":"panel_b897d4be-cf83-46fb-a111-c7fbec9ef403"},{"version":"8.0.0-SNAPSHOT","type":"lens","gridData":{"x":24,"y":46,"w":24,"h":9,"i":"e0f68f93-30f2-4da7-889a-6cd128a68d3f"},"panelIndex":"e0f68f93-30f2-4da7-889a-6cd128a68d3f","embeddableConfig":{"timeRange":{"from":"now-2w","to":"now-1w"},"hidePanelTitles":false,"enhancements":{}},"title":"Top products last week","panelRefName":"panel_e0f68f93-30f2-4da7-889a-6cd128a68d3f"}]', + '[{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":21,"w":24,"h":10,"i":"5"},"panelIndex":"5","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_5"},{"version":"8.6.0","type":"visualization","gridData":{"x":36,"y":7,"w":12,"h":7,"i":"7"},"panelIndex":"7","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_7"},{"version":"8.6.0","type":"search","gridData":{"x":0,"y":54,"w":48,"h":18,"i":"10"},"panelIndex":"10","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_10"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":31,"w":24,"h":14,"i":"11"},"panelIndex":"11","embeddableConfig":{"isLayerTOCOpen":false,"enhancements":{},"mapCenter":{"lat":45.88578,"lon":-15.07605,"zoom":2.11},"mapBuffer":{"minLon":-135,"minLat":0,"maxLon":90,"maxLat":66.51326},"openTOCDetails":[],"hiddenLayers":[]},"panelRefName":"panel_11"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":0,"w":24,"h":7,"i":"a71cf076-6895-491c-8878-63592e429ed5"},"panelIndex":"a71cf076-6895-491c-8878-63592e429ed5","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_a71cf076-6895-491c-8878-63592e429ed5"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":7,"w":12,"h":7,"i":"da51079b-952f-43dc-96e6-6f9415a3708b"},"panelIndex":"da51079b-952f-43dc-96e6-6f9415a3708b","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_da51079b-952f-43dc-96e6-6f9415a3708b"},{"version":"8.6.0","type":"lens","gridData":{"x":36,"y":0,"w":12,"h":7,"i":"491469e7-7d24-4216-aeb3-bca00e5c8c1b"},"panelIndex":"491469e7-7d24-4216-aeb3-bca00e5c8c1b","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_491469e7-7d24-4216-aeb3-bca00e5c8c1b"},{"version":"8.6.0","type":"lens","gridData":{"x":0,"y":7,"w":24,"h":7,"i":"7077b79f-2a99-4fcb-bbd4-456982843278"},"panelIndex":"7077b79f-2a99-4fcb-bbd4-456982843278","embeddableConfig":{"enhancements":{},"hidePanelTitles":false},"title":"% of target revenue ($10k)","panelRefName":"panel_7077b79f-2a99-4fcb-bbd4-456982843278"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":0,"w":12,"h":7,"i":"19a3c101-ad2e-4421-a71b-a4734ec1f03e"},"panelIndex":"19a3c101-ad2e-4421-a71b-a4734ec1f03e","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_19a3c101-ad2e-4421-a71b-a4734ec1f03e"},{"version":"8.6.0","type":"lens","gridData":{"x":0,"y":14,"w":24,"h":7,"i":"a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef"},"panelIndex":"a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":14,"w":24,"h":17,"i":"64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b"},"panelIndex":"64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":31,"w":24,"h":14,"i":"bd330ede-2eef-4e2a-8100-22a21abf5038"},"panelIndex":"bd330ede-2eef-4e2a-8100-22a21abf5038","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_bd330ede-2eef-4e2a-8100-22a21abf5038"},{"version":"8.6.0","type":"lens","gridData":{"x":0,"y":45,"w":24,"h":9,"i":"b897d4be-cf83-46fb-a111-c7fbec9ef403"},"panelIndex":"b897d4be-cf83-46fb-a111-c7fbec9ef403","embeddableConfig":{"hidePanelTitles":false,"enhancements":{}},"title":"Top products this week","panelRefName":"panel_b897d4be-cf83-46fb-a111-c7fbec9ef403"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":45,"w":24,"h":9,"i":"e0f68f93-30f2-4da7-889a-6cd128a68d3f"},"panelIndex":"e0f68f93-30f2-4da7-889a-6cd128a68d3f","embeddableConfig":{"timeRange":{"from":"now-2w","to":"now-1w"},"hidePanelTitles":false,"enhancements":{}},"title":"Top products last week","panelRefName":"panel_e0f68f93-30f2-4da7-889a-6cd128a68d3f"}]', + optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', + version: 1, + timeRestore: true, + timeTo: 'now', + timeFrom: 'now-7d', refreshInterval: { pause: true, value: 0, }, - timeFrom: 'now-7d', - timeRestore: true, - timeTo: 'now', - title: i18n.translate('home.sampleData.ecommerceSpec.revenueDashboardTitle', { - defaultMessage: '[eCommerce] Revenue Dashboard', - }), - version: 1, - }, - coreMigrationVersion: '8.0.0', - id: '722b74f0-b882-11e8-a6d9-e546fe2bba5f', - migrationVersion: { - dashboard: '7.14.0', + controlGroupInput: { + controlStyle: 'oneLine', + chainingSystem: 'HIERARCHICAL', + panelsJSON: + '{"1ee1617f-fd8e-45e4-bc6a-d5736710ea20":{"order":0,"width":"small","grow":true,"type":"optionsListControl","explicitInput":{"title":"Manufacturer","fieldName":"manufacturer.keyword","parentFieldName":"manufacturer","id":"1ee1617f-fd8e-45e4-bc6a-d5736710ea20","enhancements":{}}},"afa9fa0f-a002-41a5-bab9-b738316d2590":{"order":1,"width":"small","grow":true,"type":"optionsListControl","explicitInput":{"title":"Category","fieldName":"category.keyword","parentFieldName":"category","id":"afa9fa0f-a002-41a5-bab9-b738316d2590","enhancements":{}}},"d3f766cb-5f96-4a12-8d3c-034e08be8855":{"order":2,"width":"small","grow":true,"type":"rangeSliderControl","explicitInput":{"title":"Quantity","fieldName":"total_quantity","id":"d3f766cb-5f96-4a12-8d3c-034e08be8855","enhancements":{}}}}', + ignoreParentSettingsJSON: + '{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', + }, + kibanaSavedObjectMeta: { + searchSourceJSON: '{"query":{"language":"kuery","query":""},"filter":[]}', + }, }, references: [ { - id: '45e07720-b890-11e8-a6d9-e546fe2bba5f', name: '5:panel_5', type: 'visualization', + id: '45e07720-b890-11e8-a6d9-e546fe2bba5f', }, { - id: 'b80e6540-b891-11e8-a6d9-e546fe2bba5f', name: '7:panel_7', type: 'visualization', + id: 'b80e6540-b891-11e8-a6d9-e546fe2bba5f', }, { - id: '3ba638e0-b894-11e8-a6d9-e546fe2bba5f', name: '10:panel_10', type: 'search', + id: '3ba638e0-b894-11e8-a6d9-e546fe2bba5f', }, { - id: '9c6f83f0-bb4d-11e8-9c84-77068524bcab', name: '11:panel_11', type: 'visualization', + id: '9c6f83f0-bb4d-11e8-9c84-77068524bcab', }, { - id: 'c00d1f90-f5ea-11eb-a78e-83aac3c38a60', name: 'a71cf076-6895-491c-8878-63592e429ed5:panel_a71cf076-6895-491c-8878-63592e429ed5', type: 'visualization', + id: 'c00d1f90-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'c3378480-f5ea-11eb-a78e-83aac3c38a60', - name: 'adc0a2f4-481c-45eb-b422-0ea59a3e5163:panel_adc0a2f4-481c-45eb-b422-0ea59a3e5163', - type: 'visualization', - }, - { - id: 'c762b7a0-f5ea-11eb-a78e-83aac3c38a60', - name: '7077b79f-2a99-4fcb-bbd4-456982843278:panel_7077b79f-2a99-4fcb-bbd4-456982843278', + name: 'da51079b-952f-43dc-96e6-6f9415a3708b:panel_da51079b-952f-43dc-96e6-6f9415a3708b', type: 'lens', + id: 'e3902840-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'ce02e260-f5ea-11eb-a78e-83aac3c38a60', - name: '19a3c101-ad2e-4421-a71b-a4734ec1f03e:panel_19a3c101-ad2e-4421-a71b-a4734ec1f03e', + name: '491469e7-7d24-4216-aeb3-bca00e5c8c1b:panel_491469e7-7d24-4216-aeb3-bca00e5c8c1b', type: 'lens', + id: 'd5f90030-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'd5f90030-f5ea-11eb-a78e-83aac3c38a60', - name: '491469e7-7d24-4216-aeb3-bca00e5c8c1b:panel_491469e7-7d24-4216-aeb3-bca00e5c8c1b', + name: '7077b79f-2a99-4fcb-bbd4-456982843278:panel_7077b79f-2a99-4fcb-bbd4-456982843278', type: 'lens', + id: 'c762b7a0-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'dde978b0-f5ea-11eb-a78e-83aac3c38a60', - name: 'a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef:panel_a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef', + name: '19a3c101-ad2e-4421-a71b-a4734ec1f03e:panel_19a3c101-ad2e-4421-a71b-a4734ec1f03e', type: 'lens', + id: 'ce02e260-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'e3902840-f5ea-11eb-a78e-83aac3c38a60', - name: 'da51079b-952f-43dc-96e6-6f9415a3708b:panel_da51079b-952f-43dc-96e6-6f9415a3708b', + name: 'a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef:panel_a1b03eb9-a36b-4e12-aa1b-bb29b5d6c4ef', type: 'lens', + id: 'dde978b0-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'eddf7850-f5ea-11eb-a78e-83aac3c38a60', name: '64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b:panel_64fd5dcf-30c5-4f5a-a78c-70b1fbf87e5b', type: 'lens', + id: 'eddf7850-f5ea-11eb-a78e-83aac3c38a60', }, { - id: 'ff6a21b0-f5ea-11eb-a78e-83aac3c38a60', name: 'bd330ede-2eef-4e2a-8100-22a21abf5038:panel_bd330ede-2eef-4e2a-8100-22a21abf5038', type: 'lens', + id: 'ff6a21b0-f5ea-11eb-a78e-83aac3c38a60', }, { - id: '03071e90-f5eb-11eb-a78e-83aac3c38a60', name: 'b897d4be-cf83-46fb-a111-c7fbec9ef403:panel_b897d4be-cf83-46fb-a111-c7fbec9ef403', type: 'lens', + id: '03071e90-f5eb-11eb-a78e-83aac3c38a60', }, { - id: '06379e00-f5eb-11eb-a78e-83aac3c38a60', name: 'e0f68f93-30f2-4da7-889a-6cd128a68d3f:panel_e0f68f93-30f2-4da7-889a-6cd128a68d3f', type: 'lens', + id: '06379e00-f5eb-11eb-a78e-83aac3c38a60', + }, + { + name: 'controlGroup_1ee1617f-fd8e-45e4-bc6a-d5736710ea20:optionsListDataView', + type: 'index-pattern', + id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', + }, + { + name: 'controlGroup_afa9fa0f-a002-41a5-bab9-b738316d2590:optionsListDataView', + type: 'index-pattern', + id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', + }, + { + name: 'controlGroup_d3f766cb-5f96-4a12-8d3c-034e08be8855:rangeSliderDataView', + type: 'index-pattern', + id: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', }, ], - type: 'dashboard', - updated_at: '2021-08-05T12:45:46.525Z', - version: 'WzIzOSwxXQ==', + migrationVersion: { + dashboard: '8.5.0', + }, + coreMigrationVersion: '8.6.0', }, ]; diff --git a/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts index 2e4413dcba0d3..db6d9ce049d23 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/flights/saved_objects.ts @@ -220,62 +220,81 @@ export const getSavedObjects = (): SavedObject[] => [ { id: '7adfa750-4c81-11e8-b3d7-01146121b73d', type: 'dashboard', - updated_at: '2021-07-07T14:16:23.001Z', - version: '5', + namespaces: ['default'], + updated_at: '2022-09-26T17:13:00.935Z', + version: 'WzMzMTIsMV0=', + attributes: { + title: i18n.translate('home.sampleData.flightsSpec.globalFlightDashboardTitle', { + defaultMessage: '[Flights] Global Flight Dashboard', + }), + hits: 0, + description: i18n.translate('home.sampleData.flightsSpec.globalFlightDashboardDescription', { + defaultMessage: + 'Analyze mock flight data for ES-Air, Logstash Airways, Kibana Airlines and JetBeats', + }), + panelsJSON: + '[{"version":"8.6.0","type":"search","gridData":{"x":0,"y":69,"w":48,"h":15,"i":"4"},"panelIndex":"4","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_4"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":16,"w":24,"h":9,"i":"7"},"panelIndex":"7","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_7"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":58,"w":24,"h":11,"i":"10"},"panelIndex":"10","embeddableConfig":{"vis":{"colors":{"Count":"#1F78C1"},"legendOpen":false},"enhancements":{}},"panelRefName":"panel_10"},{"version":"8.6.0","type":"visualization","gridData":{"x":36,"y":58,"w":12,"h":11,"i":"21"},"panelIndex":"21","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_21"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":36,"w":24,"h":22,"i":"23"},"panelIndex":"23","embeddableConfig":{"isLayerTOCOpen":true,"enhancements":{},"mapCenter":{"lat":34.65823,"lon":-112.44472,"zoom":4.28},"mapBuffer":{"minLon":-135,"minLat":21.94305,"maxLon":-90,"maxLat":48.9225},"openTOCDetails":[],"hiddenLayers":[]},"panelRefName":"panel_23"},{"version":"8.6.0","type":"visualization","gridData":{"x":24,"y":36,"w":24,"h":22,"i":"31"},"panelIndex":"31","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_31"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":0,"w":24,"h":8,"i":"6afc61f7-e2d5-45a3-9e7a-281160ad3eb9"},"panelIndex":"6afc61f7-e2d5-45a3-9e7a-281160ad3eb9","embeddableConfig":{"savedVis":{"title":"[Flights] Markdown Instructions","description":"","type":"markdown","params":{"fontSize":10,"openLinksInNewTab":true,"markdown":"## Sample Flight data\\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)."},"uiState":{},"data":{"aggs":[],"searchSource":{}}},"hidePanelTitles":true,"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":0,"w":8,"h":8,"i":"392b4936-f753-47bc-a98d-a4e41a0a4cd4"},"panelIndex":"392b4936-f753-47bc-a98d-a4e41a0a4cd4","embeddableConfig":{"enhancements":{},"attributes":{"title":"[Flights] Total Flights","description":"","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"8fa993db-c147-4954-adf7-4ff264d42576":{"columns":{"81124c45-6ab6-42f4-8859-495d55eb8065":{"label":"Total flights","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true}},"columnOrder":["81124c45-6ab6-42f4-8859-495d55eb8065"],"incompleteColumns":{}}}}},"visualization":{"layerId":"8fa993db-c147-4954-adf7-4ff264d42576","accessor":"81124c45-6ab6-42f4-8859-495d55eb8065","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-8fa993db-c147-4954-adf7-4ff264d42576","type":"index-pattern"}]},"hidePanelTitles":true}},{"version":"8.6.0","type":"lens","gridData":{"x":32,"y":0,"w":8,"h":4,"i":"9271deff-5a61-4665-83fc-f9fdc6bf0c0b"},"panelIndex":"9271deff-5a61-4665-83fc-f9fdc6bf0c0b","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0":{"label":"Part of count(kql=\'FlightDelay : true\') / count()","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"FlightDelay : true","language":"kuery"},"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1":{"label":"Part of count(kql=\'FlightDelay : true\') / count()","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2":{"label":"Part of count(kql=\'FlightDelay : true\') / count()","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"location":{"min":0,"max":41},"text":"count(kql=\'FlightDelay : true\') / count()"}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ec":{"label":"Delayed","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'FlightDelay : true\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"customLabel":true}},"columnOrder":["7e8fe9b1-f45c-4f3d-9561-30febcd357ec","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"7e8fe9b1-f45c-4f3d-9561-30febcd357ec","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":40,"y":0,"w":8,"h":4,"i":"aa591c29-1a31-4ee1-a71d-b829c06fd162"},"panelIndex":"aa591c29-1a31-4ee1-a71d-b829c06fd162","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"c7851241-5526-499a-960b-357af8c2ce5bX0":{"label":"Part of Delayed","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX1":{"label":"Part of Delayed","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","timeShift":"1w","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX2":{"label":"Part of Delayed","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"subtract","args":[{"type":"function","name":"divide","args":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"location":{"min":0,"max":28},"text":"count() / count(shift=\'1w\') "},1],"location":{"min":0,"max":31},"text":"count() / count(shift=\'1w\') - 1"}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5b":{"label":"Delayed vs 1 week earlier","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count() / count(shift=\'1w\') - 1","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX2"],"customLabel":true}},"columnOrder":["c7851241-5526-499a-960b-357af8c2ce5b","c7851241-5526-499a-960b-357af8c2ce5bX2","c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"c7851241-5526-499a-960b-357af8c2ce5b","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[{"meta":{"alias":null,"negate":false,"disabled":false,"type":"phrase","key":"FlightDelay","params":{"query":true},"index":"filter-index-pattern-0"},"query":{"match_phrase":{"FlightDelay":true}},"$state":{"store":"appState"}}]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"filter-index-pattern-0","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":32,"y":4,"w":8,"h":4,"i":"b766e3b8-4544-46ed-99e6-9ecc4847e2a2"},"panelIndex":"b766e3b8-4544-46ed-99e6-9ecc4847e2a2","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0":{"label":"Part of Cancelled","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"Cancelled : true","language":"kuery"},"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1":{"label":"Part of Cancelled","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2":{"label":"Part of Cancelled","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"location":{"min":0,"max":39},"text":"count(kql=\'Cancelled : true\') / count()"}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ec":{"label":"Cancelled","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'Cancelled : true\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"customLabel":true}},"columnOrder":["7e8fe9b1-f45c-4f3d-9561-30febcd357ec","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"7e8fe9b1-f45c-4f3d-9561-30febcd357ec","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":40,"y":4,"w":8,"h":4,"i":"2e33ade5-96e5-40b4-b460-493e5d4fa834"},"panelIndex":"2e33ade5-96e5-40b4-b460-493e5d4fa834","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"c7851241-5526-499a-960b-357af8c2ce5bX0":{"label":"Part of Delayed vs 1 week earlier","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX1":{"label":"Part of Delayed vs 1 week earlier","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","timeShift":"1w","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX2":{"label":"Part of Delayed vs 1 week earlier","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"subtract","args":[{"type":"function","name":"divide","args":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"location":{"min":0,"max":28},"text":"count() / count(shift=\'1w\') "},1],"location":{"min":0,"max":31},"text":"count() / count(shift=\'1w\') - 1"}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5b":{"label":"Cancelled vs 1 week earlier","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count() / count(shift=\'1w\') - 1","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX2"],"customLabel":true}},"columnOrder":["c7851241-5526-499a-960b-357af8c2ce5b","c7851241-5526-499a-960b-357af8c2ce5bX2","c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"c7851241-5526-499a-960b-357af8c2ce5b","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[{"meta":{"alias":null,"negate":false,"disabled":false,"type":"phrase","key":"Cancelled","params":{"query":true},"index":"filter-index-pattern-0"},"query":{"match_phrase":{"Cancelled":true}},"$state":{"store":"appState"}}]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"filter-index-pattern-0","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":0,"y":8,"w":24,"h":8,"i":"086ac2e9-dd16-4b45-92b8-1e43ff7e3f65"},"panelIndex":"086ac2e9-dd16-4b45-92b8-1e43ff7e3f65","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsXY","state":{"datasourceStates":{"indexpattern":{"layers":{"03c34665-471c-49c7-acf1-5a11f517421c":{"columns":{"a5b94e30-4e77-4b0a-9187-1d8b13de1456":{"label":"timestamp","dataType":"date","operationType":"date_histogram","sourceField":"timestamp","isBucketed":true,"scale":"interval","params":{"interval":"auto","includeEmptyRows":true}},"3e267327-7317-4310-aee3-320e0f7c1e70":{"label":"Count of records","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___"}},"columnOrder":["a5b94e30-4e77-4b0a-9187-1d8b13de1456","3e267327-7317-4310-aee3-320e0f7c1e70"],"incompleteColumns":{}}}}},"visualization":{"legend":{"isVisible":true,"position":"right","legendSize":"auto"},"valueLabels":"hide","fittingFunction":"None","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"custom","lowerBound":0,"upperBound":1},"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"preferredSeriesType":"bar_stacked","layers":[{"layerId":"03c34665-471c-49c7-acf1-5a11f517421c","accessors":["3e267327-7317-4310-aee3-320e0f7c1e70"],"position":"top","seriesType":"bar_stacked","showGridlines":false,"xAccessor":"a5b94e30-4e77-4b0a-9187-1d8b13de1456","layerType":"data"}]},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-03c34665-471c-49c7-acf1-5a11f517421c","type":"index-pattern"}]},"hidePanelTitles":false,"enhancements":{}},"title":"[Flights] Flight count"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":8,"w":24,"h":28,"i":"fb86b32f-fb7a-45cf-9511-f366fef51bbd"},"panelIndex":"fb86b32f-fb7a-45cf-9511-f366fef51bbd","embeddableConfig":{"attributes":{"title":"Cities by delay, cancellation","type":"lens","visualizationType":"lnsDatatable","state":{"datasourceStates":{"indexpattern":{"layers":{"f26e8f7a-4118-4227-bea0-5c02d8b270f7":{"columns":{"3dd24cb4-45ef-4dd8-b22a-d7b802cb6da0":{"label":"Top values of OriginCityName","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"OriginCityName","isBucketed":true,"params":{"size":1000,"orderBy":{"type":"alphabetical","fallback":true},"orderDirection":"asc","otherBucket":true,"missingBucket":false}},"52f6f2e9-6242-4c44-be63-b799150e7e60X0":{"label":"Part of Delay %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"FlightDelay : true ","language":"kuery"},"customLabel":true},"52f6f2e9-6242-4c44-be63-b799150e7e60X1":{"label":"Part of Delay %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"52f6f2e9-6242-4c44-be63-b799150e7e60X2":{"label":"Part of Delay %","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["52f6f2e9-6242-4c44-be63-b799150e7e60X0","52f6f2e9-6242-4c44-be63-b799150e7e60X1"],"location":{"min":0,"max":42},"text":"count(kql=\'FlightDelay : true \') / count()"}},"references":["52f6f2e9-6242-4c44-be63-b799150e7e60X0","52f6f2e9-6242-4c44-be63-b799150e7e60X1"],"customLabel":true},"52f6f2e9-6242-4c44-be63-b799150e7e60":{"label":"Delay %","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'FlightDelay : true \') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":0}}},"references":["52f6f2e9-6242-4c44-be63-b799150e7e60X2"],"customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0":{"label":"Part of Cancel %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"Cancelled: true","language":"kuery"},"customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1":{"label":"Part of Cancel %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X2":{"label":"Part of Cancel %","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1"],"location":{"min":0,"max":38},"text":"count(kql=\'Cancelled: true\') / count()"}},"references":["7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1"],"customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6":{"label":"Cancel %","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'Cancelled: true\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":0}}},"references":["7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X2"],"customLabel":true}},"columnOrder":["3dd24cb4-45ef-4dd8-b22a-d7b802cb6da0","52f6f2e9-6242-4c44-be63-b799150e7e60","52f6f2e9-6242-4c44-be63-b799150e7e60X0","52f6f2e9-6242-4c44-be63-b799150e7e60X1","52f6f2e9-6242-4c44-be63-b799150e7e60X2","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X2","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6"],"incompleteColumns":{}}}}},"visualization":{"columns":[{"isTransposed":false,"columnId":"3dd24cb4-45ef-4dd8-b22a-d7b802cb6da0","width":262.75},{"columnId":"52f6f2e9-6242-4c44-be63-b799150e7e60","isTransposed":false,"width":302.5,"colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#f7e0b8","stop":0.6},{"color":"#e7664c","stop":1}],"name":"custom","colorStops":[{"color":"#f7e0b8","stop":0.2},{"color":"#e7664c","stop":0.6}],"rangeType":"number","rangeMin":0.2,"rangeMax":0.6}},"alignment":"center"},{"columnId":"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6","isTransposed":false,"alignment":"center","colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#f7e0b8","stop":0.6},{"color":"#e7664c","stop":0.6666666666666666}],"rangeType":"number","name":"custom","colorStops":[{"color":"#f7e0b8","stop":0.2},{"color":"#e7664c","stop":0.6}],"rangeMin":0.2,"rangeMax":0.6}}}],"layerId":"f26e8f7a-4118-4227-bea0-5c02d8b270f7","sorting":{"columnId":"52f6f2e9-6242-4c44-be63-b799150e7e60","direction":"desc"},"layerType":"data","rowHeight":"single","rowHeightLines":1},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-f26e8f7a-4118-4227-bea0-5c02d8b270f7","type":"index-pattern"}]},"enhancements":{},"hidePanelTitles":false},"title":"[Flights] Most delayed cities"},{"version":"8.6.0","type":"lens","gridData":{"x":0,"y":25,"w":24,"h":11,"i":"0cc42484-16f7-42ec-b38c-9bf8be69cde7"},"panelIndex":"0cc42484-16f7-42ec-b38c-9bf8be69cde7","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsXY","state":{"datasourceStates":{"indexpattern":{"layers":{"e80cc05e-c52a-4e5f-ac71-4b37274867f5":{"columns":{"caf7421e-93a3-439e-ab0a-fbdead93c21c":{"label":"Top values of FlightDelayType","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"FlightDelayType","isBucketed":true,"params":{"size":10,"orderBy":{"type":"column","columnId":"0233d302-ec81-4fbe-96cb-7fac84cf035c"},"orderDirection":"desc","otherBucket":true,"missingBucket":false}},"13ec79e3-9d73-4536-9056-3d92802bb30a":{"label":"timestamp","dataType":"date","operationType":"date_histogram","sourceField":"timestamp","isBucketed":true,"scale":"interval","params":{"interval":"auto","includeEmptyRows":true}},"0233d302-ec81-4fbe-96cb-7fac84cf035c":{"label":"Count of records","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___"}},"columnOrder":["caf7421e-93a3-439e-ab0a-fbdead93c21c","13ec79e3-9d73-4536-9056-3d92802bb30a","0233d302-ec81-4fbe-96cb-7fac84cf035c"],"incompleteColumns":{}}}}},"visualization":{"legend":{"isVisible":true,"position":"bottom","legendSize":"auto"},"valueLabels":"hide","fittingFunction":"None","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"},"axisTitlesVisibilitySettings":{"x":true,"yLeft":false,"yRight":true},"tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"preferredSeriesType":"bar_percentage_stacked","layers":[{"layerId":"e80cc05e-c52a-4e5f-ac71-4b37274867f5","accessors":["0233d302-ec81-4fbe-96cb-7fac84cf035c"],"position":"top","seriesType":"bar_percentage_stacked","showGridlines":false,"palette":{"type":"palette","name":"cool"},"xAccessor":"13ec79e3-9d73-4536-9056-3d92802bb30a","splitAccessor":"caf7421e-93a3-439e-ab0a-fbdead93c21c","layerType":"data"}]},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-e80cc05e-c52a-4e5f-ac71-4b37274867f5","type":"index-pattern"}]},"hidePanelTitles":false,"enhancements":{}},"title":"[Flights] Delay Type"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":58,"w":12,"h":11,"i":"5d53db36-2d5a-4adc-af7b-cec4c1a294e0"},"panelIndex":"5d53db36-2d5a-4adc-af7b-cec4c1a294e0","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsPie","state":{"datasourceStates":{"indexpattern":{"layers":{"0c8e136b-a822-4fb3-836d-e06cbea4eea4":{"columns":{"d1cee8bf-34cf-4141-99d7-ff043ee77b56":{"label":"Top values of FlightDelayType","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"FlightDelayType","isBucketed":true,"params":{"size":10,"orderBy":{"type":"column","columnId":"aa152ace-ee2d-447b-b86d-459bef4d7880"},"orderDirection":"desc","otherBucket":true,"missingBucket":false}},"aa152ace-ee2d-447b-b86d-459bef4d7880":{"label":"Count of records","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___"}},"columnOrder":["d1cee8bf-34cf-4141-99d7-ff043ee77b56","aa152ace-ee2d-447b-b86d-459bef4d7880"],"incompleteColumns":{}}}}},"visualization":{"shape":"pie","palette":{"type":"palette","name":"cool"},"layers":[{"layerId":"0c8e136b-a822-4fb3-836d-e06cbea4eea4","metric":"aa152ace-ee2d-447b-b86d-459bef4d7880","numberDisplay":"percent","categoryDisplay":"default","legendDisplay":"default","nestedLegend":false,"layerType":"data","legendSize":"auto","primaryGroups":["d1cee8bf-34cf-4141-99d7-ff043ee77b56"]}]},"query":{"query":"","language":"kuery"},"filters":[{"meta":{"type":"phrase","key":"FlightDelayType","params":{"query":"No Delay"},"disabled":false,"negate":true,"alias":null,"index":"filter-index-pattern-0"},"query":{"match_phrase":{"FlightDelayType":"No Delay"}},"$state":{"store":"appState"}}]},"references":[{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-0c8e136b-a822-4fb3-836d-e06cbea4eea4","type":"index-pattern"},{"id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"filter-index-pattern-0","type":"index-pattern"}]},"enhancements":{},"hidePanelTitles":false},"title":"[Flights] Delay Type"}]', + optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', + version: 1, + timeRestore: true, + timeTo: 'now', + timeFrom: 'now-7d', + refreshInterval: { + pause: true, + value: 0, + }, + controlGroupInput: { + controlStyle: 'oneLine', + chainingSystem: 'HIERARCHICAL', + panelsJSON: + '{"85b632c8-3b7b-408d-8223-b0caccf75bd3":{"order":0,"width":"small","grow":true,"type":"optionsListControl","explicitInput":{"title":"Origin City","fieldName":"OriginCityName","id":"85b632c8-3b7b-408d-8223-b0caccf75bd3","selectedOptions":[],"enhancements":{}}},"d4dc9d2b-5850-402a-921d-8a2cd0107156":{"order":1,"width":"small","grow":true,"type":"optionsListControl","explicitInput":{"title":"Destination City","fieldName":"DestCityName","id":"d4dc9d2b-5850-402a-921d-8a2cd0107156","enhancements":{}}},"bee4a16a-f5c1-40b2-887e-db1b9ad9e15f":{"order":2,"width":"small","grow":true,"type":"rangeSliderControl","explicitInput":{"title":"Average Ticket Price","fieldName":"AvgTicketPrice","id":"bee4a16a-f5c1-40b2-887e-db1b9ad9e15f","enhancements":{}}}}', + ignoreParentSettingsJSON: + '{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', + }, + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"query":{"language":"kuery","query":""},"highlightAll":true,"version":true,"filter":[]}', + }, + }, references: [ { - id: '571aaf70-4c88-11e8-b3d7-01146121b73d', name: '4:panel_4', type: 'search', + id: '571aaf70-4c88-11e8-b3d7-01146121b73d', }, { - id: 'bcb63b50-4c89-11e8-b3d7-01146121b73d', name: '7:panel_7', type: 'visualization', + id: 'bcb63b50-4c89-11e8-b3d7-01146121b73d', }, { - id: '9886b410-4c8b-11e8-b3d7-01146121b73d', name: '10:panel_10', type: 'visualization', + id: '9886b410-4c8b-11e8-b3d7-01146121b73d', }, { - id: '293b5a30-4c8f-11e8-b3d7-01146121b73d', name: '21:panel_21', type: 'visualization', + id: '293b5a30-4c8f-11e8-b3d7-01146121b73d', }, { - id: '334084f0-52fd-11e8-a160-89cc2ad9e8e2', name: '23:panel_23', type: 'visualization', + id: '334084f0-52fd-11e8-a160-89cc2ad9e8e2', }, { - id: 'ed78a660-53a0-11e8-acbd-0be0ad9d822b', name: '31:panel_31', type: 'visualization', + id: 'ed78a660-53a0-11e8-acbd-0be0ad9d822b', }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: 'aa810aa2-29c9-4a75-b39e-f4f267de1732:control_aa810aa2-29c9-4a75-b39e-f4f267de1732_0_index_pattern', - type: 'index-pattern', - }, - { - id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: 'aa810aa2-29c9-4a75-b39e-f4f267de1732:control_aa810aa2-29c9-4a75-b39e-f4f267de1732_1_index_pattern', - type: 'index-pattern', - }, - { - id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: 'aa810aa2-29c9-4a75-b39e-f4f267de1732:control_aa810aa2-29c9-4a75-b39e-f4f267de1732_2_index_pattern', - type: 'index-pattern', - }, - { - id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '086ac2e9-dd16-4b45-92b8-1e43ff7e3f65:indexpattern-datasource-current-indexpattern', + name: '392b4936-f753-47bc-a98d-a4e41a0a4cd4:indexpattern-datasource-current-indexpattern', type: 'index-pattern', }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '086ac2e9-dd16-4b45-92b8-1e43ff7e3f65:indexpattern-datasource-layer-03c34665-471c-49c7-acf1-5a11f517421c', + name: '392b4936-f753-47bc-a98d-a4e41a0a4cd4:indexpattern-datasource-layer-8fa993db-c147-4954-adf7-4ff264d42576', type: 'index-pattern', }, { @@ -328,6 +347,16 @@ export const getSavedObjects = (): SavedObject[] => [ name: '2e33ade5-96e5-40b4-b460-493e5d4fa834:filter-index-pattern-0', type: 'index-pattern', }, + { + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + name: '086ac2e9-dd16-4b45-92b8-1e43ff7e3f65:indexpattern-datasource-current-indexpattern', + type: 'index-pattern', + }, + { + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', + name: '086ac2e9-dd16-4b45-92b8-1e43ff7e3f65:indexpattern-datasource-layer-03c34665-471c-49c7-acf1-5a11f517421c', + type: 'index-pattern', + }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', name: 'fb86b32f-fb7a-45cf-9511-f366fef51bbd:indexpattern-datasource-current-indexpattern', @@ -340,67 +369,48 @@ export const getSavedObjects = (): SavedObject[] => [ }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0:indexpattern-datasource-current-indexpattern', + name: '0cc42484-16f7-42ec-b38c-9bf8be69cde7:indexpattern-datasource-current-indexpattern', type: 'index-pattern', }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0:indexpattern-datasource-layer-0c8e136b-a822-4fb3-836d-e06cbea4eea4', + name: '0cc42484-16f7-42ec-b38c-9bf8be69cde7:indexpattern-datasource-layer-e80cc05e-c52a-4e5f-ac71-4b37274867f5', type: 'index-pattern', }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0:filter-index-pattern-0', + name: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0:indexpattern-datasource-current-indexpattern', type: 'index-pattern', }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '0cc42484-16f7-42ec-b38c-9bf8be69cde7:indexpattern-datasource-current-indexpattern', + name: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0:indexpattern-datasource-layer-0c8e136b-a822-4fb3-836d-e06cbea4eea4', type: 'index-pattern', }, { id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '0cc42484-16f7-42ec-b38c-9bf8be69cde7:indexpattern-datasource-layer-e80cc05e-c52a-4e5f-ac71-4b37274867f5', + name: '5d53db36-2d5a-4adc-af7b-cec4c1a294e0:filter-index-pattern-0', type: 'index-pattern', }, { - id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '392b4936-f753-47bc-a98d-a4e41a0a4cd4:indexpattern-datasource-current-indexpattern', + name: 'controlGroup_85b632c8-3b7b-408d-8223-b0caccf75bd3:optionsListDataView', type: 'index-pattern', + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', }, { + name: 'controlGroup_d4dc9d2b-5850-402a-921d-8a2cd0107156:optionsListDataView', + type: 'index-pattern', id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', - name: '392b4936-f753-47bc-a98d-a4e41a0a4cd4:indexpattern-datasource-layer-8fa993db-c147-4954-adf7-4ff264d42576', + }, + { + name: 'controlGroup_bee4a16a-f5c1-40b2-887e-db1b9ad9e15f:rangeSliderDataView', type: 'index-pattern', + id: 'd3d7af60-4c81-11e8-b3d7-01146121b73d', }, ], migrationVersion: { - dashboard: '7.14.0', - }, - attributes: { - title: i18n.translate('home.sampleData.flightsSpec.globalFlightDashboardTitle', { - defaultMessage: '[Flights] Global Flight Dashboard', - }), - hits: 0, - description: i18n.translate('home.sampleData.flightsSpec.globalFlightDashboardDescription', { - defaultMessage: - 'Analyze mock flight data for ES-Air, Logstash Airways, Kibana Airlines and JetBeats', - }), - panelsJSON: - '[{"version":"7.14.0","type":"search","gridData":{"x":0,"y":68,"w":48,"h":15,"i":"4"},"panelIndex":"4","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_4"},{"version":"7.14.0","type":"visualization","gridData":{"x":0,"y":15,"w":24,"h":9,"i":"7"},"panelIndex":"7","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_7"},{"version":"7.14.0","type":"visualization","gridData":{"x":0,"y":57,"w":24,"h":11,"i":"10"},"panelIndex":"10","embeddableConfig":{"vis":{"colors":{"Count":"#1F78C1"},"legendOpen":false},"enhancements":{}},"panelRefName":"panel_10"},{"version":"7.14.0","type":"visualization","gridData":{"x":36,"y":57,"w":12,"h":11,"i":"21"},"panelIndex":"21","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_21"},{"version":"7.14.0","type":"map","gridData":{"x":0,"y":35,"w":24,"h":22,"i":"23"},"panelIndex":"23","embeddableConfig":{"isLayerTOCOpen":true,"enhancements":{},"mapCenter":{"lat":34.65823,"lon":-112.44472,"zoom":4.28},"mapBuffer":{"minLon":-135,"minLat":21.94305,"maxLon":-90,"maxLat":48.9225},"openTOCDetails":[],"hiddenLayers":[]},"panelRefName":"panel_23"},{"version":"7.14.0","type":"visualization","gridData":{"x":24,"y":35,"w":24,"h":22,"i":"31"},"panelIndex":"31","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_31"},{"version":"7.14.0","type":"visualization","gridData":{"x":0,"y":0,"w":32,"h":7,"i":"aa810aa2-29c9-4a75-b39e-f4f267de1732"},"panelIndex":"aa810aa2-29c9-4a75-b39e-f4f267de1732","embeddableConfig":{"savedVis":{"title":"[Flights] Controls","description":"","type":"input_control_vis","params":{"controls":[{"id":"1525098134264","fieldName":"OriginCityName","parent":"","label":"Origin City","type":"list","options":{"type":"terms","multiselect":true,"size":100,"order":"desc"},"indexPatternRefName":"control_aa810aa2-29c9-4a75-b39e-f4f267de1732_0_index_pattern"},{"id":"1525099277699","fieldName":"DestCityName","parent":"1525098134264","label":"Destination City","type":"list","options":{"type":"terms","multiselect":true,"size":100,"order":"desc"},"indexPatternRefName":"control_aa810aa2-29c9-4a75-b39e-f4f267de1732_1_index_pattern"},{"id":"1525099307278","fieldName":"AvgTicketPrice","parent":"","label":"Average Ticket Price","type":"range","options":{"decimalPlaces":0,"step":10},"indexPatternRefName":"control_aa810aa2-29c9-4a75-b39e-f4f267de1732_2_index_pattern"}],"updateFiltersOnChange":false,"useTimeFilter":true,"pinFilters":false},"uiState":{},"data":{"aggs":[],"searchSource":{}}},"hidePanelTitles":true,"enhancements":{}}},{"version":"7.14.0","type":"visualization","gridData":{"x":32,"y":0,"w":16,"h":7,"i":"6afc61f7-e2d5-45a3-9e7a-281160ad3eb9"},"panelIndex":"6afc61f7-e2d5-45a3-9e7a-281160ad3eb9","embeddableConfig":{"savedVis":{"title":"[Flights] Markdown Instructions","description":"","type":"markdown","params":{"fontSize":10,"openLinksInNewTab":true,"markdown":"## Sample Flight data\\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)."},"uiState":{},"data":{"aggs":[],"searchSource":{}}},"hidePanelTitles":true,"enhancements":{}}},{"version":"7.14.0","type":"lens","gridData":{"x":0,"y":7,"w":24,"h":8,"i":"086ac2e9-dd16-4b45-92b8-1e43ff7e3f65"},"panelIndex":"086ac2e9-dd16-4b45-92b8-1e43ff7e3f65","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsXY","state":{"datasourceStates":{"indexpattern":{"layers":{"03c34665-471c-49c7-acf1-5a11f517421c":{"columns":{"a5b94e30-4e77-4b0a-9187-1d8b13de1456":{"label":"timestamp","dataType":"date","operationType":"date_histogram","sourceField":"timestamp","isBucketed":true,"scale":"interval","params":{"interval":"auto"}},"3e267327-7317-4310-aee3-320e0f7c1e70":{"label":"Count of records","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records"}},"columnOrder":["a5b94e30-4e77-4b0a-9187-1d8b13de1456","3e267327-7317-4310-aee3-320e0f7c1e70"],"incompleteColumns":{}}}}},"visualization":{"legend":{"isVisible":true,"position":"right"},"valueLabels":"hide","fittingFunction":"None","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"custom","lowerBound":0,"upperBound":1},"axisTitlesVisibilitySettings":{"x":false,"yLeft":false,"yRight":true},"tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"preferredSeriesType":"bar_stacked","layers":[{"layerId":"03c34665-471c-49c7-acf1-5a11f517421c","accessors":["3e267327-7317-4310-aee3-320e0f7c1e70"],"position":"top","seriesType":"bar_stacked","showGridlines":false,"xAccessor":"a5b94e30-4e77-4b0a-9187-1d8b13de1456"}]},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-03c34665-471c-49c7-acf1-5a11f517421c"}]},"hidePanelTitles":false,"enhancements":{}},"title":"[Flights] Flight count"},{"version":"7.14.0","type":"lens","gridData":{"x":24,"y":7,"w":8,"h":8,"i":"392b4936-f753-47bc-a98d-a4e41a0a4cd4"},"panelIndex":"392b4936-f753-47bc-a98d-a4e41a0a4cd4","embeddableConfig":{"enhancements":{},"attributes":{"title":"[Flights] Total Flights","description":"","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"8fa993db-c147-4954-adf7-4ff264d42576":{"columns":{"81124c45-6ab6-42f4-8859-495d55eb8065":{"label":"Total flights","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true}},"columnOrder":["81124c45-6ab6-42f4-8859-495d55eb8065"],"incompleteColumns":{}}}}},"visualization":{"layerId":"8fa993db-c147-4954-adf7-4ff264d42576","accessor":"81124c45-6ab6-42f4-8859-495d55eb8065"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-8fa993db-c147-4954-adf7-4ff264d42576"}]},"hidePanelTitles":true}},{"version":"7.14.0","type":"lens","gridData":{"x":32,"y":7,"w":8,"h":4,"i":"9271deff-5a61-4665-83fc-f9fdc6bf0c0b"},"panelIndex":"9271deff-5a61-4665-83fc-f9fdc6bf0c0b","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0":{"label":"Part of count(kql=\'FlightDelay : true\') / count()","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"FlightDelay : true","language":"kuery"},"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1":{"label":"Part of count(kql=\'FlightDelay : true\') / count()","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2":{"label":"Part of count(kql=\'FlightDelay : true\') / count()","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"location":{"min":0,"max":41},"text":"count(kql=\'FlightDelay : true\') / count()"}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ec":{"label":"Delayed","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'FlightDelay : true\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"customLabel":true}},"columnOrder":["7e8fe9b1-f45c-4f3d-9561-30febcd357ec","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"7e8fe9b1-f45c-4f3d-9561-30febcd357ec"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317"}]},"enhancements":{}}},{"version":"7.14.0","type":"lens","gridData":{"x":40,"y":7,"w":8,"h":4,"i":"aa591c29-1a31-4ee1-a71d-b829c06fd162"},"panelIndex":"aa591c29-1a31-4ee1-a71d-b829c06fd162","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"c7851241-5526-499a-960b-357af8c2ce5bX0":{"label":"Part of Delayed","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX1":{"label":"Part of Delayed","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","timeShift":"1w","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX2":{"label":"Part of Delayed","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"subtract","args":[{"type":"function","name":"divide","args":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"location":{"min":0,"max":28},"text":"count() / count(shift=\'1w\') "},1],"location":{"min":0,"max":31},"text":"count() / count(shift=\'1w\') - 1"}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5b":{"label":"Delayed vs 1 week earlier","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count() / count(shift=\'1w\') - 1","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX2"],"customLabel":true}},"columnOrder":["c7851241-5526-499a-960b-357af8c2ce5b","c7851241-5526-499a-960b-357af8c2ce5bX2","c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"c7851241-5526-499a-960b-357af8c2ce5b"},"query":{"query":"","language":"kuery"},"filters":[{"meta":{"alias":null,"negate":false,"disabled":false,"type":"phrase","key":"FlightDelay","params":{"query":true},"indexRefName":"filter-index-pattern-0"},"query":{"match_phrase":{"FlightDelay":true}},"$state":{"store":"appState"}}]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317"},{"name":"filter-index-pattern-0","type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d"}]},"enhancements":{}}},{"version":"7.14.0","type":"lens","gridData":{"x":32,"y":11,"w":8,"h":4,"i":"b766e3b8-4544-46ed-99e6-9ecc4847e2a2"},"panelIndex":"b766e3b8-4544-46ed-99e6-9ecc4847e2a2","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0":{"label":"Part of Cancelled","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"Cancelled : true","language":"kuery"},"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1":{"label":"Part of Cancelled","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2":{"label":"Part of Cancelled","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"location":{"min":0,"max":39},"text":"count(kql=\'Cancelled : true\') / count()"}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1"],"customLabel":true},"7e8fe9b1-f45c-4f3d-9561-30febcd357ec":{"label":"Cancelled","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'Cancelled : true\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"customLabel":true}},"columnOrder":["7e8fe9b1-f45c-4f3d-9561-30febcd357ec","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX0","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX1","7e8fe9b1-f45c-4f3d-9561-30febcd357ecX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"7e8fe9b1-f45c-4f3d-9561-30febcd357ec"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317"}]},"enhancements":{}}},{"version":"7.14.0","type":"lens","gridData":{"x":40,"y":11,"w":8,"h":4,"i":"2e33ade5-96e5-40b4-b460-493e5d4fa834"},"panelIndex":"2e33ade5-96e5-40b4-b460-493e5d4fa834","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"b4712d43-1e84-4f5b-878d-8e38ba748317":{"columns":{"c7851241-5526-499a-960b-357af8c2ce5bX0":{"label":"Part of Delayed vs 1 week earlier","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX1":{"label":"Part of Delayed vs 1 week earlier","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","timeShift":"1w","customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5bX2":{"label":"Part of Delayed vs 1 week earlier","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"subtract","args":[{"type":"function","name":"divide","args":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"location":{"min":0,"max":28},"text":"count() / count(shift=\'1w\') "},1],"location":{"min":0,"max":31},"text":"count() / count(shift=\'1w\') - 1"}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"customLabel":true},"c7851241-5526-499a-960b-357af8c2ce5b":{"label":"Cancelled vs 1 week earlier","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count() / count(shift=\'1w\') - 1","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["c7851241-5526-499a-960b-357af8c2ce5bX2"],"customLabel":true}},"columnOrder":["c7851241-5526-499a-960b-357af8c2ce5b","c7851241-5526-499a-960b-357af8c2ce5bX2","c7851241-5526-499a-960b-357af8c2ce5bX0","c7851241-5526-499a-960b-357af8c2ce5bX1"],"incompleteColumns":{}}}}},"visualization":{"layerId":"b4712d43-1e84-4f5b-878d-8e38ba748317","accessor":"c7851241-5526-499a-960b-357af8c2ce5b"},"query":{"query":"","language":"kuery"},"filters":[{"meta":{"alias":null,"negate":false,"disabled":false,"type":"phrase","key":"Cancelled","params":{"query":true},"indexRefName":"filter-index-pattern-0"},"query":{"match_phrase":{"Cancelled":true}},"$state":{"store":"appState"}}]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-b4712d43-1e84-4f5b-878d-8e38ba748317"},{"name":"filter-index-pattern-0","type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d"}]},"enhancements":{}}},{"version":"7.14.0","type":"lens","gridData":{"x":24,"y":15,"w":24,"h":20,"i":"fb86b32f-fb7a-45cf-9511-f366fef51bbd"},"panelIndex":"fb86b32f-fb7a-45cf-9511-f366fef51bbd","embeddableConfig":{"attributes":{"title":"Cities by delay, cancellation","type":"lens","visualizationType":"lnsDatatable","state":{"datasourceStates":{"indexpattern":{"layers":{"f26e8f7a-4118-4227-bea0-5c02d8b270f7":{"columns":{"3dd24cb4-45ef-4dd8-b22a-d7b802cb6da0":{"label":"Top values of OriginCityName","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"OriginCityName","isBucketed":true,"params":{"size":1000,"orderBy":{"type":"alphabetical","fallback":true},"orderDirection":"asc","otherBucket":true,"missingBucket":false}},"52f6f2e9-6242-4c44-be63-b799150e7e60X0":{"label":"Part of Delay %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"FlightDelay : true ","language":"kuery"},"customLabel":true},"52f6f2e9-6242-4c44-be63-b799150e7e60X1":{"label":"Part of Delay %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"52f6f2e9-6242-4c44-be63-b799150e7e60X2":{"label":"Part of Delay %","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["52f6f2e9-6242-4c44-be63-b799150e7e60X0","52f6f2e9-6242-4c44-be63-b799150e7e60X1"],"location":{"min":0,"max":42},"text":"count(kql=\'FlightDelay : true \') / count()"}},"references":["52f6f2e9-6242-4c44-be63-b799150e7e60X0","52f6f2e9-6242-4c44-be63-b799150e7e60X1"],"customLabel":true},"52f6f2e9-6242-4c44-be63-b799150e7e60":{"label":"Delay %","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'FlightDelay : true \') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":0}}},"references":["52f6f2e9-6242-4c44-be63-b799150e7e60X2"],"customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0":{"label":"Part of Cancel %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"Cancelled: true","language":"kuery"},"customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1":{"label":"Part of Cancel %","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X2":{"label":"Part of Cancel %","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1"],"location":{"min":0,"max":38},"text":"count(kql=\'Cancelled: true\') / count()"}},"references":["7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1"],"customLabel":true},"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6":{"label":"Cancel %","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'Cancelled: true\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":0}}},"references":["7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X2"],"customLabel":true}},"columnOrder":["3dd24cb4-45ef-4dd8-b22a-d7b802cb6da0","52f6f2e9-6242-4c44-be63-b799150e7e60","52f6f2e9-6242-4c44-be63-b799150e7e60X0","52f6f2e9-6242-4c44-be63-b799150e7e60X1","52f6f2e9-6242-4c44-be63-b799150e7e60X2","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X0","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X1","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6X2","7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6"],"incompleteColumns":{}}}}},"visualization":{"columns":[{"isTransposed":false,"columnId":"3dd24cb4-45ef-4dd8-b22a-d7b802cb6da0","width":262.75},{"columnId":"52f6f2e9-6242-4c44-be63-b799150e7e60","isTransposed":false,"width":302.5,"colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#f7e0b8","stop":0.6},{"color":"#e7664c","stop":1}],"name":"custom","colorStops":[{"color":"#f7e0b8","stop":0.2},{"color":"#e7664c","stop":0.6}],"rangeType":"number","rangeMin":0.2,"rangeMax":0.6}},"alignment":"center"},{"columnId":"7b9f3ece-9da3-4c27-b582-d3f8e8cc31d6","isTransposed":false,"alignment":"center","colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#f7e0b8","stop":0.6},{"color":"#e7664c","stop":0.6666666666666666}],"rangeType":"number","name":"custom","colorStops":[{"color":"#f7e0b8","stop":0.2},{"color":"#e7664c","stop":0.6}],"rangeMin":0.2,"rangeMax":0.6}}}],"layerId":"f26e8f7a-4118-4227-bea0-5c02d8b270f7","sorting":{"columnId":"52f6f2e9-6242-4c44-be63-b799150e7e60","direction":"desc"}},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-f26e8f7a-4118-4227-bea0-5c02d8b270f7"}]},"enhancements":{},"hidePanelTitles":false},"title":"[Flights] Most delayed cities"},{"version":"7.14.0","type":"lens","gridData":{"x":0,"y":24,"w":24,"h":11,"i":"0cc42484-16f7-42ec-b38c-9bf8be69cde7"},"panelIndex":"0cc42484-16f7-42ec-b38c-9bf8be69cde7","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsXY","state":{"datasourceStates":{"indexpattern":{"layers":{"e80cc05e-c52a-4e5f-ac71-4b37274867f5":{"columns":{"caf7421e-93a3-439e-ab0a-fbdead93c21c":{"label":"Top values of FlightDelayType","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"FlightDelayType","isBucketed":true,"params":{"size":10,"orderBy":{"type":"column","columnId":"0233d302-ec81-4fbe-96cb-7fac84cf035c"},"orderDirection":"desc","otherBucket":true,"missingBucket":false}},"13ec79e3-9d73-4536-9056-3d92802bb30a":{"label":"timestamp","dataType":"date","operationType":"date_histogram","sourceField":"timestamp","isBucketed":true,"scale":"interval","params":{"interval":"auto"}},"0233d302-ec81-4fbe-96cb-7fac84cf035c":{"label":"Count of records","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records"}},"columnOrder":["caf7421e-93a3-439e-ab0a-fbdead93c21c","13ec79e3-9d73-4536-9056-3d92802bb30a","0233d302-ec81-4fbe-96cb-7fac84cf035c"],"incompleteColumns":{}}}}},"visualization":{"legend":{"isVisible":true,"position":"bottom"},"valueLabels":"hide","fittingFunction":"None","yLeftExtent":{"mode":"full"},"yRightExtent":{"mode":"full"},"axisTitlesVisibilitySettings":{"x":true,"yLeft":false,"yRight":true},"tickLabelsVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"gridlinesVisibilitySettings":{"x":true,"yLeft":true,"yRight":true},"preferredSeriesType":"bar_percentage_stacked","layers":[{"layerId":"e80cc05e-c52a-4e5f-ac71-4b37274867f5","accessors":["0233d302-ec81-4fbe-96cb-7fac84cf035c"],"position":"top","seriesType":"bar_percentage_stacked","showGridlines":false,"palette":{"type":"palette","name":"cool"},"xAccessor":"13ec79e3-9d73-4536-9056-3d92802bb30a","splitAccessor":"caf7421e-93a3-439e-ab0a-fbdead93c21c"}]},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-e80cc05e-c52a-4e5f-ac71-4b37274867f5"}]},"hidePanelTitles":false,"enhancements":{}},"title":"[Flights] Delay Type"},{"version":"7.14.0","type":"lens","gridData":{"x":24,"y":57,"w":12,"h":11,"i":"5d53db36-2d5a-4adc-af7b-cec4c1a294e0"},"panelIndex":"5d53db36-2d5a-4adc-af7b-cec4c1a294e0","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsPie","state":{"datasourceStates":{"indexpattern":{"layers":{"0c8e136b-a822-4fb3-836d-e06cbea4eea4":{"columns":{"d1cee8bf-34cf-4141-99d7-ff043ee77b56":{"label":"Top values of FlightDelayType","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"FlightDelayType","isBucketed":true,"params":{"size":10,"orderBy":{"type":"column","columnId":"aa152ace-ee2d-447b-b86d-459bef4d7880"},"orderDirection":"desc","otherBucket":true,"missingBucket":false}},"aa152ace-ee2d-447b-b86d-459bef4d7880":{"label":"Count of records","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records"}},"columnOrder":["d1cee8bf-34cf-4141-99d7-ff043ee77b56","aa152ace-ee2d-447b-b86d-459bef4d7880"],"incompleteColumns":{}}}}},"visualization":{"shape":"pie","palette":{"type":"palette","name":"cool"},"layers":[{"layerId":"0c8e136b-a822-4fb3-836d-e06cbea4eea4","groups":["d1cee8bf-34cf-4141-99d7-ff043ee77b56"],"metric":"aa152ace-ee2d-447b-b86d-459bef4d7880","numberDisplay":"percent","categoryDisplay":"default","legendDisplay":"default","nestedLegend":false}]},"query":{"query":"","language":"kuery"},"filters":[{"meta":{"type":"phrase","key":"FlightDelayType","params":{"query":"No Delay"},"disabled":false,"negate":true,"alias":null,"indexRefName":"filter-index-pattern-0"},"query":{"match_phrase":{"FlightDelayType":"No Delay"}},"$state":{"store":"appState"}}]},"references":[{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d","name":"indexpattern-datasource-layer-0c8e136b-a822-4fb3-836d-e06cbea4eea4"},{"name":"filter-index-pattern-0","type":"index-pattern","id":"d3d7af60-4c81-11e8-b3d7-01146121b73d"}]},"enhancements":{},"hidePanelTitles":false},"title":"[Flights] Delay Type"}]', - optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', - version: 1, - timeRestore: true, - timeTo: 'now', - timeFrom: 'now-7d', - refreshInterval: { - pause: true, - value: 0, - }, - kibanaSavedObjectMeta: { - searchSourceJSON: - '{"query":{"language":"kuery","query":""},"filter":[],"highlightAll":true,"version":true}', - }, + dashboard: '8.5.0', }, + coreMigrationVersion: '8.6.0', }, ]; diff --git a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts index b5f57e0edb2e6..5de45e08d0fec 100644 --- a/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts +++ b/src/plugins/home/server/services/sample_data/data_sets/logs/saved_objects.ts @@ -381,48 +381,66 @@ export const getSavedObjects = (): SavedObject[] => [ { id: 'edf84fe0-e1a0-11e7-b6d5-4dc382ef7f5b', type: 'dashboard', - updated_at: '2021-10-28T15:07:36.622Z', - version: '3', + namespaces: ['default'], + updated_at: '2022-09-26T16:24:51.698Z', + version: 'WzE1NTIsMV0=', + attributes: { + title: i18n.translate('home.sampleData.logsSpec.webTrafficTitle', { + defaultMessage: '[Logs] Web Traffic', + }), + hits: 0, + description: i18n.translate('home.sampleData.logsSpec.webTrafficDescription', { + defaultMessage: "Analyze mock web traffic log data for Elastic's website", + }), + panelsJSON: + '[{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":14,"w":24,"h":18,"i":"4"},"panelIndex":"4","embeddableConfig":{"isLayerTOCOpen":false,"enhancements":{},"mapCenter":{"lat":42.16337,"lon":-88.92107,"zoom":3.64},"mapBuffer":{"minLon":-112.5,"minLat":21.94305,"maxLon":-45,"maxLat":55.77657},"openTOCDetails":[],"hiddenLayers":[]},"panelRefName":"panel_4"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":47,"w":24,"h":13,"i":"9"},"panelIndex":"9","embeddableConfig":{"mapCenter":[36.8092847020594,-96.94335937500001],"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}},"enhancements":{}},"panelRefName":"panel_9"},{"version":"8.6.0","type":"visualization","gridData":{"x":36,"y":0,"w":12,"h":7,"i":"11"},"panelIndex":"11","embeddableConfig":{"vis":{"colors":{"0 - 500":"#BF1B00","1000 - 1500":"#7EB26D","500 - 1000":"#F2C96D"},"defaultColors":{"0 - 500":"rgb(165,0,38)","1000 - 1500":"rgb(0,104,55)","500 - 1000":"rgb(255,255,190)"},"legendOpen":false},"enhancements":{},"hidePanelTitles":true},"title":"","panelRefName":"panel_11"},{"version":"8.6.0","type":"visualization","gridData":{"x":24,"y":14,"w":24,"h":33,"i":"14"},"panelIndex":"14","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_14"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":7,"w":24,"h":7,"i":"15"},"panelIndex":"15","embeddableConfig":{"enhancements":{"dynamicActions":{"events":[]}}},"panelRefName":"panel_15"},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":0,"w":24,"h":7,"i":"343f0bef-0b19-452e-b1c8-59beb18b6f0c"},"panelIndex":"343f0bef-0b19-452e-b1c8-59beb18b6f0c","embeddableConfig":{"savedVis":{"title":"[Logs] Markdown Instructions","description":"","type":"markdown","params":{"fontSize":12,"openLinksInNewTab":true,"markdown":"## Sample Logs Data\\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)."},"uiState":{},"data":{"aggs":[],"searchSource":{"query":{"query":"","language":"kuery"},"filter":[]}}},"enhancements":{},"hidePanelTitles":true}},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":0,"w":12,"h":7,"i":"bb94016e-f4a6-49ca-87a9-296a2869d570"},"panelIndex":"bb94016e-f4a6-49ca-87a9-296a2869d570","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"483defd2-775b-4a62-bdef-496c819bb8ed":{"columns":{"37430d12-7452-4cc9-b035-5cfd4061edf0":{"label":"Visits","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true}},"columnOrder":["37430d12-7452-4cc9-b035-5cfd4061edf0"],"incompleteColumns":{}}}}},"visualization":{"layerId":"483defd2-775b-4a62-bdef-496c819bb8ed","accessor":"37430d12-7452-4cc9-b035-5cfd4061edf0","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-483defd2-775b-4a62-bdef-496c819bb8ed","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":7,"w":12,"h":7,"i":"01d8e435-91c0-484f-a11e-856747050b0a"},"panelIndex":"01d8e435-91c0-484f-a11e-856747050b0a","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"f3793bb7-3971-4753-866d-4008e77a9f9a":{"columns":{"71c076a6-e782-4866-b8df-5fd85a41f08bX0":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"response.keyword >= 400 and response.keyword < 500","language":"kuery"},"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX1":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX2":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"location":{"min":0,"max":73},"text":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()"}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08b":{"label":"HTTP 4xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"customLabel":true}},"columnOrder":["71c076a6-e782-4866-b8df-5fd85a41f08b","71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1","71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"f3793bb7-3971-4753-866d-4008e77a9f9a","accessor":"71c076a6-e782-4866-b8df-5fd85a41f08b","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-f3793bb7-3971-4753-866d-4008e77a9f9a","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"lens","gridData":{"x":36,"y":7,"w":12,"h":7,"i":"8c1456d4-1993-4ba2-b701-04aca02c9fef"},"panelIndex":"8c1456d4-1993-4ba2-b701-04aca02c9fef","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsLegacyMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"f3793bb7-3971-4753-866d-4008e77a9f9a":{"columns":{"71c076a6-e782-4866-b8df-5fd85a41f08bX0":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"response.keyword >= 500","language":"kuery"},"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX1":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX2":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"location":{"min":0,"max":46},"text":"count(kql=\'response.keyword >= 500\') / count()"}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08b":{"label":"HTTP 5xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"customLabel":true}},"columnOrder":["71c076a6-e782-4866-b8df-5fd85a41f08b","71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1","71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"f3793bb7-3971-4753-866d-4008e77a9f9a","accessor":"71c076a6-e782-4866-b8df-5fd85a41f08b","layerType":"data","textAlign":"center","titlePosition":"bottom","size":"xl"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-f3793bb7-3971-4753-866d-4008e77a9f9a","type":"index-pattern"}]},"enhancements":{}}},{"version":"8.6.0","type":"visualization","gridData":{"x":0,"y":32,"w":24,"h":15,"i":"8e59c7cf-6e42-4343-a113-c4a255fcf2ce"},"panelIndex":"8e59c7cf-6e42-4343-a113-c4a255fcf2ce","embeddableConfig":{"savedVis":{"title":"","description":"","type":"vega","params":{"spec":"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n data: {\\n url: {\\n %context%: true\\n %timefield%: @timestamp\\n index: kibana_sample_data_logs\\n body: {\\n aggs: {\\n countries: {\\n terms: {\\n field: geo.src\\n size: 25\\n }\\n aggs: {\\n hours: {\\n histogram: {\\n field: hour_of_day\\n interval: 1\\n }\\n aggs: {\\n unique: {\\n cardinality: {\\n field: clientip\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n }\\n }\\n format: {property: \\"aggregations.countries.buckets\\"}\\n }\\n \\n transform: [\\n {\\n flatten: [\\"hours.buckets\\"],\\n as: [\\"buckets\\"]\\n }\\n ]\\n\\n mark: {\\n type: rect\\n tooltip: true\\n }\\n\\n encoding: {\\n x: {\\n field: buckets.key\\n type: ordinal\\n axis: {\\n title: false\\n labelAngle: 0\\n }\\n }\\n y: {\\n field: key\\n type: nominal\\n sort: {\\n field: -buckets.unique.value\\n }\\n axis: {title: false}\\n }\\n color: {\\n field: buckets.unique.value\\n type: quantitative\\n axis: {title: false}\\n scale: {\\n scheme: reds\\n }\\n }\\n }\\n}\\n"},"uiState":{},"data":{"aggs":[],"searchSource":{"query":{"query":"","language":"kuery"},"filter":[]}}},"enhancements":{}},"panelRefName":"panel_8e59c7cf-6e42-4343-a113-c4a255fcf2ce"},{"version":"8.6.0","type":"lens","gridData":{"x":24,"y":47,"w":24,"h":13,"i":"cbca842c-b9fa-4523-9ce0-14e350866e33"},"panelIndex":"cbca842c-b9fa-4523-9ce0-14e350866e33","embeddableConfig":{"hidePanelTitles":false,"enhancements":{}},"title":"[Logs] Bytes distribution","panelRefName":"panel_cbca842c-b9fa-4523-9ce0-14e350866e33"},{"version":"8.6.0","type":"lens","gridData":{"x":0,"y":60,"w":48,"h":19,"i":"1d5f0b3f-d9d2-4b26-997b-83bc5ca3090b"},"panelIndex":"1d5f0b3f-d9d2-4b26-997b-83bc5ca3090b","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsDatatable","state":{"datasourceStates":{"indexpattern":{"layers":{"c35dc8ee-50d1-4ef7-8b4b-9c21a7e7d3b0":{"columns":{"42783ad7-dbcf-4310-bc06-f21f4eaaac96":{"label":"URL","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"url.keyword","isBucketed":true,"params":{"size":1000,"orderBy":{"type":"column","columnId":"f7835375-4d5b-4839-95ea-41928192a319"},"orderDirection":"desc","otherBucket":true,"missingBucket":false},"customLabel":true},"f7835375-4d5b-4839-95ea-41928192a319":{"label":"Visits","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1daX0":{"label":"Part of HTTP 4xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"response.keyword >= 400 and response.keyword < 500","language":"kuery"},"customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1daX1":{"label":"Part of HTTP 4xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1daX2":{"label":"Part of HTTP 4xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["07fc84ca-4147-4ba9-879e-d1b4e086e1daX0","07fc84ca-4147-4ba9-879e-d1b4e086e1daX1"],"location":{"min":0,"max":73},"text":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()"}},"references":["07fc84ca-4147-4ba9-879e-d1b4e086e1daX0","07fc84ca-4147-4ba9-879e-d1b4e086e1daX1"],"customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1da":{"label":"HTTP 4xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["07fc84ca-4147-4ba9-879e-d1b4e086e1daX2"],"customLabel":true},"791d5a5b-a7ba-4e9e-b533-51b33c7d7747":{"label":"Unique","dataType":"number","operationType":"unique_count","scale":"ratio","sourceField":"clientip","isBucketed":false,"customLabel":true},"611e3509-e834-4fdd-b573-44e959e95d27":{"label":"95th percentile of bytes","dataType":"number","operationType":"percentile","sourceField":"bytes","isBucketed":false,"scale":"ratio","params":{"percentile":95,"format":{"id":"bytes","params":{"decimals":0}}}},"9f79ecca-123f-4098-a658-6b0e998da003":{"label":"Median of bytes","dataType":"number","operationType":"median","sourceField":"bytes","isBucketed":false,"scale":"ratio","params":{"format":{"id":"bytes","params":{"decimals":0}}}},"491285fd-0196-402c-9b7f-4660fdc1c22aX0":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","filter":{"query":"response.keyword >= 500","language":"kuery"},"customLabel":true},"491285fd-0196-402c-9b7f-4660fdc1c22aX1":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"___records___","customLabel":true},"491285fd-0196-402c-9b7f-4660fdc1c22aX2":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["491285fd-0196-402c-9b7f-4660fdc1c22aX0","491285fd-0196-402c-9b7f-4660fdc1c22aX1"],"location":{"min":0,"max":46},"text":"count(kql=\'response.keyword >= 500\') / count()"}},"references":["491285fd-0196-402c-9b7f-4660fdc1c22aX0","491285fd-0196-402c-9b7f-4660fdc1c22aX1"],"customLabel":true},"491285fd-0196-402c-9b7f-4660fdc1c22a":{"label":"HTTP 5xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["491285fd-0196-402c-9b7f-4660fdc1c22aX2"],"customLabel":true}},"columnOrder":["42783ad7-dbcf-4310-bc06-f21f4eaaac96","f7835375-4d5b-4839-95ea-41928192a319","791d5a5b-a7ba-4e9e-b533-51b33c7d7747","07fc84ca-4147-4ba9-879e-d1b4e086e1da","491285fd-0196-402c-9b7f-4660fdc1c22a","491285fd-0196-402c-9b7f-4660fdc1c22aX0","491285fd-0196-402c-9b7f-4660fdc1c22aX1","491285fd-0196-402c-9b7f-4660fdc1c22aX2","07fc84ca-4147-4ba9-879e-d1b4e086e1daX0","07fc84ca-4147-4ba9-879e-d1b4e086e1daX1","07fc84ca-4147-4ba9-879e-d1b4e086e1daX2","611e3509-e834-4fdd-b573-44e959e95d27","9f79ecca-123f-4098-a658-6b0e998da003"],"incompleteColumns":{}}}}},"visualization":{"layerId":"c35dc8ee-50d1-4ef7-8b4b-9c21a7e7d3b0","columns":[{"columnId":"42783ad7-dbcf-4310-bc06-f21f4eaaac96","width":650.6666666666666},{"columnId":"f7835375-4d5b-4839-95ea-41928192a319"},{"columnId":"491285fd-0196-402c-9b7f-4660fdc1c22a","isTransposed":false,"width":81.66666666666669,"colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#fbddd6","stop":0.1},{"color":"#CC5642","stop":1}],"rangeType":"number","name":"custom","colorStops":[{"color":"#fbddd6","stop":0.05},{"color":"#CC5642","stop":0.1}],"rangeMin":0.05,"rangeMax":0.1}}},{"columnId":"07fc84ca-4147-4ba9-879e-d1b4e086e1da","isTransposed":false,"colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#fbddd6","stop":0.1},{"color":"#cc5642","stop":1.1}],"name":"custom","colorStops":[{"color":"#fbddd6","stop":0.05},{"color":"#cc5642","stop":0.1}],"rangeType":"number","rangeMin":0.05,"rangeMax":0.1}}},{"columnId":"791d5a5b-a7ba-4e9e-b533-51b33c7d7747","isTransposed":false},{"columnId":"611e3509-e834-4fdd-b573-44e959e95d27","isTransposed":false},{"columnId":"9f79ecca-123f-4098-a658-6b0e998da003","isTransposed":false}],"sorting":{"columnId":"491285fd-0196-402c-9b7f-4660fdc1c22a","direction":"desc"},"layerType":"data","rowHeight":"single","rowHeightLines":1},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern","type":"index-pattern"},{"id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-c35dc8ee-50d1-4ef7-8b4b-9c21a7e7d3b0","type":"index-pattern"}]},"enhancements":{"dynamicActions":{"events":[]}},"hidePanelTitles":false},"title":"[Logs] Errors by host"}]', + optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', + version: 2, + timeRestore: true, + timeTo: 'now', + timeFrom: 'now-7d', + refreshInterval: { + pause: false, + value: 900000, + }, + controlGroupInput: { + controlStyle: 'oneLine', + chainingSystem: 'HIERARCHICAL', + panelsJSON: + '{"612f8db8-9ba9-41cf-a809-d133fe9b83a8":{"order":0,"width":"small","grow":true,"type":"optionsListControl","explicitInput":{"fieldName":"geo.src","title":"Source Country","id":"612f8db8-9ba9-41cf-a809-d133fe9b83a8","enhancements":{}}},"9807212f-5078-4c42-879c-6f28b3033fc9":{"order":1,"width":"small","grow":true,"type":"optionsListControl","explicitInput":{"fieldName":"machine.os.keyword","parentFieldName":"machine.os","title":"OS","id":"9807212f-5078-4c42-879c-6f28b3033fc9","enhancements":{}}},"6bf7a1b4-282e-43ac-aa46-81b97fa3acae":{"order":2,"width":"small","grow":true,"type":"rangeSliderControl","explicitInput":{"fieldName":"bytes","title":"Bytes","id":"6bf7a1b4-282e-43ac-aa46-81b97fa3acae","enhancements":{}}}}', + ignoreParentSettingsJSON: + '{"ignoreFilters":false,"ignoreQuery":false,"ignoreTimerange":false,"ignoreValidations":false}', + }, + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"query":{"language":"kuery","query":""},"highlightAll":true,"version":true,"filter":[]}', + }, + }, references: [ { - id: '06cf9c40-9ee8-11e7-8711-e7a007dcef99', name: '4:panel_4', type: 'visualization', + id: '06cf9c40-9ee8-11e7-8711-e7a007dcef99', }, { - id: '4eb6e500-e1c7-11e7-b6d5-4dc382ef7f5b', name: '9:panel_9', type: 'visualization', + id: '4eb6e500-e1c7-11e7-b6d5-4dc382ef7f5b', }, { - id: '69a34b00-9ee8-11e7-8711-e7a007dcef99', name: '11:panel_11', type: 'visualization', + id: '69a34b00-9ee8-11e7-8711-e7a007dcef99', }, { - id: '7cbd2350-2223-11e8-b802-5bcf64c2cfb4', name: '14:panel_14', type: 'visualization', + id: '7cbd2350-2223-11e8-b802-5bcf64c2cfb4', }, { - id: '314c6f60-2224-11e8-b802-5bcf64c2cfb4', name: '15:panel_15', type: 'visualization', - }, - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: '30326cdb-4ddd-49eb-a4f1-b555caa21d7c:control_30326cdb-4ddd-49eb-a4f1-b555caa21d7c_0_index_pattern', - type: 'index-pattern', - }, - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: '30326cdb-4ddd-49eb-a4f1-b555caa21d7c:control_30326cdb-4ddd-49eb-a4f1-b555caa21d7c_1_index_pattern', - type: 'index-pattern', - }, - { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - name: '30326cdb-4ddd-49eb-a4f1-b555caa21d7c:control_30326cdb-4ddd-49eb-a4f1-b555caa21d7c_2_index_pattern', - type: 'index-pattern', + id: '314c6f60-2224-11e8-b802-5bcf64c2cfb4', }, { id: '90943e30-9a47-11e8-b64d-95841ca0b247', @@ -455,9 +473,14 @@ export const getSavedObjects = (): SavedObject[] => [ type: 'index-pattern', }, { - id: 'cb099a20-ea66-11eb-9425-113343a037e3', name: '8e59c7cf-6e42-4343-a113-c4a255fcf2ce:panel_8e59c7cf-6e42-4343-a113-c4a255fcf2ce', type: 'visualization', + id: 'cb099a20-ea66-11eb-9425-113343a037e3', + }, + { + name: 'cbca842c-b9fa-4523-9ce0-14e350866e33:panel_cbca842c-b9fa-4523-9ce0-14e350866e33', + type: 'lens', + id: '16b1d7d0-ea71-11eb-8b4b-f7b600de0f7d', }, { id: '90943e30-9a47-11e8-b64d-95841ca0b247', @@ -470,38 +493,25 @@ export const getSavedObjects = (): SavedObject[] => [ type: 'index-pattern', }, { - id: '16b1d7d0-ea71-11eb-8b4b-f7b600de0f7d', - name: 'cbca842c-b9fa-4523-9ce0-14e350866e33:panel_cbca842c-b9fa-4523-9ce0-14e350866e33', - type: 'lens', + name: 'controlGroup_612f8db8-9ba9-41cf-a809-d133fe9b83a8:optionsListDataView', + type: 'index-pattern', + id: '90943e30-9a47-11e8-b64d-95841ca0b247', }, - ], - migrationVersion: { - dashboard: '7.14.0', - }, - attributes: { - title: i18n.translate('home.sampleData.logsSpec.webTrafficTitle', { - defaultMessage: '[Logs] Web Traffic', - }), - hits: 0, - description: i18n.translate('home.sampleData.logsSpec.webTrafficDescription', { - defaultMessage: "Analyze mock web traffic log data for Elastic's website", - }), - panelsJSON: - '[{"version":"8.0.0","type":"map","gridData":{"x":0,"y":19,"w":24,"h":18,"i":"4"},"panelIndex":"4","embeddableConfig":{"isLayerTOCOpen":false,"enhancements":{},"mapCenter":{"lat":42.16337,"lon":-88.92107,"zoom":3.64},"mapBuffer":{"minLon":-112.5,"minLat":21.94305,"maxLon":-45,"maxLat":55.77657},"openTOCDetails":[],"hiddenLayers":[]},"panelRefName":"panel_4"},{"version":"8.0.0","type":"visualization","gridData":{"x":0,"y":52,"w":24,"h":13,"i":"9"},"panelIndex":"9","embeddableConfig":{"mapCenter":[36.8092847020594,-96.94335937500001],"vis":{"params":{"sort":{"columnIndex":null,"direction":null}}},"enhancements":{}},"panelRefName":"panel_9"},{"version":"8.0.0","type":"visualization","gridData":{"x":12,"y":6,"w":12,"h":8,"i":"11"},"panelIndex":"11","embeddableConfig":{"vis":{"colors":{"0 - 500":"#BF1B00","1000 - 1500":"#7EB26D","500 - 1000":"#F2C96D"},"defaultColors":{"0 - 500":"rgb(165,0,38)","1000 - 1500":"rgb(0,104,55)","500 - 1000":"rgb(255,255,190)"},"legendOpen":false},"enhancements":{}},"title":"","panelRefName":"panel_11"},{"version":"8.0.0","type":"visualization","gridData":{"x":24,"y":19,"w":24,"h":33,"i":"14"},"panelIndex":"14","embeddableConfig":{"enhancements":{}},"panelRefName":"panel_14"},{"version":"8.0.0","type":"visualization","gridData":{"x":24,"y":6,"w":24,"h":13,"i":"15"},"panelIndex":"15","embeddableConfig":{"enhancements":{"dynamicActions":{"events":[]}}},"panelRefName":"panel_15"},{"version":"8.0.0","type":"visualization","gridData":{"x":0,"y":0,"w":17,"h":6,"i":"343f0bef-0b19-452e-b1c8-59beb18b6f0c"},"panelIndex":"343f0bef-0b19-452e-b1c8-59beb18b6f0c","embeddableConfig":{"savedVis":{"title":"[Logs] Markdown Instructions","description":"","type":"markdown","params":{"fontSize":12,"openLinksInNewTab":true,"markdown":"## Sample Logs Data\\nThis dashboard contains sample data for you to play with. You can view it, search it, and interact with the visualizations. For more information about Kibana, check our [docs](https://www.elastic.co/guide/en/kibana/current/index.html)."},"uiState":{},"data":{"aggs":[],"searchSource":{"query":{"query":"","language":"kuery"},"filter":[]}}},"enhancements":{},"hidePanelTitles":true}},{"version":"8.0.0","type":"visualization","gridData":{"x":17,"y":0,"w":31,"h":6,"i":"30326cdb-4ddd-49eb-a4f1-b555caa21d7c"},"panelIndex":"30326cdb-4ddd-49eb-a4f1-b555caa21d7c","embeddableConfig":{"savedVis":{"title":"[Logs] Input Controls","description":"","type":"input_control_vis","params":{"controls":[{"id":"1523980210832","fieldName":"geo.src","label":"Source Country","type":"list","options":{"type":"terms","multiselect":true,"size":100,"order":"desc"},"parent":"","indexPatternRefName":"control_30326cdb-4ddd-49eb-a4f1-b555caa21d7c_0_index_pattern"},{"id":"1523980191978","fieldName":"machine.os.keyword","label":"OS","type":"list","options":{"type":"terms","multiselect":true,"size":100,"order":"desc"},"parent":"1523980210832","indexPatternRefName":"control_30326cdb-4ddd-49eb-a4f1-b555caa21d7c_1_index_pattern"},{"id":"1523980232790","fieldName":"bytes","label":"Bytes","type":"range","options":{"decimalPlaces":0,"step":1024},"indexPatternRefName":"control_30326cdb-4ddd-49eb-a4f1-b555caa21d7c_2_index_pattern"}],"updateFiltersOnChange":true,"useTimeFilter":true,"pinFilters":false},"uiState":{},"data":{"aggs":[],"searchSource":{"query":{"query":"","language":"kuery"},"filter":[]}}},"enhancements":{},"hidePanelTitles":true}},{"version":"8.0.0","type":"lens","gridData":{"x":0,"y":6,"w":12,"h":8,"i":"bb94016e-f4a6-49ca-87a9-296a2869d570"},"panelIndex":"bb94016e-f4a6-49ca-87a9-296a2869d570","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"483defd2-775b-4a62-bdef-496c819bb8ed":{"columns":{"37430d12-7452-4cc9-b035-5cfd4061edf0":{"label":"Visits","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true}},"columnOrder":["37430d12-7452-4cc9-b035-5cfd4061edf0"],"incompleteColumns":{}}}}},"visualization":{"layerId":"483defd2-775b-4a62-bdef-496c819bb8ed","accessor":"37430d12-7452-4cc9-b035-5cfd4061edf0"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-483defd2-775b-4a62-bdef-496c819bb8ed"}]},"enhancements":{}}},{"version":"8.0.0","type":"lens","gridData":{"x":0,"y":14,"w":12,"h":5,"i":"01d8e435-91c0-484f-a11e-856747050b0a"},"panelIndex":"01d8e435-91c0-484f-a11e-856747050b0a","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"f3793bb7-3971-4753-866d-4008e77a9f9a":{"columns":{"71c076a6-e782-4866-b8df-5fd85a41f08bX0":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"response.keyword >= 400 and response.keyword < 500","language":"kuery"},"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX1":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX2":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"location":{"min":0,"max":73},"text":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()"}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08b":{"label":"HTTP 4xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"customLabel":true}},"columnOrder":["71c076a6-e782-4866-b8df-5fd85a41f08b","71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1","71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"f3793bb7-3971-4753-866d-4008e77a9f9a","accessor":"71c076a6-e782-4866-b8df-5fd85a41f08b"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-f3793bb7-3971-4753-866d-4008e77a9f9a"}]},"enhancements":{}}},{"version":"8.0.0","type":"lens","gridData":{"x":12,"y":14,"w":12,"h":5,"i":"8c1456d4-1993-4ba2-b701-04aca02c9fef"},"panelIndex":"8c1456d4-1993-4ba2-b701-04aca02c9fef","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsMetric","state":{"datasourceStates":{"indexpattern":{"layers":{"f3793bb7-3971-4753-866d-4008e77a9f9a":{"columns":{"71c076a6-e782-4866-b8df-5fd85a41f08bX0":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"response.keyword >= 500","language":"kuery"},"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX1":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08bX2":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"location":{"min":0,"max":46},"text":"count(kql=\'response.keyword >= 500\') / count()"}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1"],"customLabel":true},"71c076a6-e782-4866-b8df-5fd85a41f08b":{"label":"HTTP 5xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"customLabel":true}},"columnOrder":["71c076a6-e782-4866-b8df-5fd85a41f08b","71c076a6-e782-4866-b8df-5fd85a41f08bX0","71c076a6-e782-4866-b8df-5fd85a41f08bX1","71c076a6-e782-4866-b8df-5fd85a41f08bX2"],"incompleteColumns":{}}}}},"visualization":{"layerId":"f3793bb7-3971-4753-866d-4008e77a9f9a","accessor":"71c076a6-e782-4866-b8df-5fd85a41f08b"},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-f3793bb7-3971-4753-866d-4008e77a9f9a"}]},"enhancements":{}}},{"version":"8.0.0","type":"visualization","gridData":{"x":0,"y":37,"w":24,"h":15,"i":"8e59c7cf-6e42-4343-a113-c4a255fcf2ce"},"panelIndex":"8e59c7cf-6e42-4343-a113-c4a255fcf2ce","embeddableConfig":{"savedVis":{"title":"","description":"","type":"vega","params":{"spec":"{\\n $schema: https://vega.github.io/schema/vega-lite/v5.json\\n data: {\\n url: {\\n %context%: true\\n %timefield%: @timestamp\\n index: kibana_sample_data_logs\\n body: {\\n aggs: {\\n countries: {\\n terms: {\\n field: geo.src\\n size: 25\\n }\\n aggs: {\\n hours: {\\n histogram: {\\n field: hour_of_day\\n interval: 1\\n }\\n aggs: {\\n unique: {\\n cardinality: {\\n field: clientip\\n }\\n }\\n }\\n }\\n }\\n }\\n }\\n size: 0\\n }\\n }\\n format: {property: \\"aggregations.countries.buckets\\"}\\n }\\n \\n transform: [\\n {\\n flatten: [\\"hours.buckets\\"],\\n as: [\\"buckets\\"]\\n }\\n ]\\n\\n mark: {\\n type: rect\\n tooltip: true\\n }\\n\\n encoding: {\\n x: {\\n field: buckets.key\\n type: ordinal\\n axis: {\\n title: false\\n labelAngle: 0\\n }\\n }\\n y: {\\n field: key\\n type: nominal\\n sort: {\\n field: -buckets.unique.value\\n }\\n axis: {title: false}\\n }\\n color: {\\n field: buckets.unique.value\\n type: quantitative\\n axis: {title: false}\\n scale: {\\n scheme: reds\\n }\\n }\\n }\\n}\\n"},"uiState":{},"data":{"aggs":[],"searchSource":{"query":{"query":"","language":"kuery"},"filter":[]}}},"enhancements":{}},"panelRefName":"panel_8e59c7cf-6e42-4343-a113-c4a255fcf2ce"},{"version":"8.0.0","type":"lens","gridData":{"x":0,"y":65,"w":48,"h":19,"i":"1d5f0b3f-d9d2-4b26-997b-83bc5ca3090b"},"panelIndex":"1d5f0b3f-d9d2-4b26-997b-83bc5ca3090b","embeddableConfig":{"attributes":{"title":"","type":"lens","visualizationType":"lnsDatatable","state":{"datasourceStates":{"indexpattern":{"layers":{"c35dc8ee-50d1-4ef7-8b4b-9c21a7e7d3b0":{"columns":{"42783ad7-dbcf-4310-bc06-f21f4eaaac96":{"label":"URL","dataType":"string","operationType":"terms","scale":"ordinal","sourceField":"url.keyword","isBucketed":true,"params":{"size":1000,"orderBy":{"type":"column","columnId":"f7835375-4d5b-4839-95ea-41928192a319"},"orderDirection":"desc","otherBucket":true,"missingBucket":false},"customLabel":true},"f7835375-4d5b-4839-95ea-41928192a319":{"label":"Visits","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1daX0":{"label":"Part of HTTP 4xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"response.keyword >= 400 and response.keyword < 500","language":"kuery"},"customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1daX1":{"label":"Part of HTTP 4xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1daX2":{"label":"Part of HTTP 4xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["07fc84ca-4147-4ba9-879e-d1b4e086e1daX0","07fc84ca-4147-4ba9-879e-d1b4e086e1daX1"],"location":{"min":0,"max":73},"text":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()"}},"references":["07fc84ca-4147-4ba9-879e-d1b4e086e1daX0","07fc84ca-4147-4ba9-879e-d1b4e086e1daX1"],"customLabel":true},"07fc84ca-4147-4ba9-879e-d1b4e086e1da":{"label":"HTTP 4xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 400 and response.keyword < 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["07fc84ca-4147-4ba9-879e-d1b4e086e1daX2"],"customLabel":true},"791d5a5b-a7ba-4e9e-b533-51b33c7d7747":{"label":"Unique","dataType":"number","operationType":"unique_count","scale":"ratio","sourceField":"clientip","isBucketed":false,"customLabel":true},"611e3509-e834-4fdd-b573-44e959e95d27":{"label":"95th percentile of bytes","dataType":"number","operationType":"percentile","sourceField":"bytes","isBucketed":false,"scale":"ratio","params":{"percentile":95,"format":{"id":"bytes","params":{"decimals":0}}}},"9f79ecca-123f-4098-a658-6b0e998da003":{"label":"Median of bytes","dataType":"number","operationType":"median","sourceField":"bytes","isBucketed":false,"scale":"ratio","params":{"format":{"id":"bytes","params":{"decimals":0}}}},"491285fd-0196-402c-9b7f-4660fdc1c22aX0":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","filter":{"query":"response.keyword >= 500","language":"kuery"},"customLabel":true},"491285fd-0196-402c-9b7f-4660fdc1c22aX1":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"count","isBucketed":false,"scale":"ratio","sourceField":"Records","customLabel":true},"491285fd-0196-402c-9b7f-4660fdc1c22aX2":{"label":"Part of HTTP 5xx","dataType":"number","operationType":"math","isBucketed":false,"scale":"ratio","params":{"tinymathAst":{"type":"function","name":"divide","args":["491285fd-0196-402c-9b7f-4660fdc1c22aX0","491285fd-0196-402c-9b7f-4660fdc1c22aX1"],"location":{"min":0,"max":46},"text":"count(kql=\'response.keyword >= 500\') / count()"}},"references":["491285fd-0196-402c-9b7f-4660fdc1c22aX0","491285fd-0196-402c-9b7f-4660fdc1c22aX1"],"customLabel":true},"491285fd-0196-402c-9b7f-4660fdc1c22a":{"label":"HTTP 5xx","dataType":"number","operationType":"formula","isBucketed":false,"scale":"ratio","params":{"formula":"count(kql=\'response.keyword >= 500\') / count()","isFormulaBroken":false,"format":{"id":"percent","params":{"decimals":1}}},"references":["491285fd-0196-402c-9b7f-4660fdc1c22aX2"],"customLabel":true}},"columnOrder":["42783ad7-dbcf-4310-bc06-f21f4eaaac96","f7835375-4d5b-4839-95ea-41928192a319","791d5a5b-a7ba-4e9e-b533-51b33c7d7747","07fc84ca-4147-4ba9-879e-d1b4e086e1da","491285fd-0196-402c-9b7f-4660fdc1c22a","491285fd-0196-402c-9b7f-4660fdc1c22aX0","491285fd-0196-402c-9b7f-4660fdc1c22aX1","491285fd-0196-402c-9b7f-4660fdc1c22aX2","07fc84ca-4147-4ba9-879e-d1b4e086e1daX0","07fc84ca-4147-4ba9-879e-d1b4e086e1daX1","07fc84ca-4147-4ba9-879e-d1b4e086e1daX2","611e3509-e834-4fdd-b573-44e959e95d27","9f79ecca-123f-4098-a658-6b0e998da003"],"incompleteColumns":{}}}}},"visualization":{"layerId":"c35dc8ee-50d1-4ef7-8b4b-9c21a7e7d3b0","columns":[{"columnId":"42783ad7-dbcf-4310-bc06-f21f4eaaac96","width":650.6666666666666},{"columnId":"f7835375-4d5b-4839-95ea-41928192a319"},{"columnId":"491285fd-0196-402c-9b7f-4660fdc1c22a","isTransposed":false,"width":81.66666666666669,"colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#fbddd6","stop":0.1},{"color":"#CC5642","stop":1}],"rangeType":"number","name":"custom","colorStops":[{"color":"#fbddd6","stop":0.05},{"color":"#CC5642","stop":0.1}],"rangeMin":0.05,"rangeMax":0.1}}},{"columnId":"07fc84ca-4147-4ba9-879e-d1b4e086e1da","isTransposed":false,"colorMode":"cell","palette":{"name":"custom","type":"palette","params":{"steps":5,"stops":[{"color":"#fbddd6","stop":0.1},{"color":"#cc5642","stop":1.1}],"name":"custom","colorStops":[{"color":"#fbddd6","stop":0.05},{"color":"#cc5642","stop":0.1}],"rangeType":"number","rangeMin":0.05,"rangeMax":0.1}}},{"columnId":"791d5a5b-a7ba-4e9e-b533-51b33c7d7747","isTransposed":false},{"columnId":"611e3509-e834-4fdd-b573-44e959e95d27","isTransposed":false},{"columnId":"9f79ecca-123f-4098-a658-6b0e998da003","isTransposed":false}],"sorting":{"columnId":"491285fd-0196-402c-9b7f-4660fdc1c22a","direction":"desc"}},"query":{"query":"","language":"kuery"},"filters":[]},"references":[{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-current-indexpattern"},{"type":"index-pattern","id":"90943e30-9a47-11e8-b64d-95841ca0b247","name":"indexpattern-datasource-layer-c35dc8ee-50d1-4ef7-8b4b-9c21a7e7d3b0"}]},"enhancements":{"dynamicActions":{"events":[]}},"hidePanelTitles":false},"title":"[Logs] Errors by host"},{"version":"8.0.0","type":"lens","gridData":{"x":24,"y":52,"w":24,"h":13,"i":"cbca842c-b9fa-4523-9ce0-14e350866e33"},"panelIndex":"cbca842c-b9fa-4523-9ce0-14e350866e33","embeddableConfig":{"hidePanelTitles":false,"enhancements":{}},"title":"[Logs] Bytes distribution","panelRefName":"panel_cbca842c-b9fa-4523-9ce0-14e350866e33"}]', - optionsJSON: '{"hidePanelTitles":false,"useMargins":true}', - version: 2, - timeRestore: true, - timeTo: 'now', - timeFrom: 'now-7d', - refreshInterval: { - pause: false, - value: 900000, + { + name: 'controlGroup_9807212f-5078-4c42-879c-6f28b3033fc9:optionsListDataView', + type: 'index-pattern', + id: '90943e30-9a47-11e8-b64d-95841ca0b247', }, - kibanaSavedObjectMeta: { - searchSourceJSON: - '{"query":{"language":"kuery","query":""},"filter":[],"highlightAll":true,"version":true}', + { + name: 'controlGroup_6bf7a1b4-282e-43ac-aa46-81b97fa3acae:rangeSliderDataView', + type: 'index-pattern', + id: '90943e30-9a47-11e8-b64d-95841ca0b247', }, + ], + migrationVersion: { + dashboard: '8.5.0', }, + coreMigrationVersion: '8.6.0', }, { id: '2f360f30-ea74-11eb-b4c6-3d2afc1cb389', diff --git a/src/plugins/home/tsconfig.json b/src/plugins/home/tsconfig.json index 8e617896e3f96..af121720eee0e 100644 --- a/src/plugins/home/tsconfig.json +++ b/src/plugins/home/tsconfig.json @@ -15,6 +15,7 @@ { "path": "../kibana_react/tsconfig.json" }, { "path": "../share/tsconfig.json" }, { "path": "../url_forwarding/tsconfig.json" }, - { "path": "../usage_collection/tsconfig.json" } + { "path": "../usage_collection/tsconfig.json" }, + { "path": "../../../x-pack/plugins/cloud/tsconfig.json" } ] } diff --git a/src/plugins/inspector/public/views/requests/components/details/req_code_viewer.tsx b/src/plugins/inspector/public/views/requests/components/details/req_code_viewer.tsx index df2b3d5c88b93..5ab50ba33a514 100644 --- a/src/plugins/inspector/public/views/requests/components/details/req_code_viewer.tsx +++ b/src/plugins/inspector/public/views/requests/components/details/req_code_viewer.tsx @@ -132,7 +132,7 @@ export const RequestCodeViewer = ({ indexPattern, json }: RequestCodeViewerProps )}
- + { }; }; +const tick = (ms: number = 1) => new Promise((r) => setTimeout(r, ms)); + +const until = async (check: () => Promise, pollInterval: number = 1) => { + do { + if (await check()) return; + await tick(pollInterval); + } while (true); +}; + describe('ServerShortUrlClient', () => { describe('.create()', () => { test('can create a short URL', async () => { @@ -72,6 +81,20 @@ describe('ServerShortUrlClient', () => { }, }); }); + + test('initializes "accessDate" and "accessCount" fields on URL creation', async () => { + const { client, locator } = setup(); + const { data } = await client.create({ + locator, + slug: 'lala', + params: { + url: '/app/test#foo/bar/baz', + }, + }); + + expect(data.accessDate).toBeGreaterThan(Date.now() - 1000000); + expect(data.accessCount).toBe(0); + }); }); describe('.resolve()', () => { @@ -85,7 +108,7 @@ describe('ServerShortUrlClient', () => { }); const shortUrl2 = await client.resolve(shortUrl1.data.slug); - expect(shortUrl2.data).toMatchObject(shortUrl1.data); + expect(shortUrl2.data).toStrictEqual(shortUrl1.data); }); test('can create short URL with custom slug', async () => { @@ -128,6 +151,33 @@ describe('ServerShortUrlClient', () => { }) ).rejects.toThrowError(new UrlServiceError(`Slug "lala" already exists.`, 'SLUG_EXISTS')); }); + + test('updates "accessCount" and "accessDate" on URL resolution by slug', async () => { + const { client, locator } = setup(); + const shortUrl1 = await client.create({ + locator, + params: { + url: '/app/test#foo/bar/baz', + }, + }); + + expect(shortUrl1.data.accessDate).toBeGreaterThan(Date.now() - 1000000); + expect(shortUrl1.data.accessCount).toBe(0); + + await client.resolve(shortUrl1.data.slug); + await until(async () => (await client.get(shortUrl1.data.id)).data.accessCount === 1); + const shortUrl2 = await client.get(shortUrl1.data.id); + + expect(shortUrl2.data.accessDate).toBeGreaterThanOrEqual(shortUrl1.data.accessDate); + expect(shortUrl2.data.accessCount).toBe(1); + + await client.resolve(shortUrl1.data.slug); + await until(async () => (await client.get(shortUrl1.data.id)).data.accessCount === 2); + const shortUrl3 = await client.get(shortUrl1.data.id); + + expect(shortUrl3.data.accessDate).toBeGreaterThanOrEqual(shortUrl2.data.accessDate); + expect(shortUrl3.data.accessCount).toBe(2); + }); }); describe('.get()', () => { @@ -141,7 +191,7 @@ describe('ServerShortUrlClient', () => { }); const shortUrl2 = await client.get(shortUrl1.data.id); - expect(shortUrl2.data).toMatchObject(shortUrl1.data); + expect(shortUrl2.data).toStrictEqual(shortUrl1.data); }); test('throws when fetching non-existing short URL', async () => { diff --git a/src/plugins/share/server/url_service/short_urls/short_url_client.ts b/src/plugins/share/server/url_service/short_urls/short_url_client.ts index cecc4c3127135..096b2610b916a 100644 --- a/src/plugins/share/server/url_service/short_urls/short_url_client.ts +++ b/src/plugins/share/server/url_service/short_urls/short_url_client.ts @@ -143,12 +143,29 @@ export class ServerShortUrlClient implements IShortUrlClient { const { storage } = this.dependencies; const record = await storage.getBySlug(slug); const data = this.injectReferences(record); + this.updateAccessFields(record); return { data, }; } + /** + * Access field updates are executed in the background as we don't need to + * wait for them and confirm that they were successful. + */ + protected updateAccessFields(record: ShortUrlRecord) { + const { storage } = this.dependencies; + const { id, ...attributes } = record.data; + storage + .update(id, { + ...attributes, + accessDate: Date.now(), + accessCount: (attributes.accessCount || 0) + 1, + }) + .catch(() => {}); // We are not interested if it succeeds or not. + } + public async delete(id: string): Promise { const { storage } = this.dependencies; await storage.delete(id); 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 8497b599650b2..362ff4a209164 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 @@ -13,6 +13,7 @@ import { mountWithIntl as mount } from '@kbn/test-jest-helpers'; import { findTestSubject } from '@elastic/eui/lib/test'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { indexPatternEditorPluginMock as dataViewEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks'; import { ChangeDataView } from './change_dataview'; import { DataViewPickerPropsExtended, TextBasedLanguages } from '.'; @@ -44,6 +45,8 @@ describe('DataView component', () => { storageValue: boolean, uiSettingValue: boolean = false ) { + const dataViewEditorMock = dataViewEditorPluginMock.createStartContract(); + (dataViewEditorMock.userPermissions.editDataView as jest.Mock).mockReturnValue(true); let dataMock = dataPluginMock.createStartContract(); dataMock = { ...dataMock, @@ -56,6 +59,7 @@ describe('DataView component', () => { const services = { data: dataMock, storage: getStorage(storageValue), + dataViewEditor: dataViewEditorMock, uiSettings: { get: jest.fn(() => uiSettingValue), }, 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 72a2d8fea290f..1e71da3a0b20a 100644 --- a/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx +++ b/src/plugins/unified_search/public/dataview_picker/change_dataview.tsx @@ -72,6 +72,7 @@ export function ChangeDataView({ onTextLangQuerySubmit, textBasedLanguage, isDisabled, + onEditDataView, onCreateDefaultAdHocDataView, }: DataViewPickerPropsExtended) { const { euiTheme } = useEuiTheme(); @@ -88,7 +89,7 @@ export function ChangeDataView({ const [selectedDataViewId, setSelectedDataViewId] = useState(currentDataViewId); const kibana = useKibana(); - const { application, data, storage } = kibana.services; + const { application, data, storage, dataViews, dataViewEditor } = kibana.services; const styles = changeDataViewStyles({ fullWidth: trigger.fullWidth }); const [isTextLangTransitionModalDismissed, setIsTextLangTransitionModalDismissed] = useState(() => Boolean(storage.get(TEXT_LANG_TRANSITION_MODAL_KEY)) @@ -189,21 +190,35 @@ export function ChangeDataView({ defaultMessage: 'Add a field to this data view', })} , - { - setPopoverIsOpen(false); - application.navigateToApp('management', { - path: `/kibana/indexPatterns/patterns/${currentDataViewId}`, - }); - }} - > - {i18n.translate('unifiedSearch.query.queryBar.indexPattern.manageFieldButton', { - defaultMessage: 'Manage this data view', - })} - , + onEditDataView || dataViewEditor.userPermissions.editDataView() ? ( + { + if (onEditDataView) { + const dataView = await dataViews.get(currentDataViewId!); + dataViewEditor.openEditor({ + editData: dataView, + onSave: (updatedDataView) => { + onEditDataView(updatedDataView); + }, + }); + } else { + application.navigateToApp('management', { + path: `/kibana/indexPatterns/patterns/${currentDataViewId}`, + }); + } + setPopoverIsOpen(false); + }} + > + {i18n.translate('unifiedSearch.query.queryBar.indexPattern.manageFieldButton', { + defaultMessage: 'Manage this data view', + })} + + ) : ( + + ), ); } diff --git a/src/plugins/unified_search/public/dataview_picker/index.tsx b/src/plugins/unified_search/public/dataview_picker/index.tsx index 9fb794d58e642..8ed524b32ea12 100644 --- a/src/plugins/unified_search/public/dataview_picker/index.tsx +++ b/src/plugins/unified_search/public/dataview_picker/index.tsx @@ -41,6 +41,11 @@ export interface DataViewPickerProps { * Callback that is called when the user changes the currently selected dataview. */ onChangeDataView: (newId: string) => void; + /** + * Callback that is called when the user edits the current data view via flyout. + * The first parameter is the updated data view stub without fetched fields + */ + onEditDataView?: (updatedDataViewStub: DataView) => void; /** * The id of the selected dataview. */ @@ -98,6 +103,7 @@ export const DataViewPicker = ({ currentDataViewId, adHocDataViews, onChangeDataView, + onEditDataView, onAddField, onDataViewCreated, trigger, @@ -114,6 +120,7 @@ export const DataViewPicker = ({ isMissingCurrent={isMissingCurrent} currentDataViewId={currentDataViewId} onChangeDataView={onChangeDataView} + onEditDataView={onEditDataView} onAddField={onAddField} onDataViewCreated={onDataViewCreated} onCreateDefaultAdHocDataView={onCreateDefaultAdHocDataView} diff --git a/src/plugins/unified_search/public/filters_builder/filters_builder_utils.test.ts b/src/plugins/unified_search/public/filters_builder/filters_builder_utils.test.ts index 517a0cea4cce7..56a0eb97b80b2 100644 --- a/src/plugins/unified_search/public/filters_builder/filters_builder_utils.test.ts +++ b/src/plugins/unified_search/public/filters_builder/filters_builder_utils.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { buildEmptyFilter, Filter } from '@kbn/es-query'; +import { buildEmptyFilter, Filter, FilterItem } from '@kbn/es-query'; import { ConditionTypes } from '../utils'; import { getFilterByPath, @@ -16,7 +16,6 @@ import { moveFilter, normalizeFilters, } from './filters_builder_utils'; -import type { FilterItem } from '../utils'; import { getConditionalOperationType } from '../utils'; import { diff --git a/src/plugins/unified_search/public/filters_builder/filters_builder_utils.ts b/src/plugins/unified_search/public/filters_builder/filters_builder_utils.ts index dbbc81824a479..bc665edfbbf1d 100644 --- a/src/plugins/unified_search/public/filters_builder/filters_builder_utils.ts +++ b/src/plugins/unified_search/public/filters_builder/filters_builder_utils.ts @@ -7,10 +7,10 @@ */ import { DataViewField } from '@kbn/data-views-plugin/common'; -import type { Filter } from '@kbn/es-query'; +import type { Filter, FilterItem } from '@kbn/es-query'; import { cloneDeep } from 'lodash'; -import { ConditionTypes, getConditionalOperationType, isOrFilter, buildOrFilter } from '../utils'; -import type { FilterItem } from '../utils'; +import { buildOrFilter, isOrFilter } from '@kbn/es-query'; +import { ConditionTypes, getConditionalOperationType } from '../utils'; import type { Operator } from '../filter_bar/filter_editor'; const PATH_SEPARATOR = '.'; diff --git a/src/plugins/unified_search/public/search_bar/search_bar.test.tsx b/src/plugins/unified_search/public/search_bar/search_bar.test.tsx index b47b2d81b780c..518f9d1f16e16 100644 --- a/src/plugins/unified_search/public/search_bar/search_bar.test.tsx +++ b/src/plugins/unified_search/public/search_bar/search_bar.test.tsx @@ -10,6 +10,7 @@ import React from 'react'; import SearchBar from './search_bar'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { indexPatternEditorPluginMock as dataViewEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks'; import { I18nProvider } from '@kbn/i18n-react'; import { coreMock } from '@kbn/core/public/mocks'; @@ -83,6 +84,9 @@ function wrapSearchBarInContext(testProps: any) { intl: null as any, }; + const dataViewEditorMock = dataViewEditorPluginMock.createStartContract(); + (dataViewEditorMock.userPermissions.editDataView as jest.Mock).mockReturnValue(true); + const services = { uiSettings: startMock.uiSettings, savedObjects: startMock.savedObjects, @@ -111,6 +115,7 @@ function wrapSearchBarInContext(testProps: any) { }), }, }, + dataViewEditor: dataViewEditorMock, dataViews: { getIdsWithTitle: jest.fn(() => []), }, diff --git a/src/plugins/unified_search/public/types.ts b/src/plugins/unified_search/public/types.ts index 85f32a9d4b7e3..5142cd323c136 100755 --- a/src/plugins/unified_search/public/types.ts +++ b/src/plugins/unified_search/public/types.ts @@ -7,6 +7,7 @@ */ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import type { ScreenshotModePluginStart } from '@kbn/screenshot-mode-plugin/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; @@ -87,5 +88,6 @@ export interface IUnifiedSearchPluginServices extends Partial { docLinks: DocLinksStart; data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; + dataViewEditor: DataViewEditorStart; usageCollection?: UsageCollectionStart; } diff --git a/src/plugins/unified_search/public/utils/index.ts b/src/plugins/unified_search/public/utils/index.ts index 395304c48a914..def500dcc66e6 100644 --- a/src/plugins/unified_search/public/utils/index.ts +++ b/src/plugins/unified_search/public/utils/index.ts @@ -9,10 +9,4 @@ export { onRaf } from './on_raf'; export { shallowEqual } from './shallow_equal'; -export type { FilterItem } from './or_filter'; -export { - ConditionTypes, - isOrFilter, - getConditionalOperationType, - buildOrFilter, -} from './or_filter'; +export { ConditionTypes, getConditionalOperationType } from './or_filter'; diff --git a/src/plugins/unified_search/public/utils/or_filter.ts b/src/plugins/unified_search/public/utils/or_filter.ts index 419e4f04d74ae..f336790947d7d 100644 --- a/src/plugins/unified_search/public/utils/or_filter.ts +++ b/src/plugins/unified_search/public/utils/or_filter.ts @@ -6,20 +6,13 @@ * Side Public License, v 1. */ -// Methods from this file will be removed after they are moved to the package -import { buildEmptyFilter, Filter } from '@kbn/es-query'; +import { isOrFilter, FilterItem } from '@kbn/es-query'; export enum ConditionTypes { OR = 'OR', AND = 'AND', } -/** @internal **/ -export type FilterItem = Filter | FilterItem[]; - -/** to: @kbn/es-query **/ -export const isOrFilter = (filter: Filter) => Boolean(filter?.meta?.type === 'OR'); - /** * Defines a conditional operation type (AND/OR) from the filter otherwise returns undefined. * @param {FilterItem} filter @@ -31,17 +24,3 @@ export const getConditionalOperationType = (filter: FilterItem) => { return ConditionTypes.OR; } }; - -/** to: @kbn/es-query **/ -export const buildOrFilter = (filters: FilterItem) => { - const filter = buildEmptyFilter(false); - - return { - ...filter, - meta: { - ...filter.meta, - type: 'OR', - params: filters, - }, - }; -}; diff --git a/src/plugins/vis_types/metric/kibana.json b/src/plugins/vis_types/metric/kibana.json index ab69f78430338..4d8f776d2a0bb 100644 --- a/src/plugins/vis_types/metric/kibana.json +++ b/src/plugins/vis_types/metric/kibana.json @@ -4,11 +4,20 @@ "kibanaVersion": "kibana", "server": true, "ui": true, - "requiredPlugins": ["data", "visualizations", "charts", "expressions"], - "requiredBundles": ["visDefaultEditor"], + "requiredPlugins": [ + "data", + "visualizations", + "charts", + "expressions", + "dataViews" + ], + "requiredBundles": [ + "visDefaultEditor", + "kibanaUtils" + ], "owner": { "name": "Vis Editors", "githubTeam": "kibana-vis-editors" }, "description": "Registers the Metric aggregation-based visualization." -} +} \ No newline at end of file diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/configurations/index.test.ts b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/index.test.ts new file mode 100644 index 0000000000000..97fb145e74a2f --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/index.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ColorSchemas } from '@kbn/charts-plugin/common'; +import { getConfiguration, getPercentageModeConfig } from '.'; +import { VisParams } from '../../types'; + +const mockGetPalette = jest.fn(); + +jest.mock('./palette', () => ({ + getPalette: jest.fn(() => mockGetPalette()), +})); + +const params: VisParams = { + addTooltip: false, + addLegend: false, + dimensions: {} as VisParams['dimensions'], + metric: { + percentageMode: false, + percentageFormatPattern: '', + useRanges: true, + colorSchema: ColorSchemas.Greys, + metricColorMode: 'Labels', + colorsRange: [ + { type: 'range', from: 0, to: 100 }, + { type: 'range', from: 100, to: 200 }, + { type: 'range', from: 200, to: 300 }, + ], + labels: {}, + invertColors: false, + style: {} as VisParams['metric']['style'], + }, + type: 'metric', +}; + +describe('getPercentageModeConfig', () => { + test('should return falsy percentage mode if percentage mode is off', () => { + expect(getPercentageModeConfig(params)).toEqual({ isPercentageMode: false }); + }); + + test('should return percentage mode config', () => { + expect( + getPercentageModeConfig({ ...params, metric: { ...params.metric, percentageMode: true } }) + ).toEqual({ isPercentageMode: true, min: 0, max: 300 }); + }); +}); + +describe('getConfiguration', () => { + const palette = { name: 'custom', params: { name: 'custom' }, type: 'palette' }; + + beforeEach(() => { + jest.clearAllMocks(); + mockGetPalette.mockReturnValue(palette); + }); + + test('shourd return correct configuration', () => { + const layerId = 'layer-id'; + const metric = 'metric-id'; + const bucket = 'bucket-id'; + const collapseFn = 'sum'; + expect( + getConfiguration(layerId, params, { + metrics: [metric], + buckets: [bucket], + columnsWithoutReferenced: [], + bucketCollapseFn: { [metric]: collapseFn }, + }) + ).toEqual({ + breakdownByAccessor: bucket, + collapseFn, + layerId, + layerType: 'data', + metricAccessor: metric, + palette, + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); +}); diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/configurations/index.ts b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/index.ts new file mode 100644 index 0000000000000..39e001c1b87b8 --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/index.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Column, MetricVisConfiguration } from '@kbn/visualizations-plugin/common'; +import { PercentageModeConfig } from '@kbn/visualizations-plugin/common/convert_to_lens'; +import { VisParams } from '../../types'; +import { getPalette } from './palette'; + +export const getPercentageModeConfig = (params: VisParams): PercentageModeConfig => { + if (!params.metric.percentageMode) { + return { isPercentageMode: false }; + } + const { colorsRange } = params.metric; + return { + isPercentageMode: true, + min: colorsRange[0].from, + max: colorsRange[colorsRange.length - 1].to, + }; +}; + +export const getConfiguration = ( + layerId: string, + params: VisParams, + { + metrics, + buckets, + columnsWithoutReferenced, + bucketCollapseFn, + }: { + metrics: string[]; + buckets: string[]; + columnsWithoutReferenced: Column[]; + bucketCollapseFn?: Record; + } +): MetricVisConfiguration => { + const [metricAccessor] = metrics; + const [breakdownByAccessor] = buckets; + return { + layerId, + layerType: 'data', + palette: getPalette(params), + metricAccessor, + breakdownByAccessor, + collapseFn: Object.values(bucketCollapseFn ?? {})[0], + }; +}; diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/configurations/palette.test.ts b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/palette.test.ts new file mode 100644 index 0000000000000..7458a78b7b554 --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/palette.test.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ColorSchemas } from '@kbn/charts-plugin/common'; +import { VisParams } from '../../types'; +import { getPalette } from './palette'; + +describe('getPalette', () => { + const params: VisParams = { + addTooltip: false, + addLegend: false, + dimensions: {} as VisParams['dimensions'], + metric: { + percentageMode: false, + percentageFormatPattern: '', + useRanges: true, + colorSchema: ColorSchemas.Greys, + metricColorMode: 'Labels', + colorsRange: [ + { type: 'range', from: 0, to: 100 }, + { type: 'range', from: 100, to: 200 }, + { type: 'range', from: 200, to: 300 }, + ], + labels: {}, + invertColors: false, + style: {} as VisParams['metric']['style'], + }, + type: 'metric', + }; + + test('should return undefined if metricColorMode is `None`', () => { + const metricColorMode = 'None'; + const paramsWithNoneMetricColorMode: VisParams = { + ...params, + metric: { ...params.metric, metricColorMode }, + }; + expect(getPalette(paramsWithNoneMetricColorMode)).toBeUndefined(); + }); + + test('should return undefined if empty color ranges were passed', () => { + const paramsWithNoneMetricColorMode: VisParams = { + ...params, + metric: { ...params.metric, colorsRange: [] }, + }; + expect(getPalette(paramsWithNoneMetricColorMode)).toBeUndefined(); + }); + + test('should return correct palette', () => { + expect(getPalette(params)).toEqual({ + name: 'custom', + params: { + colorStops: [ + { color: '#FFFFFF', stop: 0 }, + { color: '#979797', stop: 100 }, + { color: '#000000', stop: 200 }, + ], + continuity: 'none', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 300, + rangeMin: 0, + rangeType: 'number', + reverse: false, + stops: [ + { color: '#FFFFFF', stop: 100 }, + { color: '#979797', stop: 200 }, + { color: '#000000', stop: 300 }, + ], + }, + type: 'palette', + }); + }); +}); diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/configurations/palette.ts b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/palette.ts new file mode 100644 index 0000000000000..360de60199efa --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/configurations/palette.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 color from 'color'; +import { CustomPaletteParams, PaletteOutput } from '@kbn/coloring'; +import { VisParams } from '../../types'; +import { getStopsWithColorsFromRanges } from '../../utils'; +import { PaletteConfig } from '../../utils/palette'; + +type ColorStopsWithMinMax = Pick< + CustomPaletteParams, + 'colorStops' | 'stops' | 'steps' | 'rangeMax' | 'rangeMin' | 'continuity' +>; + +const buildPaletteParams = ({ color: colors, stop }: PaletteConfig): ColorStopsWithMinMax => { + const colorsWithoutStartColor = colors.slice(1, colors.length); + return { + rangeMin: stop[0], + rangeMax: stop[stop.length - 1], + continuity: 'none', + colorStops: colorsWithoutStartColor.map((c, index) => ({ + color: color(c!).hex(), + stop: stop[index], + })), + stops: colorsWithoutStartColor.map((c, index) => ({ + color: color(c!).hex(), + stop: stop[index + 1], + })), + }; +}; + +const buildCustomPalette = ( + colorStopsWithMinMax: ColorStopsWithMinMax +): PaletteOutput => { + return { + name: 'custom', + params: { + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: Infinity, + rangeMin: -Infinity, + rangeType: 'number', + reverse: false, + ...colorStopsWithMinMax, + }, + type: 'palette', + }; +}; + +export const getPalette = (params: VisParams): PaletteOutput | undefined => { + const { colorSchema, colorsRange, invertColors, metricColorMode } = params.metric; + + if (metricColorMode === 'None' || !(colorsRange && colorsRange.length)) { + return; + } + + const stopsWithColors = getStopsWithColorsFromRanges(colorsRange, colorSchema, invertColors); + return buildCustomPalette(buildPaletteParams(stopsWithColors)); +}; diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/index.test.ts b/src/plugins/vis_types/metric/public/convert_to_lens/index.test.ts new file mode 100644 index 0000000000000..015b19157e91a --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/index.test.ts @@ -0,0 +1,144 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ColorSchemas } from '@kbn/charts-plugin/common'; +import { Vis } from '@kbn/visualizations-plugin/public'; +import { convertToLens } from '.'; +import { VisParams } from '../types'; + +const mockGetColumnsFromVis = jest.fn(); +const mockGetPercentageColumnFormulaColumn = jest.fn(); +const mockGetConfiguration = jest.fn().mockReturnValue({}); +const mockGetPercentageModeConfig = jest.fn(); + +jest.mock('../services', () => ({ + getDataViewsStart: jest.fn(() => ({ get: () => ({}), getDefault: () => ({}) })), +})); + +jest.mock('@kbn/visualizations-plugin/public', () => ({ + convertToLensModule: Promise.resolve({ + getColumnsFromVis: jest.fn(() => mockGetColumnsFromVis()), + getPercentageColumnFormulaColumn: jest.fn(() => mockGetPercentageColumnFormulaColumn()), + }), + getDataViewByIndexPatternId: jest.fn(() => ({ id: 'index-pattern' })), +})); + +jest.mock('./configurations', () => ({ + getConfiguration: jest.fn(() => mockGetConfiguration()), + getPercentageModeConfig: jest.fn(() => mockGetPercentageModeConfig()), +})); + +const params: VisParams = { + addTooltip: false, + addLegend: false, + dimensions: {} as VisParams['dimensions'], + metric: { + percentageMode: false, + percentageFormatPattern: '', + useRanges: false, + colorSchema: ColorSchemas.Greys, + metricColorMode: 'None', + colorsRange: [], + labels: {}, + invertColors: false, + style: { + bgFill: '', + bgColor: false, + labelColor: false, + subText: '', + fontSize: 10, + }, + }, + type: 'metric', +}; + +const vis = { + isHierarchical: () => false, + type: {}, + params, + data: {}, +} as unknown as Vis; + +const timefilter = { + getAbsoluteTime: () => {}, +} as any; + +describe('convertToLens', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should return null if getColumnsFromVis returns null', async () => { + mockGetColumnsFromVis.mockReturnValue(null); + const result = await convertToLens(vis, timefilter); + expect(mockGetColumnsFromVis).toBeCalledTimes(1); + expect(result).toBeNull(); + }); + + test('should return null if metrics count is more than 1', async () => { + mockGetColumnsFromVis.mockReturnValue({ + metrics: ['1', '2'], + columns: [{ columnId: '2' }, { columnId: '1' }], + }); + const result = await convertToLens(vis, timefilter); + expect(mockGetColumnsFromVis).toBeCalledTimes(1); + expect(result).toBeNull(); + }); + test('should return null if buckets count is more than 1', async () => { + mockGetColumnsFromVis.mockReturnValue({ + metrics: [], + buckets: ['1', '2'], + columns: [{ columnId: '2' }, { columnId: '1' }], + }); + const result = await convertToLens(vis, timefilter); + expect(mockGetColumnsFromVis).toBeCalledTimes(1); + expect(result).toBeNull(); + }); + + test('should return null if metric column data type is different from number', async () => { + mockGetColumnsFromVis.mockReturnValue({ + metrics: ['1'], + buckets: ['2'], + columns: [{ columnId: '2' }, { columnId: '1', dataType: 'string' }], + }); + const result = await convertToLens(vis, timefilter); + expect(mockGetColumnsFromVis).toBeCalledTimes(1); + expect(result).toBeNull(); + }); + test('should return correct state for valid vis', async () => { + const config = { + layerType: 'data', + metricAccessor: '1', + }; + + mockGetColumnsFromVis.mockReturnValue({ + metrics: ['1'], + buckets: ['2'], + columns: [{ columnId: '2' }, { columnId: '1', dataType: 'number' }], + columnsWithoutReferenced: [ + { columnId: '1', meta: { aggId: 'agg-1' } }, + { columnId: '2', meta: { aggId: 'agg-2' } }, + ], + }); + mockGetConfiguration.mockReturnValue(config); + + const result = await convertToLens(vis, timefilter); + expect(mockGetColumnsFromVis).toBeCalledTimes(1); + expect(mockGetConfiguration).toBeCalledTimes(1); + + expect(result?.type).toEqual('lnsMetric'); + expect(result?.layers.length).toEqual(1); + expect(result?.layers[0]).toEqual( + expect.objectContaining({ + columnOrder: [], + columns: [{ columnId: '2' }, { columnId: '1', dataType: 'number' }], + }) + ); + expect(result?.configuration).toEqual(config); + }); +}); diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/index.ts b/src/plugins/vis_types/metric/public/convert_to_lens/index.ts new file mode 100644 index 0000000000000..7675cbcc1d714 --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/index.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { Column, ColumnWithMeta } from '@kbn/visualizations-plugin/common'; +import { + convertToLensModule, + getDataViewByIndexPatternId, +} from '@kbn/visualizations-plugin/public'; +import uuid from 'uuid'; +import { getDataViewsStart } from '../services'; +import { ConvertMetricVisToLensVisualization } from './types'; + +export const isColumnWithMeta = (column: Column): column is ColumnWithMeta => { + if ((column as ColumnWithMeta).meta) { + return true; + } + return false; +}; + +export const excludeMetaFromColumn = (column: Column) => { + if (isColumnWithMeta(column)) { + const { meta, ...rest } = column; + return rest; + } + return column; +}; + +export const convertToLens: ConvertMetricVisToLensVisualization = async (vis, timefilter) => { + if (!timefilter) { + return null; + } + + const dataViews = getDataViewsStart(); + const dataView = await getDataViewByIndexPatternId(vis.data.indexPattern?.id, dataViews); + + if (!dataView) { + return null; + } + + const [{ getColumnsFromVis }, { getConfiguration, getPercentageModeConfig }] = await Promise.all([ + convertToLensModule, + import('./configurations'), + ]); + + const result = getColumnsFromVis( + vis, + timefilter, + dataView, + { + splits: ['group'], + }, + { dropEmptyRowsInDateHistogram: true, ...getPercentageModeConfig(vis.params) } + ); + + if (result === null) { + return null; + } + + // for now, multiple metrics are not supported + if (result.metrics.length > 1 || result.buckets.length > 1) { + return null; + } + + if (result.metrics[0]) { + const metric = result.columns.find(({ columnId }) => columnId === result.metrics[0]); + if (metric?.dataType !== 'number') { + return null; + } + } + + const layerId = uuid(); + const indexPatternId = dataView.id!; + + return { + type: 'lnsMetric', + layers: [ + { + indexPatternId, + layerId, + columns: result.columns.map(excludeMetaFromColumn), + columnOrder: [], + }, + ], + configuration: getConfiguration(layerId, vis.params, result), + indexPatternIds: [indexPatternId], + }; +}; diff --git a/src/plugins/vis_types/metric/public/convert_to_lens/types.ts b/src/plugins/vis_types/metric/public/convert_to_lens/types.ts new file mode 100644 index 0000000000000..3676c9dee8d9d --- /dev/null +++ b/src/plugins/vis_types/metric/public/convert_to_lens/types.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { TimefilterContract } from '@kbn/data-plugin/public'; +import { NavigateToLensContext, MetricVisConfiguration } from '@kbn/visualizations-plugin/common'; +import { Vis } from '@kbn/visualizations-plugin/public'; +import { VisParams } from '../types'; + +export type ConvertMetricVisToLensVisualization = ( + vis: Vis, + timefilter?: TimefilterContract +) => Promise | null>; diff --git a/src/plugins/vis_types/metric/public/metric_vis_type.ts b/src/plugins/vis_types/metric/public/metric_vis_type.ts index 30e13e8605b6d..b39cde5e07fc4 100644 --- a/src/plugins/vis_types/metric/public/metric_vis_type.ts +++ b/src/plugins/vis_types/metric/public/metric_vis_type.ts @@ -13,6 +13,7 @@ import { AggGroupNames } from '@kbn/data-plugin/public'; import { MetricVisOptions } from './components'; import { toExpressionAst } from './to_ast'; import { VisParams } from './types'; +import { convertToLens } from './convert_to_lens'; export const createMetricVisTypeDefinition = (): VisTypeDefinition => ({ name: 'metric', @@ -103,4 +104,10 @@ export const createMetricVisTypeDefinition = (): VisTypeDefinition => ], }, requiresSearch: true, + navigateToLens: async (vis, timefilter) => (vis ? convertToLens(vis, timefilter) : null), + getExpressionVariables: async (vis, timeFilter) => { + return { + canNavigateToLens: Boolean(vis?.params ? await convertToLens(vis, timeFilter) : null), + }; + }, }); diff --git a/src/plugins/vis_types/metric/public/plugin.ts b/src/plugins/vis_types/metric/public/plugin.ts index 9e79d1d23efda..bf8b8af0bddda 100644 --- a/src/plugins/vis_types/metric/public/plugin.ts +++ b/src/plugins/vis_types/metric/public/plugin.ts @@ -8,8 +8,10 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { VisualizationsSetup } from '@kbn/visualizations-plugin/public'; +import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { createMetricVisTypeDefinition } from './metric_vis_type'; import { ConfigSchema } from '../config'; +import { setDataViewsStart } from './services'; /** @internal */ export interface MetricVisPluginSetupDependencies { @@ -17,7 +19,14 @@ export interface MetricVisPluginSetupDependencies { } /** @internal */ -export class MetricVisPlugin implements Plugin { +export interface MetricVisPluginStartDependencies { + dataViews: DataViewsPublicPluginStart; +} + +/** @internal */ +export class MetricVisPlugin + implements Plugin +{ initializerContext: PluginInitializerContext; constructor(initializerContext: PluginInitializerContext) { @@ -28,5 +37,7 @@ export class MetricVisPlugin implements Plugin { visualizations.createBaseVisualization(createMetricVisTypeDefinition()); } - public start(core: CoreStart) {} + public start(core: CoreStart, { dataViews }: MetricVisPluginStartDependencies) { + setDataViewsStart(dataViews); + } } diff --git a/src/plugins/vis_types/metric/public/services.ts b/src/plugins/vis_types/metric/public/services.ts new file mode 100644 index 0000000000000..736ad70d49419 --- /dev/null +++ b/src/plugins/vis_types/metric/public/services.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 { createGetterSetter } from '@kbn/kibana-utils-plugin/public'; +import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; + +export const [getDataViewsStart, setDataViewsStart] = + createGetterSetter('dataViews'); diff --git a/src/plugins/vis_types/table/public/convert_to_lens/index.ts b/src/plugins/vis_types/table/public/convert_to_lens/index.ts index e236c36e82a10..1b37e36f1d982 100644 --- a/src/plugins/vis_types/table/public/convert_to_lens/index.ts +++ b/src/plugins/vis_types/table/public/convert_to_lens/index.ts @@ -54,7 +54,7 @@ export const convertToLens: ConvertTableToLensVisualization = async (vis, timefi buckets: ['bucket'], splits: ['split_row', 'split_column'], }, - { dropEmptyRowsInDateHistogram: true } + { dropEmptyRowsInDateHistogram: true, isPercentageMode: false } ); if (result === null) { diff --git a/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts b/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts index 487ad390a62dc..a0885d792ad3f 100644 --- a/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts +++ b/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts @@ -102,16 +102,9 @@ export function getTimelionRequestHandler({ const esQueryConfigs = getEsQueryConfig(uiSettings); - // parse the time range client side to make sure it behaves like other charts - const timeRangeBounds = timefilter.calculateBounds(timeRange); - const untrackSearch = - dataSearch.session.isCurrentSession(searchSessionId) && - dataSearch.session.trackSearch({ - abort: () => abortController.abort(), - }); - - try { - const searchSessionOptions = dataSearch.session.getSearchOptions(searchSessionId); + const doSearch = async ( + searchOptions: ReturnType + ): Promise => { return await http.post('/api/timelion/run', { body: JSON.stringify({ sheet: [expression], @@ -126,14 +119,40 @@ export function getTimelionRequestHandler({ interval: visParams.interval, timezone, }, - ...(searchSessionOptions && { - searchSession: searchSessionOptions, - }), + ...(searchOptions + ? { + searchSession: searchOptions, + } + : {}), }), context: executionContext, signal: abortController.signal, }); + }; + + // parse the time range client side to make sure it behaves like other charts + const timeRangeBounds = timefilter.calculateBounds(timeRange); + const searchTracker = dataSearch.session.isCurrentSession(searchSessionId) + ? dataSearch.session.trackSearch({ + abort: () => abortController.abort(), + poll: async () => { + // don't use, keep this empty, onSavingSession is used instead + }, + onSavingSession: async (searchSessionOptions) => { + await doSearch(searchSessionOptions); + }, + }) + : undefined; + + try { + const searchSessionOptions = dataSearch.session.getSearchOptions(searchSessionId); + const visData = await doSearch(searchSessionOptions); + + searchTracker?.complete(); + return visData; } catch (e) { + searchTracker?.error(); + if (e && e.body) { const err = new Error( `${i18n.translate('timelion.requestHandlerErrorTitle', { @@ -146,10 +165,6 @@ export function getTimelionRequestHandler({ throw e; } } finally { - if (untrackSearch && dataSearch.session.isCurrentSession(searchSessionId)) { - // call `untrack` if this search still belongs to current session - untrackSearch(); - } expressionAbortSignal.removeEventListener('abort', expressionAbortHandler); } }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts new file mode 100644 index 0000000000000..cbc899981717b --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.test.ts @@ -0,0 +1,171 @@ +/* + * Copyright 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 { METRIC_TYPES } from '@kbn/data-plugin/public'; +import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; +import { TSVB_METRIC_TYPES } from '../../../common/enums'; +import { Metric } from '../../../common/types'; +import { convertToLens } from '.'; +import { createPanel, createSeries } from '../lib/__mocks__'; +import { AvgColumn } from '../lib/convert'; + +const mockGetMetricsColumns = jest.fn(); +const mockGetBucketsColumns = jest.fn(); +const mockGetConfigurationForGauge = jest.fn(); +const mockIsValidMetrics = jest.fn(); +const mockGetDatasourceValue = jest + .fn() + .mockImplementation(() => Promise.resolve(stubLogstashDataView)); +const mockGetDataSourceInfo = jest.fn(); +const mockGetSeriesAgg = jest.fn(); + +jest.mock('../../services', () => ({ + getDataViewsStart: jest.fn(() => mockGetDatasourceValue), +})); + +jest.mock('../lib/series', () => ({ + getMetricsColumns: jest.fn(() => mockGetMetricsColumns()), + getBucketsColumns: jest.fn(() => mockGetBucketsColumns()), + getSeriesAgg: jest.fn(() => mockGetSeriesAgg()), +})); + +jest.mock('../lib/configurations/metric', () => ({ + getConfigurationForGauge: jest.fn(() => mockGetConfigurationForGauge()), +})); + +jest.mock('../lib/metrics', () => { + const actual = jest.requireActual('../lib/metrics'); + return { + isValidMetrics: jest.fn(() => mockIsValidMetrics()), + getReducedTimeRange: jest.fn().mockReturnValue('10'), + SUPPORTED_METRICS: actual.SUPPORTED_METRICS, + getFormulaFromMetric: actual.getFormulaFromMetric, + }; +}); + +jest.mock('../lib/datasource', () => ({ + getDataSourceInfo: jest.fn(() => mockGetDataSourceInfo()), +})); + +describe('convertToLens', () => { + const metric = { id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }; + const model = createPanel({ + series: [createSeries({ metrics: [metric] })], + }); + + const metricColumn: AvgColumn = { + columnId: 'col-id', + dataType: 'number', + isSplit: false, + isBucketed: false, + meta: { metricId: metric.id }, + operationType: 'average', + sourceField: metric.field, + params: {}, + reducedTimeRange: '10m', + }; + + beforeEach(() => { + mockIsValidMetrics.mockReturnValue(true); + mockGetDataSourceInfo.mockReturnValue({ + indexPatternId: 'test-index-pattern', + timeField: 'timeField', + indexPattern: { id: 'test-index-pattern' }, + }); + mockGetMetricsColumns.mockReturnValue([{}]); + mockGetBucketsColumns.mockReturnValue([{}]); + mockGetConfigurationForGauge.mockReturnValue({}); + mockGetSeriesAgg.mockReturnValue({ metrics: [] }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('should return null for invalid metrics', async () => { + mockIsValidMetrics.mockReturnValue(null); + const result = await convertToLens(model); + expect(result).toBeNull(); + expect(mockIsValidMetrics).toBeCalledTimes(1); + }); + + test('should return null for invalid or unsupported metrics', async () => { + mockGetMetricsColumns.mockReturnValue(null); + const result = await convertToLens(model); + expect(result).toBeNull(); + expect(mockGetMetricsColumns).toBeCalledTimes(1); + }); + + test('should return null for invalid or unsupported buckets', async () => { + mockGetBucketsColumns.mockReturnValue(null); + const result = await convertToLens(model); + expect(result).toBeNull(); + expect(mockGetBucketsColumns).toBeCalledTimes(1); + }); + + test('should return null if metric is staticValue', async () => { + const result = await convertToLens({ + ...model, + series: [ + { + ...model.series[0], + metrics: [...model.series[0].metrics, { type: TSVB_METRIC_TYPES.STATIC } as Metric], + }, + ], + }); + expect(result).toBeNull(); + expect(mockGetDataSourceInfo).toBeCalledTimes(0); + }); + + test('should return null if only series agg is specified', async () => { + const result = await convertToLens({ + ...model, + series: [ + { + ...model.series[0], + metrics: [ + { type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'min', id: 'some-id' } as Metric, + ], + }, + ], + }); + expect(result).toBeNull(); + }); + + test('should return null configuration is not valid', async () => { + mockGetMetricsColumns.mockReturnValue([metricColumn]); + mockGetSeriesAgg.mockReturnValue({ metrics: [metric] }); + mockGetConfigurationForGauge.mockReturnValue(null); + + const result = await convertToLens(model); + expect(result).toBeNull(); + }); + + test('should return state', async () => { + mockGetMetricsColumns.mockReturnValue([metricColumn]); + mockGetSeriesAgg.mockReturnValue({ metrics: [metric] }); + mockGetConfigurationForGauge.mockReturnValue({}); + + const result = await convertToLens( + createPanel({ + series: [ + createSeries({ + metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], + hidden: false, + }), + createSeries({ + metrics: [{ id: 'some-id', type: METRIC_TYPES.AVG, field: 'test-field' }], + hidden: false, + }), + ], + }) + ); + expect(result).toBeDefined(); + expect(result?.type).toBe('lnsMetric'); + }); +}); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts new file mode 100644 index 0000000000000..b97f8d59e9537 --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/gauge/index.ts @@ -0,0 +1,139 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import uuid from 'uuid'; +import { parseTimeShift } from '@kbn/data-plugin/common'; +import { + FormulaColumn, + getIndexPatternIds, + StaticValueColumn, +} from '@kbn/visualizations-plugin/common/convert_to_lens'; +import { PANEL_TYPES, TSVB_METRIC_TYPES } from '../../../common/enums'; +import { Metric } from '../../../common/types'; +import { getDataViewsStart } from '../../services'; +import { getDataSourceInfo } from '../lib/datasource'; +import { getMetricsColumns, getBucketsColumns } from '../lib/series'; +import { getConfigurationForGauge as getConfiguration } from '../lib/configurations/metric'; +import { + getFormulaFromMetric, + getReducedTimeRange, + isValidMetrics, + SUPPORTED_METRICS, +} from '../lib/metrics'; +import { ConvertTsvbToLensVisualization } from '../types'; +import { + Column, + createFormulaColumnWithoutMeta, + createStaticValueColumn, + Layer as ExtendedLayer, +} from '../lib/convert'; +import { excludeMetaFromLayers, findMetricColumn, getMetricWithCollapseFn } from '../utils'; + +const getMaxFormula = (metric: Metric, column?: Column) => { + const baseFormula = `overall_max`; + if (column && column.operationType === 'formula') { + return `${baseFormula}(${column.params.formula})`; + } + + return `${baseFormula}(${getFormulaFromMetric(SUPPORTED_METRICS[metric.type]!)}(${ + metric.field ?? '' + }))`; +}; + +export const convertToLens: ConvertTsvbToLensVisualization = async (model, timeRange) => { + const dataViews = getDataViewsStart(); + + const series = model.series[0]; + // not valid time shift + if (series.offset_time && parseTimeShift(series.offset_time) === 'invalid') { + return null; + } + + if (!isValidMetrics(series.metrics, PANEL_TYPES.GAUGE, series.time_range_mode)) { + return null; + } + + if (series.metrics[series.metrics.length - 1].type === TSVB_METRIC_TYPES.STATIC) { + return null; + } + + const reducedTimeRange = getReducedTimeRange(model, series, timeRange); + const datasourceInfo = await getDataSourceInfo( + model.index_pattern, + model.time_field, + Boolean(series.override_index_pattern), + series.series_index_pattern, + series.series_time_field, + dataViews + ); + + if (!datasourceInfo) { + return null; + } + + const { indexPatternId, indexPattern } = datasourceInfo; + + // handle multiple metrics + const metricsColumns = getMetricsColumns(series, indexPattern!, model.series.length, { + reducedTimeRange, + }); + if (metricsColumns === null) { + return null; + } + + const bucketsColumns = getBucketsColumns(model, series, metricsColumns, indexPattern!, false); + + if (bucketsColumns === null) { + return null; + } + + const [bucket] = bucketsColumns; + + const extendedLayer: ExtendedLayer = { + indexPatternId, + layerId: uuid(), + columns: [...metricsColumns, ...(bucket ? [bucket] : [])], + columnOrder: [], + }; + + const primarySeries = model.series[0]; + const primaryMetricWithCollapseFn = getMetricWithCollapseFn(primarySeries); + + if (!primaryMetricWithCollapseFn || !primaryMetricWithCollapseFn.metric) { + return null; + } + + const primaryColumn = findMetricColumn(primaryMetricWithCollapseFn.metric, extendedLayer.columns); + if (!primaryColumn) { + return null; + } + + let gaugeMaxColumn: StaticValueColumn | FormulaColumn | null = createFormulaColumnWithoutMeta( + getMaxFormula(primaryMetricWithCollapseFn.metric, primaryColumn) + ); + if (model.gauge_max !== undefined && model.gauge_max !== '') { + gaugeMaxColumn = createStaticValueColumn(model.gauge_max); + } + + const layer = { + ...extendedLayer, + columns: [...extendedLayer.columns, gaugeMaxColumn], + }; + const configuration = getConfiguration(model, layer, bucket, gaugeMaxColumn ?? undefined); + if (!configuration) { + return null; + } + + const layers = Object.values(excludeMetaFromLayers({ 0: layer })); + return { + type: 'lnsMetric', + layers, + configuration, + indexPatternIds: getIndexPatternIds(layers), + }; +}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts index a64118a1cb507..a3d08e89e91a2 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/index.ts @@ -25,6 +25,10 @@ const getConvertFnByType = (type: PANEL_TYPES) => { const { convertToLens } = await import('./metric'); return convertToLens; }, + [PANEL_TYPES.GAUGE]: async () => { + const { convertToLens } = await import('./gauge'); + return convertToLens; + }, }; return convertionFns[type]?.(); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts new file mode 100644 index 0000000000000..9cb0238f9d265 --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.test.ts @@ -0,0 +1,344 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { METRIC_TYPES } from '@kbn/data-plugin/common'; +import { TSVB_METRIC_TYPES } from '../../../../../common/enums'; +import { Column, FormulaColumn, Layer } from '../../convert'; +import { createPanel, createSeries } from '../../__mocks__'; +import { getConfigurationForMetric, getConfigurationForGauge } from '.'; + +const mockGetPalette = jest.fn(); + +jest.mock('./palette', () => ({ + getPalette: jest.fn(() => mockGetPalette()), +})); + +describe('getConfigurationForMetric', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockGetPalette.mockReturnValue(undefined); + }); + + const metricId = 'some-id'; + const metric = { id: metricId, type: METRIC_TYPES.COUNT }; + test('should return null if no series was provided', () => { + const layerId = 'layer-id-1'; + const model = createPanel({ series: [] }); + const layer: Layer = { + columns: [], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForMetric(model, layer); + + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(0); + }); + + test('should return null if only series agg', () => { + const layerId = 'layer-id-1'; + const metric1 = { id: 'metric-id-2', type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'min' }; + const model = createPanel({ + series: [createSeries({ metrics: [metric1] })], + }); + const layer: Layer = { + columns: [], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForMetric(model, layer); + + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(0); + }); + + test('should return null if multiple series aggs', () => { + const layerId = 'layer-id-1'; + const metric1 = { id: 'metric-id-1', type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'sum' }; + const metric2 = { id: 'metric-id-2', type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'min' }; + const model = createPanel({ + series: [ + createSeries({ metrics: [metric, metric1] }), + createSeries({ metrics: [metric, metric2] }), + ], + }); + const layer: Layer = { + columns: [], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForMetric(model, layer); + + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(0); + }); + + test('should return config if only one series agg is specified', () => { + const layerId = 'layer-id-1'; + const metricId1 = 'metric-id-1'; + + const metricId2 = 'metric-id-2'; + const metric1 = { id: metricId1, type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'sum' }; + const metric2 = { ...metric, id: metricId2 }; + const columnId1 = 'col-id-1'; + const columnId2 = 'col-id-2'; + + const model = createPanel({ + series: [createSeries({ metrics: [metric, metric1] }), createSeries({ metrics: [metric2] })], + }); + const layer: Layer = { + columns: [ + { + columnId: columnId1, + meta: { metricId }, + }, + { + columnId: columnId2, + meta: { metricId: metricId2 }, + }, + ] as Column[], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForMetric(model, layer); + + expect(config).toEqual({ + breakdownByAccessor: undefined, + collapseFn: 'sum', + layerId, + layerType: 'data', + metricAccessor: columnId1, + palette: undefined, + secondaryMetricAccessor: columnId2, + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); + + test('should return config for single metric', () => { + const layerId = 'layer-id-1'; + const columnId = 'col-id-1'; + const bucketColumnId = 'col-id-2'; + const model = createPanel({ + series: [createSeries({ metrics: [metric] })], + }); + const bucket = { columnId: bucketColumnId } as Column; + const layer: Layer = { + columns: [ + { + columnId, + operationType: 'count', + dataType: 'number', + params: {}, + sourceField: 'document', + isBucketed: false, + isSplit: false, + meta: { metricId }, + }, + ], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForMetric(model, layer, bucket); + + expect(config).toEqual({ + layerId, + layerType: 'data', + metricAccessor: columnId, + breakdownByAccessor: bucketColumnId, + collapseFn: undefined, + palette: undefined, + secondaryMetricAccessor: undefined, + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); + + test('should return null if palette is invalid', () => { + mockGetPalette.mockReturnValue(null); + const layerId = 'layer-id-1'; + const columnId = 'col-id-1'; + const model = createPanel({ + series: [createSeries({ metrics: [metric] })], + }); + const layer: Layer = { + columns: [ + { + columnId, + operationType: 'count', + dataType: 'number', + params: {}, + sourceField: 'document', + isBucketed: false, + isSplit: false, + meta: { metricId }, + }, + ], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForMetric(model, layer); + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(1); + }); +}); + +describe('getConfigurationForGauge', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockGetPalette.mockReturnValue(undefined); + }); + + const metricId = 'some-id'; + const maxColumnId = 'col-id-1'; + const metric = { id: metricId, type: METRIC_TYPES.COUNT }; + const gaugeMaxColumn: FormulaColumn = { + references: [], + columnId: maxColumnId, + operationType: 'formula', + isBucketed: false, + isSplit: false, + dataType: 'number', + params: { formula: '100' }, + meta: { metricId }, + }; + + test('should return null if no series was provided', () => { + const layerId = 'layer-id-1'; + const model = createPanel({ series: [] }); + const layer: Layer = { + columns: [], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForGauge(model, layer, undefined, gaugeMaxColumn); + + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(0); + }); + + test('should return null if only series agg', () => { + const layerId = 'layer-id-1'; + const metric1 = { id: 'metric-id-2', type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'min' }; + const model = createPanel({ + series: [createSeries({ metrics: [metric1] })], + }); + const layer: Layer = { + columns: [], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForGauge(model, layer, undefined, gaugeMaxColumn); + + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(0); + }); + + test('should return null if palette is invalid', () => { + mockGetPalette.mockReturnValueOnce(null); + const layerId = 'layer-id-1'; + const columnId = 'col-id-1'; + const model = createPanel({ + series: [createSeries({ metrics: [metric] })], + }); + const layer: Layer = { + columns: [ + { + columnId, + operationType: 'count', + dataType: 'number', + params: {}, + sourceField: 'document', + isBucketed: false, + isSplit: false, + meta: { metricId }, + }, + ], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForGauge(model, layer, undefined, gaugeMaxColumn); + expect(config).toBeNull(); + expect(mockGetPalette).toBeCalledTimes(1); + }); + + test('should return config with color if palette is not valid', () => { + const layerId = 'layer-id-1'; + const metric1 = { id: 'metric-id-1', type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'sum' }; + const color = '#fff'; + const model = createPanel({ series: [createSeries({ metrics: [metric, metric1], color })] }); + const layer: Layer = { + columns: [], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForGauge(model, layer, undefined, gaugeMaxColumn); + + expect(config).toEqual({ + breakdownByAccessor: undefined, + collapseFn: 'sum', + layerId: 'layer-id-1', + layerType: 'data', + metricAccessor: undefined, + palette: undefined, + maxAccessor: maxColumnId, + color: '#FFFFFF', + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); + + test('should return config with palette', () => { + const palette = { type: 'custom', name: 'default', params: {} }; + mockGetPalette.mockReturnValue(palette); + const layerId = 'layer-id-1'; + const columnId1 = 'col-id-1'; + + const metric1 = { id: 'metric-id-1', type: TSVB_METRIC_TYPES.SERIES_AGG, function: 'sum' }; + const color = '#fff'; + const model = createPanel({ series: [createSeries({ metrics: [metric, metric1], color })] }); + const bucketColumnId = 'bucket-column-id-1'; + const bucket = { columnId: bucketColumnId } as Column; + const layer: Layer = { + columns: [ + { + columnId: columnId1, + operationType: 'count', + dataType: 'number', + params: {}, + sourceField: 'document', + isBucketed: false, + isSplit: false, + meta: { metricId }, + }, + ], + columnOrder: [], + indexPatternId: 'some-index-pattern', + layerId, + }; + const config = getConfigurationForGauge(model, layer, bucket, gaugeMaxColumn); + + expect(config).toEqual({ + breakdownByAccessor: bucket.columnId, + collapseFn: 'sum', + layerId, + layerType: 'data', + metricAccessor: columnId1, + palette, + maxAccessor: maxColumnId, + }); + expect(mockGetPalette).toBeCalledTimes(1); + }); +}); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts index d1f24485d7646..7b49d604b2343 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/index.ts @@ -6,28 +6,12 @@ * Side Public License, v 1. */ +import color from 'color'; import { MetricVisConfiguration } from '@kbn/visualizations-plugin/common'; -import { Metric, Panel, Series } from '../../../../../common/types'; +import { Panel } from '../../../../../common/types'; import { Column, Layer } from '../../convert'; -import { getSeriesAgg } from '../../series'; import { getPalette } from './palette'; - -const getMetricWithCollapseFn = (series: Series | undefined) => { - if (!series) { - return; - } - const { metrics, seriesAgg } = getSeriesAgg(series.metrics); - const visibleMetric = metrics[metrics.length - 1]; - return { metric: visibleMetric, collapseFn: seriesAgg }; -}; - -const findMetricColumn = (metric: Metric | undefined, columns: Column[]) => { - if (!metric) { - return; - } - - return columns.find((column) => 'meta' in column && column.meta.metricId === metric.id); -}; +import { findMetricColumn, getMetricWithCollapseFn } from '../../../utils'; export const getConfigurationForMetric = ( model: Panel, @@ -37,7 +21,6 @@ export const getConfigurationForMetric = ( const [primarySeries, secondarySeries] = model.series.filter(({ hidden }) => !hidden); const primaryMetricWithCollapseFn = getMetricWithCollapseFn(primarySeries); - if (!primaryMetricWithCollapseFn || !primaryMetricWithCollapseFn.metric) { return null; } @@ -45,7 +28,6 @@ export const getConfigurationForMetric = ( const secondaryMetricWithCollapseFn = getMetricWithCollapseFn(secondarySeries); const primaryColumn = findMetricColumn(primaryMetricWithCollapseFn.metric, layer.columns); const secondaryColumn = findMetricColumn(secondaryMetricWithCollapseFn?.metric, layer.columns); - if (primaryMetricWithCollapseFn.collapseFn && secondaryMetricWithCollapseFn?.collapseFn) { return null; } @@ -65,3 +47,35 @@ export const getConfigurationForMetric = ( collapseFn: primaryMetricWithCollapseFn.collapseFn ?? secondaryMetricWithCollapseFn?.collapseFn, }; }; + +export const getConfigurationForGauge = ( + model: Panel, + layer: Layer, + bucket: Column | undefined, + gaugeMaxColumn: Column +): MetricVisConfiguration | null => { + const primarySeries = model.series[0]; + const primaryMetricWithCollapseFn = getMetricWithCollapseFn(primarySeries); + if (!primaryMetricWithCollapseFn || !primaryMetricWithCollapseFn.metric) { + return null; + } + + const primaryColumn = findMetricColumn(primaryMetricWithCollapseFn.metric, layer.columns); + const primaryColor = primarySeries.color ? color(primarySeries.color).hex() : undefined; + + const gaugePalette = getPalette(model.gauge_color_rules ?? [], primaryColor); + if (gaugePalette === null) { + return null; + } + + return { + layerId: layer.layerId, + layerType: 'data', + metricAccessor: primaryColumn?.columnId, + breakdownByAccessor: bucket?.columnId, + maxAccessor: gaugeMaxColumn.columnId, + palette: gaugePalette, + collapseFn: primaryMetricWithCollapseFn.collapseFn, + ...(gaugePalette ? {} : { color: primaryColor }), + }; +}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts index 827dc15ff171b..b7356f094f91a 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.test.ts @@ -9,6 +9,7 @@ import { getPalette } from './palette'; describe('getPalette', () => { + const baseColor = '#fff'; const invalidRules = [ { id: 'some-id-0' }, { id: 'some-id-1', value: 10 }, @@ -16,162 +17,346 @@ describe('getPalette', () => { { id: 'some-id-3', color: '#000' }, { id: 'some-id-4', background_color: '#000' }, ]; - test('should return undefined if no filled rules was provided', () => { - expect(getPalette([])).toBeUndefined(); - expect(getPalette(invalidRules)).toBeUndefined(); - }); - test('should return undefined if only one valid rule is provided and it is not lte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'gt', value: 100, background_color: '#000' }, - ]) - ).toBeUndefined(); - }); + describe('Metric', () => { + test('should return undefined if no filled rules was provided', () => { + expect(getPalette([])).toBeUndefined(); + expect(getPalette(invalidRules)).toBeUndefined(); + }); + + test('should return undefined if only one valid rule is provided and it is not lte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'gt', value: 100, background_color: '#000' }, + ]) + ).toBeUndefined(); + }); - test('should return custom palette if only one valid rule is provided and it is lte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'lte', value: 100, background_color: '#000' }, - ]) - ).toEqual({ - name: 'custom', - params: { - colorStops: [{ color: '#000000', stop: 100 }], - continuity: 'below', - maxSteps: 5, + test('should return custom palette if only one valid rule is provided and it is lte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'lte', value: 100, background_color: '#000' }, + ]) + ).toEqual({ name: 'custom', - progression: 'fixed', - rangeMax: 100, - rangeMin: -Infinity, - rangeType: 'number', - reverse: false, - steps: 1, - stops: [{ color: '#000000', stop: 100 }], - }, - type: 'palette', + params: { + colorStops: [{ color: '#000000', stop: 100 }], + continuity: 'below', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 100, + rangeMin: -Infinity, + rangeType: 'number', + reverse: false, + steps: 1, + stops: [{ color: '#000000', stop: 100 }], + }, + type: 'palette', + }); }); - }); - test('should return undefined if more than two types of rules', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'lte', value: 100, background_color: '#000' }, - { id: 'some-id-6', operator: 'gte', value: 150, background_color: '#000' }, - { id: 'some-id-7', operator: 'lt', value: 200, background_color: '#000' }, - ]) - ).toBeUndefined(); - }); + test('should return undefined if more than two types of rules', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'lte', value: 100, background_color: '#000' }, + { id: 'some-id-6', operator: 'gte', value: 150, background_color: '#000' }, + { id: 'some-id-7', operator: 'lt', value: 200, background_color: '#000' }, + ]) + ).toBeUndefined(); + }); - test('should return undefined if two types of rules and last rule is not lte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'gte', value: 100, background_color: '#000' }, - { id: 'some-id-7', operator: 'lt', value: 200, background_color: '#000' }, - { id: 'some-id-6', operator: 'gte', value: 150, background_color: '#000' }, - ]) - ).toBeUndefined(); - }); + test('should return undefined if two types of rules and last rule is not lte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'gte', value: 100, background_color: '#000' }, + { id: 'some-id-7', operator: 'lt', value: 200, background_color: '#000' }, + { id: 'some-id-6', operator: 'gte', value: 150, background_color: '#000' }, + ]) + ).toBeUndefined(); + }); - test('should return undefined if all rules are lte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'lte', value: 100, background_color: '#000' }, - { id: 'some-id-7', operator: 'lte', value: 200, background_color: '#000' }, - { id: 'some-id-6', operator: 'lte', value: 150, background_color: '#000' }, - ]) - ).toBeUndefined(); - }); + test('should return undefined if all rules are lte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'lte', value: 100, background_color: '#000' }, + { id: 'some-id-7', operator: 'lte', value: 200, background_color: '#000' }, + { id: 'some-id-6', operator: 'lte', value: 150, background_color: '#000' }, + ]) + ).toBeUndefined(); + }); - test('should return undefined if two types of rules and all except last one are lt and last one is not lte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'lt', value: 100, background_color: '#000' }, - { id: 'some-id-7', operator: 'gte', value: 200, background_color: '#000' }, - { id: 'some-id-6', operator: 'lt', value: 150, background_color: '#000' }, - ]) - ).toBeUndefined(); - }); + test('should return undefined if two types of rules and all except last one are lt and last one is not lte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'lt', value: 100, background_color: '#000' }, + { id: 'some-id-7', operator: 'gte', value: 200, background_color: '#000' }, + { id: 'some-id-6', operator: 'lt', value: 150, background_color: '#000' }, + ]) + ).toBeUndefined(); + }); - test('should return custom palette if two types of rules and all except last one is lt and last one is lte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'lt', value: 100, background_color: '#000' }, - { id: 'some-id-7', operator: 'lte', value: 200, background_color: '#000' }, - { id: 'some-id-6', operator: 'lt', value: 150, background_color: '#000' }, - ]) - ).toEqual({ - name: 'custom', - params: { - colorStops: [ - { color: '#000000', stop: -Infinity }, - { color: '#000000', stop: 100 }, - { color: '#000000', stop: 150 }, - ], - continuity: 'below', - maxSteps: 5, + test('should return custom palette if two types of rules and all except last one is lt and last one is lte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'lt', value: 100, background_color: '#000' }, + { id: 'some-id-7', operator: 'lte', value: 200, background_color: '#000' }, + { id: 'some-id-6', operator: 'lt', value: 150, background_color: '#000' }, + ]) + ).toEqual({ name: 'custom', - progression: 'fixed', - rangeMax: 200, - rangeMin: -Infinity, - rangeType: 'number', - reverse: false, - steps: 4, - stops: [ - { color: '#000000', stop: 100 }, - { color: '#000000', stop: 150 }, - { color: '#000000', stop: 200 }, - ], - }, - type: 'palette', + params: { + colorStops: [ + { color: '#000000', stop: -Infinity }, + { color: '#000000', stop: 100 }, + { color: '#000000', stop: 150 }, + ], + continuity: 'below', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 200, + rangeMin: -Infinity, + rangeType: 'number', + reverse: false, + steps: 4, + stops: [ + { color: '#000000', stop: 100 }, + { color: '#000000', stop: 150 }, + { color: '#000000', stop: 200 }, + ], + }, + type: 'palette', + }); + }); + + test('should return custom palette if last one is lte and all previous are gte', () => { + expect(getPalette([])).toBeUndefined(); + expect( + getPalette([ + ...invalidRules, + { id: 'some-id-5', operator: 'gte', value: 100, background_color: '#000' }, + { id: 'some-id-7', operator: 'lte', value: 200, background_color: '#000' }, + { id: 'some-id-6', operator: 'gte', value: 150, background_color: '#000' }, + ]) + ).toEqual({ + name: 'custom', + params: { + colorStops: [ + { color: '#000000', stop: 100 }, + { color: '#000000', stop: 150 }, + ], + continuity: 'none', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 200, + rangeMin: 100, + rangeType: 'number', + reverse: false, + steps: 2, + stops: [ + { color: '#000000', stop: 150 }, + { color: '#000000', stop: 200 }, + ], + }, + type: 'palette', + }); }); }); - test('should return custom palette if last one is lte and all previous are gte', () => { - expect(getPalette([])).toBeUndefined(); - expect( - getPalette([ - ...invalidRules, - { id: 'some-id-5', operator: 'gte', value: 100, background_color: '#000' }, - { id: 'some-id-7', operator: 'lte', value: 200, background_color: '#000' }, - { id: 'some-id-6', operator: 'gte', value: 150, background_color: '#000' }, - ]) - ).toEqual({ - name: 'custom', - params: { - colorStops: [ - { color: '#000000', stop: 100 }, - { color: '#000000', stop: 150 }, - ], - continuity: 'none', - maxSteps: 5, + describe('Gauge', () => { + test('should return undefined if no filled rules was provided', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect(getPalette(invalidRules, baseColor)).toBeUndefined(); + }); + + test('should return undefined if only one valid rule is provided and it is not lte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [...invalidRules, { id: 'some-id-5', operator: 'gt', value: 100, gauge: '#000' }], + baseColor + ) + ).toBeUndefined(); + }); + + test('should return custom palette if only one valid rule is provided and it is lte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [...invalidRules, { id: 'some-id-5', operator: 'lte', value: 100, gauge: '#000' }], + baseColor + ) + ).toEqual({ + name: 'custom', + params: { + colorStops: [{ color: '#000000', stop: 100 }], + continuity: 'below', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 100, + rangeMin: -Infinity, + rangeType: 'number', + reverse: false, + steps: 1, + stops: [{ color: '#000000', stop: 100 }], + }, + type: 'palette', + }); + }); + + test('should return undefined if more than two types of rules', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [ + ...invalidRules, + { id: 'some-id-5', operator: 'lte', value: 100, gauge: '#000' }, + { id: 'some-id-6', operator: 'gte', value: 150, gauge: '#000' }, + { id: 'some-id-7', operator: 'lt', value: 200, gauge: '#000' }, + ], + baseColor + ) + ).toBeUndefined(); + }); + + test('should return undefined if two types of rules and last rule is not lte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [ + ...invalidRules, + { id: 'some-id-5', operator: 'gte', value: 100, gauge: '#000' }, + { id: 'some-id-7', operator: 'lt', value: 200, gauge: '#000' }, + { id: 'some-id-6', operator: 'gte', value: 150, gauge: '#000' }, + ], + baseColor + ) + ).toBeUndefined(); + }); + + test('should return undefined if all rules are lte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [ + ...invalidRules, + { id: 'some-id-5', operator: 'lte', value: 100, gauge: '#000' }, + { id: 'some-id-7', operator: 'lte', value: 200, gauge: '#000' }, + { id: 'some-id-6', operator: 'lte', value: 150, gauge: '#000' }, + ], + baseColor + ) + ).toBeUndefined(); + }); + + test('should return undefined if two types of rules and all except last one are lt and last one is not lte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [ + ...invalidRules, + { id: 'some-id-5', operator: 'lt', value: 100, gauge: '#000' }, + { id: 'some-id-7', operator: 'gte', value: 200, gauge: '#000' }, + { id: 'some-id-6', operator: 'lt', value: 150, gauge: '#000' }, + ], + baseColor + ) + ).toBeUndefined(); + }); + + test('should return custom palette if two types of rules and all except last one is lt and last one is lte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [ + ...invalidRules, + { id: 'some-id-5', operator: 'lt', value: 100, gauge: '#000' }, + { id: 'some-id-7', operator: 'lte', value: 200, gauge: '#000' }, + { id: 'some-id-6', operator: 'lt', value: 150, gauge: '#000' }, + ], + baseColor + ) + ).toEqual({ + name: 'custom', + params: { + colorStops: [ + { color: '#000000', stop: -Infinity }, + { color: '#000000', stop: 100 }, + { color: '#000000', stop: 150 }, + ], + continuity: 'below', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 200, + rangeMin: -Infinity, + rangeType: 'number', + reverse: false, + steps: 4, + stops: [ + { color: '#000000', stop: 100 }, + { color: '#000000', stop: 150 }, + { color: '#000000', stop: 200 }, + ], + }, + type: 'palette', + }); + }); + + test('should return custom palette if last one is lte and all previous are gte', () => { + expect(getPalette([], baseColor)).toBeUndefined(); + expect( + getPalette( + [ + ...invalidRules, + { id: 'some-id-5', operator: 'gte', value: 100, gauge: '#000' }, + { id: 'some-id-7', operator: 'lte', value: 200, gauge: '#000' }, + { id: 'some-id-6', operator: 'gte', value: 150, gauge: '#000' }, + ], + baseColor + ) + ).toEqual({ name: 'custom', - progression: 'fixed', - rangeMax: 200, - rangeMin: 100, - rangeType: 'number', - reverse: false, - steps: 2, - stops: [ - { color: '#000000', stop: 150 }, - { color: '#000000', stop: 200 }, - ], - }, - type: 'palette', + params: { + colorStops: [ + { color: baseColor, stop: -Infinity }, + { color: '#000000', stop: 100 }, + { color: '#000000', stop: 150 }, + ], + continuity: 'below', + maxSteps: 5, + name: 'custom', + progression: 'fixed', + rangeMax: 200, + rangeMin: -Infinity, + rangeType: 'number', + reverse: false, + steps: 3, + stops: [ + { color: baseColor, stop: 100 }, + { color: '#000000', stop: 150 }, + { color: '#000000', stop: 200 }, + ], + }, + type: 'palette', + }); }); }); }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts index 55741c57595e7..4079ffb396647 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/metric/palette.ts @@ -22,15 +22,61 @@ type ColorStopsWithMinMax = Pick< 'colorStops' | 'stops' | 'steps' | 'rangeMax' | 'rangeMin' | 'continuity' >; +type MetricColorRules = Exclude; +type GaugeColorRules = Exclude; + +type MetricColorRule = MetricColorRules[number]; +type GaugeColorRule = GaugeColorRules[number]; + +type ValidMetricColorRule = Omit & + ( + | { + background_color: Exclude; + color: MetricColorRule['color']; + } + | { + background_color: MetricColorRule['background_color']; + color: Exclude; + } + ); + +type ValidGaugeColorRule = Omit & { + gauge: Exclude; +}; + +const isValidColorRule = ( + rule: MetricColorRule | GaugeColorRule +): rule is ValidMetricColorRule | ValidGaugeColorRule => { + const { background_color: bColor, color: textColor } = rule as MetricColorRule; + const { gauge } = rule as GaugeColorRule; + + return rule.operator && (bColor ?? textColor ?? gauge) && rule.value !== undefined ? true : false; +}; + +const isMetricColorRule = ( + rule: ValidMetricColorRule | ValidGaugeColorRule +): rule is ValidMetricColorRule => { + const metricRule = rule as ValidMetricColorRule; + return metricRule.background_color ?? metricRule.color ? true : false; +}; + +const getColor = (rule: ValidMetricColorRule | ValidGaugeColorRule) => { + if (isMetricColorRule(rule)) { + return rule.background_color ?? rule.color; + } + return rule.gauge; +}; + const getColorStopsWithMinMaxForAllGteOrWithLte = ( - rules: Exclude, - tailOperator: string + rules: Array, + tailOperator: string, + baseColor?: string ): ColorStopsWithMinMax => { const lastRule = rules[rules.length - 1]; - const lastRuleColor = (lastRule.background_color ?? lastRule.color)!; - + const lastRuleColor = getColor(lastRule); + const initRules = baseColor ? [{ stop: -Infinity, color: baseColor }] : []; const colorStops = rules.reduce((colors, rule, index, rulesArr) => { - const rgbColor = (rule.background_color ?? rule.color)!; + const rgbColor = getColor(rule); if (index === rulesArr.length - 1 && tailOperator === Operators.LTE) { return colors; } @@ -51,7 +97,7 @@ const getColorStopsWithMinMaxForAllGteOrWithLte = ( stop: rule.value!, }, ]; - }, []); + }, initRules); const stops = colorStops.reduce((prevStops, colorStop, index, colorStopsArr) => { if (index === colorStopsArr.length - 1) { @@ -68,24 +114,25 @@ const getColorStopsWithMinMaxForAllGteOrWithLte = ( const [rule] = rules; return { - rangeMin: rule.value, + rangeMin: baseColor ? -Infinity : rule.value, rangeMax: tailOperator === Operators.LTE ? lastRule.value : Infinity, colorStops, stops, steps: colorStops.length, - continuity: tailOperator === Operators.LTE ? 'none' : 'above', + continuity: + tailOperator === Operators.LTE ? (baseColor ? 'below' : 'none') : baseColor ? 'all' : 'above', }; }; const getColorStopsWithMinMaxForLtWithLte = ( - rules: Exclude + rules: Array ): ColorStopsWithMinMax => { const lastRule = rules[rules.length - 1]; const colorStops = rules.reduce((colors, rule, index, rulesArr) => { if (index === 0) { - return [{ color: color((rule.background_color ?? rule.color)!).hex(), stop: -Infinity }]; + return [{ color: color(getColor(rule)).hex(), stop: -Infinity }]; } - const rgbColor = (rule.background_color ?? rule.color)!; + const rgbColor = getColor(rule); return [ ...colors, { @@ -119,10 +166,10 @@ const getColorStopsWithMinMaxForLtWithLte = ( }; const getColorStopWithMinMaxForLte = ( - rule: Exclude[number] + rule: ValidMetricColorRule | ValidGaugeColorRule ): ColorStopsWithMinMax => { const colorStop = { - color: color((rule.background_color ?? rule.color)!).hex(), + color: color(getColor(rule)).hex(), stop: rule.value!, }; return { @@ -135,6 +182,27 @@ const getColorStopWithMinMaxForLte = ( }; }; +const getColorStopWithMinMaxForGte = ( + rule: ValidMetricColorRule | ValidGaugeColorRule, + baseColor?: string +): ColorStopsWithMinMax => { + const colorStop = { + color: color(getColor(rule)).hex(), + stop: rule.value!, + }; + return { + colorStops: [...(baseColor ? [{ color: baseColor, stop: -Infinity }] : []), colorStop], + continuity: baseColor ? 'all' : 'above', + rangeMax: Infinity, + rangeMin: baseColor ? -Infinity : colorStop.stop, + steps: 2, + stops: [ + ...(baseColor ? [{ color: baseColor, stop: colorStop.stop }] : []), + { color: colorStop.color, stop: Infinity }, + ], + }; +}; + const getCustomPalette = ( colorStopsWithMinMax: ColorStopsWithMinMax ): PaletteOutput => { @@ -156,13 +224,12 @@ const getCustomPalette = ( }; export const getPalette = ( - rules: Exclude + rules: MetricColorRules | GaugeColorRules, + baseColor?: string ): PaletteOutput | null | undefined => { - const validRules = - rules.filter( - ({ operator, color: textColor, value, background_color: bColor }) => - operator && (bColor ?? textColor) && value !== undefined - ) ?? []; + const validRules = (rules as Array).filter< + ValidMetricColorRule | ValidGaugeColorRule + >((rule): rule is ValidMetricColorRule | ValidGaugeColorRule => isValidColorRule(rule)); validRules.sort((rule1, rule2) => { return rule1.value! - rule2.value!; @@ -176,10 +243,14 @@ export const getPalette = ( // lnsMetric is supporting lte only, if one rule is defined if (validRules.length === 1) { - if (validRules[0].operator !== Operators.LTE) { - return; + if (validRules[0].operator === Operators.LTE) { + return getCustomPalette(getColorStopWithMinMaxForLte(validRules[0])); } - return getCustomPalette(getColorStopWithMinMaxForLte(validRules[0])); + + if (validRules[0].operator === Operators.GTE) { + return getCustomPalette(getColorStopWithMinMaxForGte(validRules[0], baseColor)); + } + return; } const headRules = validRules.slice(0, -1); @@ -208,7 +279,7 @@ export const getPalette = ( if (rule.operator === Operators.GTE) { return getCustomPalette( - getColorStopsWithMinMaxForAllGteOrWithLte(validRules, tailRule.operator!) + getColorStopsWithMinMaxForAllGteOrWithLte(validRules, tailRule.operator!, baseColor) ); } }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.test.ts index 6c94971397d3e..3bb4b743c2588 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.test.ts @@ -24,6 +24,33 @@ jest.mock('uuid', () => ({ v4: () => 'test-id', })); +const mockedIndices = [ + { + id: 'test', + title: 'test', + timeFieldName: 'test_field', + getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }), + }, +] as unknown as DataView[]; + +const indexPatternsService = { + getDefault: jest.fn(() => + Promise.resolve({ + id: 'default', + title: 'index', + getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }), + }) + ), + get: jest.fn((id) => Promise.resolve({ ...mockedIndices[0], id })), + find: jest.fn((search: string, size: number) => { + if (size !== 1) { + // shouldn't request more than one data view since there is a significant performance penalty + throw new Error('trying to fetch too many data views'); + } + return Promise.resolve(mockedIndices || []); + }), +} as unknown as DataViewsPublicPluginStart; + describe('getLayers', () => { const dataSourceLayers: Record = [ { @@ -83,7 +110,6 @@ describe('getLayers', () => { params: { value: '100', }, - meta: { metricId: 'metric-1' }, }, ], columnOrder: [], @@ -331,10 +357,16 @@ describe('getLayers', () => { series: [createSeries({ metrics: staticValueMetric })], }); - test.each<[string, [Record, Panel], Array>]>([ + test.each< + [ + string, + [Record, Panel, DataViewsPublicPluginStart, boolean], + Array> + ] + >([ [ 'data layer if columns do not include static column', - [dataSourceLayers, panel], + [dataSourceLayers, panel, indexPatternsService, false], [ { layerType: 'data', @@ -353,9 +385,30 @@ describe('getLayers', () => { }, ], ], + [ + 'data layer with "left" axisMode if isSingleAxis is provided', + [dataSourceLayers, panel, indexPatternsService, true], + [ + { + layerType: 'data', + accessors: ['column-id-1'], + xAccessor: 'column-id-2', + splitAccessor: 'column-id-3', + seriesType: 'area', + layerId: 'test-layer-1', + yConfig: [ + { + forAccessor: 'column-id-1', + axisMode: 'left', + color: '#68BC00', + }, + ], + }, + ], + ], [ 'reference line layer if columns include static column', - [dataSourceLayersWithStatic, panelWithStaticValue], + [dataSourceLayersWithStatic, panelWithStaticValue, indexPatternsService, false], [ { layerType: 'referenceLine', @@ -364,9 +417,10 @@ describe('getLayers', () => { yConfig: [ { forAccessor: 'column-id-1', - axisMode: 'right', + axisMode: 'left', color: '#68BC00', fill: 'below', + lineWidth: 1, }, ], }, @@ -374,7 +428,7 @@ describe('getLayers', () => { ], [ 'correct colors if columns include percentile columns', - [dataSourceLayersWithPercentile, panelWithPercentileMetric], + [dataSourceLayersWithPercentile, panelWithPercentileMetric, indexPatternsService, false], [ { yConfig: [ @@ -394,7 +448,12 @@ describe('getLayers', () => { ], [ 'correct colors if columns include percentile rank columns', - [dataSourceLayersWithPercentileRank, panelWithPercentileRankMetric], + [ + dataSourceLayersWithPercentileRank, + panelWithPercentileRankMetric, + indexPatternsService, + false, + ], [ { yConfig: [ @@ -414,7 +473,7 @@ describe('getLayers', () => { ], [ 'annotation layer gets correct params and converts color, extraFields and icons', - [dataSourceLayersWithStatic, panelWithSingleAnnotation], + [dataSourceLayersWithStatic, panelWithSingleAnnotation, indexPatternsService, false], [ { layerType: 'referenceLine', @@ -423,9 +482,10 @@ describe('getLayers', () => { yConfig: [ { forAccessor: 'column-id-1', - axisMode: 'right', + axisMode: 'left', color: '#68BC00', fill: 'below', + lineWidth: 1, }, ], }, @@ -459,7 +519,12 @@ describe('getLayers', () => { ], [ 'annotation layer should gets correct default params', - [dataSourceLayersWithStatic, panelWithSingleAnnotationWithoutQueryStringAndTimefield], + [ + dataSourceLayersWithStatic, + panelWithSingleAnnotationWithoutQueryStringAndTimefield, + indexPatternsService, + false, + ], [ { layerType: 'referenceLine', @@ -468,9 +533,10 @@ describe('getLayers', () => { yConfig: [ { forAccessor: 'column-id-1', - axisMode: 'right', + axisMode: 'left', color: '#68BC00', fill: 'below', + lineWidth: 1, }, ], }, @@ -504,7 +570,7 @@ describe('getLayers', () => { ], [ 'multiple annotations with different data views create separate layers', - [dataSourceLayersWithStatic, panelWithMultiAnnotations], + [dataSourceLayersWithStatic, panelWithMultiAnnotations, indexPatternsService, false], [ { layerType: 'referenceLine', @@ -513,9 +579,10 @@ describe('getLayers', () => { yConfig: [ { forAccessor: 'column-id-1', - axisMode: 'right', + axisMode: 'left', color: '#68BC00', fill: 'below', + lineWidth: 1, }, ], }, @@ -598,7 +665,12 @@ describe('getLayers', () => { ], [ 'annotation layer gets correct dataView when none is defined', - [dataSourceLayersWithStatic, panelWithSingleAnnotationDefaultDataView], + [ + dataSourceLayersWithStatic, + panelWithSingleAnnotationDefaultDataView, + indexPatternsService, + false, + ], [ { layerType: 'referenceLine', @@ -607,9 +679,10 @@ describe('getLayers', () => { yConfig: [ { forAccessor: 'column-id-1', - axisMode: 'right', + axisMode: 'left', color: '#68BC00', fill: 'below', + lineWidth: 1, }, ], }, @@ -642,34 +715,7 @@ describe('getLayers', () => { ], ], ])('should return %s', async (_, input, expected) => { - const layers = await getLayers(...input, indexPatternsService as DataViewsPublicPluginStart); + const layers = await getLayers(...input); expect(layers).toEqual(expected.map(expect.objectContaining)); }); }); - -const mockedIndices = [ - { - id: 'test', - title: 'test', - timeFieldName: 'test_field', - getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }), - }, -] as unknown as DataView[]; - -const indexPatternsService = { - getDefault: jest.fn(() => - Promise.resolve({ - id: 'default', - title: 'index', - getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }), - }) - ), - get: jest.fn((id) => Promise.resolve({ ...mockedIndices[0], id })), - find: jest.fn((search: string, size: number) => { - if (size !== 1) { - // shouldn't request more than one data view since there is a significant performance penalty - throw new Error('trying to fetch too many data views'); - } - return Promise.resolve(mockedIndices || []); - }), -} as unknown as DataViewsPublicPluginStart; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.ts index ec0e24e2db873..8784c2952807d 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.ts @@ -24,7 +24,7 @@ import { getDefaultQueryLanguage } from '../../../../application/components/lib/ import { fetchIndexPattern } from '../../../../../common/index_patterns_utils'; import { ICON_TYPES_MAP } from '../../../../application/visualizations/constants'; import { SUPPORTED_METRICS } from '../../metrics'; -import type { Annotation, Metric, Panel } from '../../../../../common/types'; +import type { Annotation, Metric, Panel, Series } from '../../../../../common/types'; import { getSeriesAgg } from '../../series'; import { isPercentileRanksColumnWithMeta, @@ -44,6 +44,10 @@ function getPalette(palette: PaletteOutput): PaletteOutput { : palette; } +function getAxisMode(series: Series, model: Panel): YAxisMode { + return (series.separate_axis ? series.axis_position : model.axis_position) as YAxisMode; +} + function getColor( metricColumn: Column, metric: Metric, @@ -69,7 +73,8 @@ function nonNullable(value: T): value is NonNullable { export const getLayers = async ( dataSourceLayers: Record, model: Panel, - dataViews: DataViewsPublicPluginStart + dataViews: DataViewsPublicPluginStart, + isSingleAxis: boolean = false ): Promise => { const nonAnnotationsLayers: XYLayerConfig[] = Object.keys(dataSourceLayers).map((key) => { const series = model.series[parseInt(key, 10)]; @@ -84,13 +89,13 @@ export const getLayers = async ( const metricColumns = dataSourceLayer.columns.filter( (l) => !l.isBucketed && l.columnId !== referenceColumnId ); - const isReferenceLine = metrics.length === 1 && metrics[0].type === 'static'; + const isReferenceLine = + metricColumns.length === 1 && metricColumns[0].operationType === 'static_value'; const splitAccessor = dataSourceLayer.columns.find( (column) => column.isBucketed && column.isSplit )?.columnId; const chartType = getChartType(series, model.type); const commonProps = { - seriesType: chartType, layerId: dataSourceLayer.layerId, accessors: metricColumns.map((metricColumn) => { return metricColumn.columnId; @@ -102,19 +107,19 @@ export const getLayers = async ( return { forAccessor: metricColumn.columnId, color: getColor(metricColumn, metric!, series.color, splitAccessor), - axisMode: (series.separate_axis - ? series.axis_position - : model.axis_position) as YAxisMode, + axisMode: isReferenceLine // reference line should be assigned to axis with real data + ? model.series.some((s) => s.id !== series.id && getAxisMode(s, model) === 'right') + ? 'right' + : 'left' + : isSingleAxis + ? 'left' + : getAxisMode(series, model), ...(isReferenceLine && { - fill: chartType === 'area' ? FillTypes.BELOW : FillTypes.NONE, + fill: chartType.includes('area') ? FillTypes.BELOW : FillTypes.NONE, + lineWidth: series.line_width, }), }; }), - xAccessor: dataSourceLayer.columns.find((column) => column.isBucketed && !column.isSplit) - ?.columnId, - splitAccessor, - collapseFn: seriesAgg, - palette: getPalette(series.palette as PaletteOutput), }; if (isReferenceLine) { return { @@ -123,8 +128,14 @@ export const getLayers = async ( }; } else { return { + seriesType: chartType, layerType: 'data', ...commonProps, + xAccessor: dataSourceLayer.columns.find((column) => column.isBucketed && !column.isSplit) + ?.columnId, + splitAccessor, + collapseFn: seriesAgg, + palette: getPalette(series.palette as PaletteOutput), }; } }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts index 730e770160ecd..15b35fade92c2 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts @@ -6,8 +6,12 @@ * Side Public License, v 1. */ +import uuid from 'uuid'; import { METRIC_TYPES } from '@kbn/data-plugin/public'; -import { FormulaParams } from '@kbn/visualizations-plugin/common/convert_to_lens'; +import { + FormulaParams, + FormulaColumn as BaseFormulaColumn, +} from '@kbn/visualizations-plugin/common/convert_to_lens'; import { CommonColumnConverterArgs, CommonColumnsConverterArgs, FormulaColumn } from './types'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import type { Metric } from '../../../../common/types'; @@ -39,6 +43,19 @@ export const createFormulaColumn = ( }; }; +export const createFormulaColumnWithoutMeta = (formula: string): BaseFormulaColumn => { + const params = convertToFormulaParams(formula); + return { + columnId: uuid(), + operationType: 'formula', + references: [], + dataType: 'string', + isSplit: false, + isBucketed: false, + params: { ...params }, + }; +}; + const convertFormulaScriptForPercentileAggs = ( mathScript: string, variables: Exclude, diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts index e03701e6ea153..b1b15339b37a6 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts @@ -9,7 +9,11 @@ export { isColumnWithMeta, excludeMetaFromColumn } from './column'; export { convertToPercentileColumns, isPercentileColumnWithMeta } from './percentile'; export { convertToPercentileRankColumns, isPercentileRanksColumnWithMeta } from './percentile_rank'; -export { convertMathToFormulaColumn, convertOtherAggsToFormulaColumn } from './formula'; +export { + convertMathToFormulaColumn, + convertOtherAggsToFormulaColumn, + createFormulaColumnWithoutMeta, +} from './formula'; export { convertParentPipelineAggToColumns, convertMetricAggregationColumnWithoutSpecialParams, @@ -17,7 +21,11 @@ export { export { convertToCumulativeSumColumns } from './cumulative_sum'; export { convertFilterRatioToFormulaColumn } from './filter_ratio'; export { convertToLastValueColumn } from './last_value'; -export { convertToStaticValueColumn, convertStaticValueToFormulaColumn } from './static_value'; +export { + convertToStaticValueColumn, + createStaticValueColumn, + convertStaticValueToFormulaColumn, +} from './static_value'; export { convertToFiltersColumn } from './filters'; export { convertToDateHistogramColumn } from './date_histogram'; export { convertToTermsColumn } from './terms'; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts index e03a9d7821364..d3e6aef09b1cf 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/static_value.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -import { StaticValueParams } from '@kbn/visualizations-plugin/common/convert_to_lens'; +import uuid from 'uuid'; +import { + StaticValueParams, + StaticValueColumn as BaseStaticValueColumn, +} from '@kbn/visualizations-plugin/common/convert_to_lens'; import { CommonColumnsConverterArgs, FormulaColumn, StaticValueColumn } from './types'; import type { Metric } from '../../../../common/types'; import { createColumn, getFormat } from './column'; @@ -39,6 +43,19 @@ export const convertToStaticValueColumn = ( }; }; +export const createStaticValueColumn = (staticValue: number): BaseStaticValueColumn => ({ + columnId: uuid(), + operationType: 'static_value', + references: [], + dataType: 'number', + isStaticValue: true, + isBucketed: false, + isSplit: false, + params: { + value: staticValue.toString(), + }, +}); + export const convertStaticValueToFormulaColumn = ( { series, metrics, dataView }: CommonColumnsConverterArgs, { diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts index e5b862a0fe70f..4b3b6c582f915 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/types.ts @@ -85,7 +85,13 @@ export type MovingAverageColumn = GenericColumnWithMeta; export type StaticValueColumn = GenericColumnWithMeta; -export type ColumnsWithoutMeta = FiltersColumn | TermsColumn | DateHistogramColumn; +export type ColumnsWithoutMeta = + | FiltersColumn + | TermsColumn + | DateHistogramColumn + | BaseStaticValueColumn + | BaseFormulaColumn; + export type AnyColumnWithReferences = GenericColumnWithMeta; type CommonColumns = Exclude; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts index 76d15793f4516..8be4b444be099 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/supported_metrics.ts @@ -66,6 +66,7 @@ const supportedPanelTypes: readonly PANEL_TYPES[] = [ PANEL_TYPES.TIMESERIES, PANEL_TYPES.TOP_N, PANEL_TYPES.METRIC, + PANEL_TYPES.GAUGE, ]; const supportedTimeRangeModes: readonly TIME_RANGE_DATA_MODES[] = [ diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts index 25f55b5a1c44c..149acc513b9ff 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/index.ts @@ -17,7 +17,7 @@ import { getConfigurationForMetric as getConfiguration } from '../lib/configurat import { getReducedTimeRange, isValidMetrics } from '../lib/metrics'; import { ConvertTsvbToLensVisualization } from '../types'; import { ColumnsWithoutMeta, Layer as ExtendedLayer } from '../lib/convert'; -import { excludeMetaFromLayers, getUniqueBuckets } from './utils'; +import { excludeMetaFromLayers, getUniqueBuckets } from '../utils'; const MAX_SERIES = 2; const MAX_BUCKETS = 2; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts index 50aa1a6c6f7f4..c81db38e05384 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.test.ts @@ -112,6 +112,19 @@ describe('convertToLens', () => { expect(mockGetBucketsColumns).toBeCalledTimes(1); }); + test('should return null for static value with buckets', async () => { + mockGetBucketsColumns.mockReturnValue([{}]); + mockGetMetricsColumns.mockReturnValue([ + { + operationType: 'static_value', + }, + ]); + const result = await convertToLens(model); + expect(result).toBeNull(); + expect(mockGetMetricsColumns).toBeCalledTimes(1); + expect(mockGetBucketsColumns).toBeCalledTimes(1); + }); + test('should return state for valid model', async () => { const result = await convertToLens(model); expect(result).toBeDefined(); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts index 8cbbbf0f9e739..ef678fcc2dab4 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts @@ -98,11 +98,21 @@ export const convertToLens: ConvertTsvbToLensVisualization = async (model: Panel return null; } + const isReferenceLine = + metricsColumns.length === 1 && metricsColumns[0].operationType === 'static_value'; + + // only static value without split is supported + if (isReferenceLine && bucketsColumns.length) { + return null; + } + const layerId = uuid(); extendedLayers[layerIdx] = { indexPatternId, layerId, - columns: [...metricsColumns, dateHistogramColumn, ...bucketsColumns], + columns: isReferenceLine + ? [...metricsColumns] + : [...metricsColumns, dateHistogramColumn, ...bucketsColumns], columnOrder: [], }; } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts index 020aaec28f573..130646f72f127 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts @@ -86,7 +86,7 @@ export const convertToLens: ConvertTsvbToLensVisualization = async (model, timeR }; } - const configLayers = await getLayers(extendedLayers, model, dataViews); + const configLayers = await getLayers(extendedLayers, model, dataViews, true); if (configLayers === null) { return null; } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/utils.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/utils.test.ts similarity index 97% rename from src/plugins/vis_types/timeseries/public/convert_to_lens/metric/utils.test.ts rename to src/plugins/vis_types/timeseries/public/convert_to_lens/utils.test.ts index 8f880dfe95c5e..c60370871294a 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/utils.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/utils.test.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { Column, DateHistogramColumn, TermsColumn } from '../lib/convert'; +import { Column, DateHistogramColumn, TermsColumn } from './lib/convert'; import { getUniqueBuckets } from './utils'; describe('getUniqueBuckets', () => { diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/utils.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/utils.ts similarity index 75% rename from src/plugins/vis_types/timeseries/public/convert_to_lens/metric/utils.ts rename to src/plugins/vis_types/timeseries/public/convert_to_lens/utils.ts index 8df1b0f40f8be..93fb56e39012c 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/metric/utils.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/utils.ts @@ -9,7 +9,14 @@ import { uniqWith } from 'lodash'; import deepEqual from 'react-fast-compare'; import { Layer, Operations, TermsColumn } from '@kbn/visualizations-plugin/common/convert_to_lens'; -import { Layer as ExtendedLayer, excludeMetaFromColumn, ColumnsWithoutMeta } from '../lib/convert'; +import { + Layer as ExtendedLayer, + excludeMetaFromColumn, + ColumnsWithoutMeta, + Column, +} from './lib/convert'; +import { getSeriesAgg } from './lib/series'; +import { Metric, Series } from '../../common/types'; export const excludeMetaFromLayers = ( layers: Record @@ -63,3 +70,20 @@ export const getUniqueBuckets = (buckets: ColumnsWithoutMeta[]) => return deepEqual(bucketWithoutColumnIds1, bucketWithoutColumnIds2); }); + +export const getMetricWithCollapseFn = (series: Series | undefined) => { + if (!series) { + return; + } + const { metrics, seriesAgg } = getSeriesAgg(series.metrics); + const visibleMetric = metrics[metrics.length - 1]; + return { metric: visibleMetric, collapseFn: seriesAgg }; +}; + +export const findMetricColumn = (metric: Metric | undefined, columns: Column[]) => { + if (!metric) { + return; + } + + return columns.find((column) => 'meta' in column && column.meta.metricId === metric.id); +}; diff --git a/src/plugins/vis_types/timeseries/public/request_handler.ts b/src/plugins/vis_types/timeseries/public/request_handler.ts index 24768dc10a17f..4512034d3b124 100644 --- a/src/plugins/vis_types/timeseries/public/request_handler.ts +++ b/src/plugins/vis_types/timeseries/public/request_handler.ts @@ -49,33 +49,46 @@ export const metricsRequestHandler = async ({ const dataSearch = data.search; const parsedTimeRange = data.query.timefilter.timefilter.calculateBounds(input?.timeRange!); + const doSearch = async ( + searchOptions: ReturnType + ): Promise => { + return await getCoreStart().http.post(ROUTES.VIS_DATA, { + body: JSON.stringify({ + timerange: { + timezone, + ...parsedTimeRange, + }, + query: input?.query, + filters: input?.filters, + panels: [visParams], + state: uiStateObj, + ...(searchOptions + ? { + searchSession: searchOptions, + } + : {}), + }), + context: executionContext, + signal: abortController.signal, + }); + }; + if (visParams && visParams.id && !visParams.isModelInvalid && !expressionAbortSignal.aborted) { - const untrackSearch = - dataSearch.session.isCurrentSession(searchSessionId) && - dataSearch.session.trackSearch({ - abort: () => abortController.abort(), - }); + const searchTracker = dataSearch.session.isCurrentSession(searchSessionId) + ? dataSearch.session.trackSearch({ + abort: () => abortController.abort(), + poll: async () => { + // don't use, keep this empty, onSavingSession is used instead + }, + onSavingSession: async (searchSessionOptions) => { + await doSearch(searchSessionOptions); + }, + }) + : undefined; try { const searchSessionOptions = dataSearch.session.getSearchOptions(searchSessionId); - - const visData: TimeseriesVisData = await getCoreStart().http.post(ROUTES.VIS_DATA, { - body: JSON.stringify({ - timerange: { - timezone, - ...parsedTimeRange, - }, - query: input?.query, - filters: input?.filters, - panels: [visParams], - state: uiStateObj, - ...(searchSessionOptions && { - searchSession: searchSessionOptions, - }), - }), - context: executionContext, - signal: abortController.signal, - }); + const visData: TimeseriesVisData = await doSearch(searchSessionOptions); inspectorAdapters?.requests?.reset(); @@ -86,12 +99,12 @@ export const metricsRequestHandler = async ({ .ok({ time: query.time, json: { rawResponse: query.response } }); }); + searchTracker?.complete(); + return visData; + } catch (e) { + searchTracker?.error(); } finally { - if (untrackSearch && dataSearch.session.isCurrentSession(searchSessionId)) { - // untrack if this search still belongs to current session - untrackSearch(); - } expressionAbortSignal.removeEventListener('abort', expressionAbortHandler); } } diff --git a/src/plugins/visualizations/common/convert_to_lens/lib/convert/column.ts b/src/plugins/visualizations/common/convert_to_lens/lib/convert/column.ts index b1ac46dd36a20..7fe98b9f7ec65 100644 --- a/src/plugins/visualizations/common/convert_to_lens/lib/convert/column.ts +++ b/src/plugins/visualizations/common/convert_to_lens/lib/convert/column.ts @@ -25,7 +25,7 @@ export const createColumn = ( { isBucketed = false, isSplit = false, reducedTimeRange }: ExtraColumnFields = {} ): GeneralColumnWithMeta => ({ columnId: uuid(), - dataType: (field?.type as DataType) ?? undefined, + dataType: (field?.type as DataType) ?? 'number', label: getLabel(agg), isBucketed, isSplit, diff --git a/src/plugins/visualizations/common/convert_to_lens/lib/convert/index.ts b/src/plugins/visualizations/common/convert_to_lens/lib/convert/index.ts index b77ea6b97209a..9da33607be2a9 100644 --- a/src/plugins/visualizations/common/convert_to_lens/lib/convert/index.ts +++ b/src/plugins/visualizations/common/convert_to_lens/lib/convert/index.ts @@ -20,3 +20,4 @@ export * from './terms'; export * from './types'; export * from './last_value'; export * from './range'; +export * from './percentage_mode'; diff --git a/src/plugins/visualizations/common/convert_to_lens/lib/convert/percentage_mode.test.ts b/src/plugins/visualizations/common/convert_to_lens/lib/convert/percentage_mode.test.ts new file mode 100644 index 0000000000000..3b7e8ad7e797f --- /dev/null +++ b/src/plugins/visualizations/common/convert_to_lens/lib/convert/percentage_mode.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { METRIC_TYPES } from '@kbn/data-plugin/common'; +import { stubLogstashDataView } from '@kbn/data-views-plugin/common/data_view.stub'; +import { SchemaConfig } from '../../..'; +import { convertToColumnInPercentageMode } from './percentage_mode'; + +const mockGetFormulaForAgg = jest.fn(); + +jest.mock('../metrics/formula', () => ({ + getFormulaForAgg: jest.fn(() => mockGetFormulaForAgg()), +})); + +describe('convertToColumnInPercentageMode', () => { + const formula = 'average(some_field)'; + const dataView = stubLogstashDataView; + + const agg: SchemaConfig = { + accessor: 0, + label: '', + format: { + id: undefined, + params: undefined, + }, + params: {}, + aggType: METRIC_TYPES.AVG, + aggParams: { + field: dataView.fields[0].displayName, + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + mockGetFormulaForAgg.mockReturnValue(formula); + }); + + test('should return null if it is not possible to build the valid formula', () => { + mockGetFormulaForAgg.mockReturnValue(null); + expect(convertToColumnInPercentageMode({ agg, dataView, aggs: [agg] }, {})).toBeNull(); + }); + + test('should return percentage mode over range formula if min and max was passed', () => { + const formulaColumn = { + operationType: 'formula', + params: { format: { id: 'percent' }, formula: `((${formula}) - 0) / (100 - 0)` }, + }; + expect( + convertToColumnInPercentageMode({ agg, dataView, aggs: [agg] }, { min: 0, max: 100 }) + ).toEqual(expect.objectContaining(formulaColumn)); + }); + + test('should return percentage mode formula if min and max was not passed', () => { + const formulaColumn = { + operationType: 'formula', + params: { format: { id: 'percent' }, formula: `(${formula}) / 10000` }, + }; + expect(convertToColumnInPercentageMode({ agg, dataView, aggs: [agg] }, {})).toEqual( + expect.objectContaining(formulaColumn) + ); + }); +}); diff --git a/src/plugins/visualizations/common/convert_to_lens/lib/convert/percentage_mode.ts b/src/plugins/visualizations/common/convert_to_lens/lib/convert/percentage_mode.ts new file mode 100644 index 0000000000000..df49635c97636 --- /dev/null +++ b/src/plugins/visualizations/common/convert_to_lens/lib/convert/percentage_mode.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 { METRIC_TYPES } from '@kbn/data-plugin/common'; +import { MinMax } from '../../types'; +import { getFormulaForAgg } from '../metrics/formula'; +import { createFormulaColumn } from './formula'; +import { ExtendedColumnConverterArgs } from './types'; + +const getPercentageFormulaOverRange = (formula: string, { min, max }: MinMax) => + `((${formula}) - ${min}) / (${max} - ${min})`; + +// Lens is multiplying by 100, so, it is necessary to disable that operation. +const getPercentageFormula = (formula: string) => `(${formula}) / 10000`; + +const isMinMax = (minMax: MinMax | {}): minMax is MinMax => { + if ((minMax as MinMax).min !== undefined && (minMax as MinMax).max !== undefined) { + return true; + } + return false; +}; + +export const convertToColumnInPercentageMode = ( + columnConverterArgs: ExtendedColumnConverterArgs, + minMax: MinMax | {} +) => { + if (columnConverterArgs.agg.aggType === METRIC_TYPES.TOP_HITS) { + return null; + } + + const formula = getFormulaForAgg(columnConverterArgs); + if (formula === null) { + return null; + } + + const percentageModeFormula = isMinMax(minMax) + ? getPercentageFormulaOverRange(formula, minMax) + : getPercentageFormula(formula); + + const column = createFormulaColumn(percentageModeFormula, columnConverterArgs.agg); + if (column === null) { + return null; + } + return { + ...column, + params: { ...column?.params, format: { id: 'percent' } }, + }; +}; diff --git a/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.test.ts b/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.test.ts index 659ab80ea03d5..207dedd133bc9 100644 --- a/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.test.ts +++ b/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.test.ts @@ -19,6 +19,7 @@ const mockConvertToSiblingPipelineColumns = jest.fn(); const mockConvertToStdDeviationFormulaColumns = jest.fn(); const mockConvertToLastValueColumn = jest.fn(); const mockConvertToCumulativeSumAggColumn = jest.fn(); +const mockConvertToColumnInPercentageMode = jest.fn(); jest.mock('../convert', () => ({ convertMetricAggregationColumnWithoutSpecialParams: jest.fn(() => @@ -33,6 +34,7 @@ jest.mock('../convert', () => ({ convertToStdDeviationFormulaColumns: jest.fn(() => mockConvertToStdDeviationFormulaColumns()), convertToLastValueColumn: jest.fn(() => mockConvertToLastValueColumn()), convertToCumulativeSumAggColumn: jest.fn(() => mockConvertToCumulativeSumAggColumn()), + convertToColumnInPercentageMode: jest.fn(() => mockConvertToColumnInPercentageMode()), })); describe('convertMetricToColumns invalid cases', () => { @@ -56,145 +58,265 @@ describe('convertMetricToColumns invalid cases', () => { test.each<[string, Parameters, null, jest.Mock | undefined]>([ [ 'null if agg is not supported', - [{ aggType: METRIC_TYPES.GEO_BOUNDS } as unknown as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.GEO_BOUNDS } as unknown as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, undefined, ], [ 'null if supported agg AVG is not valid', - [{ aggType: METRIC_TYPES.AVG } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.AVG } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg MIN is not valid', - [{ aggType: METRIC_TYPES.MIN } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MIN } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg MAX is not valid', - [{ aggType: METRIC_TYPES.MAX } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MAX } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg SUM is not valid', - [{ aggType: METRIC_TYPES.SUM } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SUM } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg COUNT is not valid', - [{ aggType: METRIC_TYPES.COUNT } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.COUNT } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg CARDINALITY is not valid', - [{ aggType: METRIC_TYPES.CARDINALITY } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.CARDINALITY } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg VALUE_COUNT is not valid', - [{ aggType: METRIC_TYPES.VALUE_COUNT } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.VALUE_COUNT } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg MEDIAN is not valid', - [{ aggType: METRIC_TYPES.MEDIAN } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MEDIAN } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'null if supported agg STD_DEV is not valid', - [{ aggType: METRIC_TYPES.STD_DEV } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.STD_DEV } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToStdDeviationFormulaColumns, ], [ 'null if supported agg PERCENTILES is not valid', - [{ aggType: METRIC_TYPES.PERCENTILES } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.PERCENTILES } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToPercentileColumn, ], [ 'null if supported agg SINGLE_PERCENTILE is not valid', - [{ aggType: METRIC_TYPES.SINGLE_PERCENTILE } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SINGLE_PERCENTILE } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToPercentileColumn, ], [ 'null if supported agg PERCENTILE_RANKS is not valid', - [{ aggType: METRIC_TYPES.PERCENTILE_RANKS } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.PERCENTILE_RANKS } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToPercentileRankColumn, ], [ 'null if supported agg SINGLE_PERCENTILE_RANK is not valid', - [{ aggType: METRIC_TYPES.SINGLE_PERCENTILE_RANK } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SINGLE_PERCENTILE_RANK } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToPercentileRankColumn, ], [ 'null if supported agg TOP_HITS is not valid', - [{ aggType: METRIC_TYPES.TOP_HITS } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.TOP_HITS } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToLastValueColumn, ], [ 'null if supported agg TOP_METRICS is not valid', - [{ aggType: METRIC_TYPES.TOP_METRICS } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.TOP_METRICS } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToLastValueColumn, ], [ 'null if supported agg CUMULATIVE_SUM is not valid', - [{ aggType: METRIC_TYPES.CUMULATIVE_SUM } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.CUMULATIVE_SUM } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToCumulativeSumAggColumn, ], [ 'null if supported agg DERIVATIVE is not valid', - [{ aggType: METRIC_TYPES.DERIVATIVE } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.DERIVATIVE } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToOtherParentPipelineAggColumns, ], [ 'null if supported agg MOVING_FN is not valid', - [{ aggType: METRIC_TYPES.MOVING_FN } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MOVING_FN } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToOtherParentPipelineAggColumns, ], [ 'null if supported agg SUM_BUCKET is not valid', - [{ aggType: METRIC_TYPES.SUM_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SUM_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToSiblingPipelineColumns, ], [ 'null if supported agg MIN_BUCKET is not valid', - [{ aggType: METRIC_TYPES.MIN_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MIN_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToSiblingPipelineColumns, ], [ 'null if supported agg MAX_BUCKET is not valid', - [{ aggType: METRIC_TYPES.MAX_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MAX_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToSiblingPipelineColumns, ], [ 'null if supported agg AVG_BUCKET is not valid', - [{ aggType: METRIC_TYPES.AVG_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.AVG_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, mockConvertToSiblingPipelineColumns, ], [ 'null if supported agg SERIAL_DIFF is not valid', - [{ aggType: METRIC_TYPES.SERIAL_DIFF } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SERIAL_DIFF } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], null, undefined, ], @@ -224,141 +346,274 @@ describe('convertMetricToColumns valid cases', () => { mockConvertToStdDeviationFormulaColumns.mockReturnValue(result); mockConvertToLastValueColumn.mockReturnValue(result); mockConvertToCumulativeSumAggColumn.mockReturnValue(result); + mockConvertToColumnInPercentageMode.mockReturnValue(result); }); test.each<[string, Parameters, Array<{}>, jest.Mock]>([ [ 'array of columns if supported agg AVG is valid', - [{ aggType: METRIC_TYPES.AVG } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.AVG } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg MIN is valid', - [{ aggType: METRIC_TYPES.MIN } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MIN } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg MAX is valid', - [{ aggType: METRIC_TYPES.MAX } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MAX } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg SUM is valid', - [{ aggType: METRIC_TYPES.SUM } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SUM } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg COUNT is valid', - [{ aggType: METRIC_TYPES.COUNT } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.COUNT } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg CARDINALITY is valid', - [{ aggType: METRIC_TYPES.CARDINALITY } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.CARDINALITY } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg VALUE_COUNT is valid', - [{ aggType: METRIC_TYPES.VALUE_COUNT } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.VALUE_COUNT } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg MEDIAN is valid', - [{ aggType: METRIC_TYPES.MEDIAN } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MEDIAN } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertMetricAggregationColumnWithoutSpecialParams, ], [ 'array of columns if supported agg STD_DEV is valid', - [{ aggType: METRIC_TYPES.STD_DEV } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.STD_DEV } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToStdDeviationFormulaColumns, ], [ 'array of columns if supported agg PERCENTILES is valid', - [{ aggType: METRIC_TYPES.PERCENTILES } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.PERCENTILES } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToPercentileColumn, ], [ 'array of columns if supported agg SINGLE_PERCENTILE is valid', - [{ aggType: METRIC_TYPES.SINGLE_PERCENTILE } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SINGLE_PERCENTILE } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToPercentileColumn, ], [ 'array of columns if supported agg PERCENTILE_RANKS is valid', - [{ aggType: METRIC_TYPES.PERCENTILE_RANKS } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.PERCENTILE_RANKS } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToPercentileRankColumn, ], [ 'array of columns if supported agg SINGLE_PERCENTILE_RANK is valid', - [{ aggType: METRIC_TYPES.SINGLE_PERCENTILE_RANK } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SINGLE_PERCENTILE_RANK } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToPercentileRankColumn, ], [ 'array of columns if supported agg TOP_HITS is valid', - [{ aggType: METRIC_TYPES.TOP_HITS } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.TOP_HITS } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToLastValueColumn, ], [ 'array of columns if supported agg TOP_METRICS is valid', - [{ aggType: METRIC_TYPES.TOP_METRICS } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.TOP_METRICS } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToLastValueColumn, ], [ 'array of columns if supported agg CUMULATIVE_SUM is valid', - [{ aggType: METRIC_TYPES.CUMULATIVE_SUM } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.CUMULATIVE_SUM } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToCumulativeSumAggColumn, ], [ 'array of columns if supported agg DERIVATIVE is valid', - [{ aggType: METRIC_TYPES.DERIVATIVE } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.DERIVATIVE } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToOtherParentPipelineAggColumns, ], [ 'array of columns if supported agg MOVING_FN is valid', - [{ aggType: METRIC_TYPES.MOVING_FN } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MOVING_FN } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToOtherParentPipelineAggColumns, ], [ 'array of columns if supported agg SUM_BUCKET is valid', - [{ aggType: METRIC_TYPES.SUM_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.SUM_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToSiblingPipelineColumns, ], [ 'array of columns if supported agg MIN_BUCKET is valid', - [{ aggType: METRIC_TYPES.MIN_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MIN_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToSiblingPipelineColumns, ], [ 'array of columns if supported agg MAX_BUCKET is valid', - [{ aggType: METRIC_TYPES.MAX_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.MAX_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToSiblingPipelineColumns, ], [ 'array of columns if supported agg AVG_BUCKET is valid', - [{ aggType: METRIC_TYPES.AVG_BUCKET } as SchemaConfig, dataView, []], + [ + { aggType: METRIC_TYPES.AVG_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: false }, + ], result, mockConvertToSiblingPipelineColumns, ], + [ + 'column in percentage mode without range if percentageMode is enabled ', + [ + { aggType: METRIC_TYPES.AVG_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: true }, + ], + result, + mockConvertToColumnInPercentageMode, + ], + [ + 'column in percentage mode with range if percentageMode is enabled ', + [ + { aggType: METRIC_TYPES.AVG_BUCKET } as SchemaConfig, + dataView, + [], + { isPercentageMode: true, min: 0, max: 100 }, + ], + result, + mockConvertToColumnInPercentageMode, + ], ])('should return %s', (_, input, expected, mock) => { expect(convertMetricToColumns(...input)).toEqual(expected.map(expect.objectContaining)); if (mock) { diff --git a/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.ts b/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.ts index d97f81c4c8240..be4c92cd4ec7f 100644 --- a/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.ts +++ b/src/plugins/visualizations/common/convert_to_lens/lib/metrics/metrics.ts @@ -8,7 +8,7 @@ import { METRIC_TYPES } from '@kbn/data-plugin/common'; import type { DataView } from '@kbn/data-views-plugin/common'; -import { SchemaConfig } from '../../..'; +import { PercentageModeConfig, SchemaConfig } from '../../..'; import { convertMetricAggregationColumnWithoutSpecialParams, convertToOtherParentPipelineAggColumns, @@ -19,20 +19,29 @@ import { convertToLastValueColumn, convertToCumulativeSumAggColumn, AggBasedColumn, + convertToColumnInPercentageMode, } from '../convert'; import { SUPPORTED_METRICS } from '../convert/supported_metrics'; import { getValidColumns } from '../utils'; export const convertMetricToColumns = ( - agg: SchemaConfig, + agg: SchemaConfig, dataView: DataView, - aggs: Array> + aggs: Array>, + percentageModeConfig: PercentageModeConfig = { isPercentageMode: false } ): AggBasedColumn[] | null => { const supportedAgg = SUPPORTED_METRICS[agg.aggType]; if (!supportedAgg) { return null; } + if (percentageModeConfig.isPercentageMode) { + const { isPercentageMode, ...minMax } = percentageModeConfig; + + const formulaColumn = convertToColumnInPercentageMode({ agg, dataView, aggs }, minMax); + return getValidColumns(formulaColumn); + } + switch (agg.aggType) { case METRIC_TYPES.AVG: case METRIC_TYPES.MIN: @@ -119,8 +128,6 @@ export const convertMetricToColumns = ( }); return getValidColumns(columns); } - case METRIC_TYPES.SERIAL_DIFF: - return null; default: return null; } diff --git a/src/plugins/visualizations/common/convert_to_lens/types/common.ts b/src/plugins/visualizations/common/convert_to_lens/types/common.ts index d792467e298d0..c526a7116877d 100644 --- a/src/plugins/visualizations/common/convert_to_lens/types/common.ts +++ b/src/plugins/visualizations/common/convert_to_lens/types/common.ts @@ -45,3 +45,12 @@ export interface NumberValueFormat { suffix?: string; }; } + +export interface MinMax { + min: number; + max: number; +} + +export type PercentageModeConfig = + | ({ isPercentageMode: true } & MinMax) + | { isPercentageMode: boolean }; diff --git a/src/plugins/visualizations/public/convert_to_lens/schemas.ts b/src/plugins/visualizations/public/convert_to_lens/schemas.ts index 56108b1a1d63f..ecfbbf34ad9c9 100644 --- a/src/plugins/visualizations/public/convert_to_lens/schemas.ts +++ b/src/plugins/visualizations/public/convert_to_lens/schemas.ts @@ -8,7 +8,7 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import { METRIC_TYPES, TimefilterContract } from '@kbn/data-plugin/public'; -import { AggBasedColumn, SchemaConfig } from '../../common'; +import { AggBasedColumn, PercentageModeConfig, SchemaConfig } from '../../common'; import { convertMetricToColumns } from '../../common/convert_to_lens/lib/metrics'; import { convertBucketToColumns } from '../../common/convert_to_lens/lib/buckets'; import { getCustomBucketsFromSiblingAggs } from '../../common/convert_to_lens/lib/utils'; @@ -46,8 +46,11 @@ export const getColumnsFromVis = ( } = {}, config?: { dropEmptyRowsInDateHistogram?: boolean; - } + } & (PercentageModeConfig | void) ) => { + const { dropEmptyRowsInDateHistogram, ...percentageModeConfig } = config ?? { + isPercentageMode: false, + }; const visSchemas = getVisSchemas(vis, { timefilter, timeRange: timefilter.getAbsoluteTime(), @@ -67,8 +70,8 @@ export const getColumnsFromVis = ( const metricsWithoutDuplicates = getMetricsWithoutDuplicates(visSchemas.metric); const aggs = metricsWithoutDuplicates as Array>; - const metricColumns = metricsWithoutDuplicates.flatMap((m) => - convertMetricToColumns(m, dataView, aggs) + const metricColumns = aggs.flatMap((m) => + convertMetricToColumns(m, dataView, aggs, percentageModeConfig) ); if (metricColumns.includes(null)) { @@ -81,7 +84,7 @@ export const getColumnsFromVis = ( const customBucketColumn = convertBucketToColumns( { agg: customBuckets[0], dataView, metricColumns: metrics, aggs }, false, - config?.dropEmptyRowsInDateHistogram + dropEmptyRowsInDateHistogram ); if (!customBucketColumn) { return null; @@ -95,7 +98,7 @@ export const getColumnsFromVis = ( dataView, false, metricColumns as AggBasedColumn[], - config?.dropEmptyRowsInDateHistogram + dropEmptyRowsInDateHistogram ); if (!bucketColumns) { return null; @@ -107,7 +110,7 @@ export const getColumnsFromVis = ( dataView, true, metricColumns as AggBasedColumn[], - config?.dropEmptyRowsInDateHistogram + dropEmptyRowsInDateHistogram ); if (!splitBucketColumns) { return null; diff --git a/test/analytics/tests/instrumented_events/from_the_browser/loaded_dashboard.ts b/test/analytics/tests/instrumented_events/from_the_browser/loaded_dashboard.ts index 0522ab5b41c2c..7b21a5637d167 100644 --- a/test/analytics/tests/instrumented_events/from_the_browser/loaded_dashboard.ts +++ b/test/analytics/tests/instrumented_events/from_the_browser/loaded_dashboard.ts @@ -26,7 +26,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dashboardAddPanel = getService('dashboardAddPanel'); const queryBar = getService('queryBar'); - describe('Loaded Dashboard', () => { + // Failing: See https://github.com/elastic/kibana/issues/142548 + describe.skip('Loaded Dashboard', () => { let fromTimestamp: string | undefined; const getEvents = async (count: number, options?: GetEventsOptions) => @@ -200,7 +201,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); expect(event.properties.key2).to.be('num_of_panels'); - expect(event.properties.value2).to.be(17); + expect(event.properties.value2).to.be(16); }); /** diff --git a/test/api_integration/apis/saved_objects/find.ts b/test/api_integration/apis/saved_objects/find.ts index 4afcc4f162a62..5c11b6f74d7ae 100644 --- a/test/api_integration/apis/saved_objects/find.ts +++ b/test/api_integration/apis/saved_objects/find.ts @@ -338,6 +338,131 @@ export default function ({ getService }: FtrProviderContext) { }); }); + describe('`has_no_reference` and `has_no_reference_operator` parameters', () => { + before(async () => { + await kibanaServer.importExport.load( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/references.json', + { space: SPACE_ID } + ); + }); + after(async () => { + await kibanaServer.importExport.unload( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/references.json', + { space: SPACE_ID } + ); + }); + + it('search for objects not containing a reference', async () => { + await supertest + .get(`/s/${SPACE_ID}/api/saved_objects/_find`) + .query({ + type: 'visualization', + has_no_reference: JSON.stringify({ type: 'ref-type', id: 'ref-1' }), + }) + .expect(200) + .then((resp) => { + const objects = resp.body.saved_objects; + const ids = objects.map((obj: SavedObject) => obj.id); + expect(ids).to.contain('only-ref-2'); + expect(ids).to.contain('only-ref-3'); + expect(ids).not.to.contain('only-ref-1'); + expect(ids).not.to.contain('ref-1-and-ref-2'); + }); + }); + + it('search for multiple references with OR operator', async () => { + await supertest + .get(`/s/${SPACE_ID}/api/saved_objects/_find`) + .query({ + type: 'visualization', + has_no_reference: JSON.stringify([ + { type: 'ref-type', id: 'ref-1' }, + { type: 'ref-type', id: 'ref-2' }, + ]), + has_no_reference_operator: 'OR', + }) + .expect(200) + .then((resp) => { + const objects = resp.body.saved_objects; + const ids = objects.map((obj: SavedObject) => obj.id); + + expect(ids).to.contain('only-ref-3'); + expect(ids).not.to.contain('only-ref-1'); + expect(ids).not.to.contain('only-ref-2'); + expect(ids).not.to.contain('ref-1-and-ref-2'); + }); + }); + + it('search for multiple references with AND operator', async () => { + await supertest + .get(`/s/${SPACE_ID}/api/saved_objects/_find`) + .query({ + type: 'visualization', + has_no_reference: JSON.stringify([ + { type: 'ref-type', id: 'ref-1' }, + { type: 'ref-type', id: 'ref-2' }, + ]), + has_no_reference_operator: 'AND', + }) + .expect(200) + .then((resp) => { + const objects = resp.body.saved_objects; + const ids = objects.map((obj: SavedObject) => obj.id); + expect(ids).to.contain('only-ref-1'); + expect(ids).to.contain('only-ref-2'); + expect(ids).to.contain('only-ref-3'); + expect(ids).not.to.contain('ref-1-and-ref-2'); + }); + }); + }); + + describe('with both `has_reference` and `has_no_reference` parameters', () => { + before(async () => { + await kibanaServer.importExport.load( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/references.json', + { space: SPACE_ID } + ); + }); + after(async () => { + await kibanaServer.importExport.unload( + 'test/api_integration/fixtures/kbn_archiver/saved_objects/references.json', + { space: SPACE_ID } + ); + }); + + it('search for objects containing a reference and excluding another reference', async () => { + await supertest + .get(`/s/${SPACE_ID}/api/saved_objects/_find`) + .query({ + type: 'visualization', + has_reference: JSON.stringify({ type: 'ref-type', id: 'ref-1' }), + has_no_reference: JSON.stringify({ type: 'ref-type', id: 'ref-2' }), + }) + .expect(200) + .then((resp) => { + const objects = resp.body.saved_objects; + const ids = objects.map((obj: SavedObject) => obj.id); + expect(ids).to.eql(['only-ref-1']); + }); + }); + + it('search for objects with same reference passed to `has_reference` and `has_no_reference`', async () => { + await supertest + .get(`/s/${SPACE_ID}/api/saved_objects/_find`) + .query({ + type: 'visualization', + has_reference: JSON.stringify({ type: 'ref-type', id: 'ref-1' }), + has_no_reference: JSON.stringify({ type: 'ref-type', id: 'ref-1' }), + }) + .expect(200) + .then((resp) => { + const objects = resp.body.saved_objects; + const ids = objects.map((obj: SavedObject) => obj.id); + expect(ids).to.eql([]); + }); + }); + }); + describe('searching for special characters', () => { before(async () => { await kibanaServer.importExport.load( diff --git a/test/functional/apps/home/_sample_data.ts b/test/functional/apps/home/_sample_data.ts index 7b362aefc609d..4120a9ecc1a54 100644 --- a/test/functional/apps/home/_sample_data.ts +++ b/test/functional/apps/home/_sample_data.ts @@ -95,7 +95,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); const panelCount = await PageObjects.dashboard.getPanelCount(); - expect(panelCount).to.be(17); + expect(panelCount).to.be(16); }); it('should render visualizations', async () => { @@ -107,7 +107,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { log.debug('Checking saved searches rendered'); await dashboardExpect.savedSearchRowCount(10); log.debug('Checking input controls rendered'); - await dashboardExpect.inputControlItemCount(3); + await dashboardExpect.controlCount(3); log.debug('Checking tag cloud rendered'); await dashboardExpect.tagCloudWithValuesFound(['Sunny', 'Rain', 'Clear', 'Cloudy', 'Hail']); log.debug('Checking vega chart rendered'); @@ -119,7 +119,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); const panelCount = await PageObjects.dashboard.getPanelCount(); - expect(panelCount).to.be(13); + expect(panelCount).to.be(12); }); it('should launch sample ecommerce data set dashboard', async () => { @@ -127,7 +127,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await renderable.waitForRender(); const panelCount = await PageObjects.dashboard.getPanelCount(); - expect(panelCount).to.be(15); + expect(panelCount).to.be(14); }); }); diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts index 73c49525ef4a1..6e20e5b574202 100644 --- a/test/functional/services/dashboard/expectations.ts +++ b/test/functional/services/dashboard/expectations.ts @@ -281,6 +281,7 @@ export class DashboardExpectService extends FtrService { }); } + // legacy controls visualization async inputControlItemCount(expectedCount: number) { this.log.debug(`DashboardExpect.inputControlItemCount(${expectedCount})`); await this.retry.try(async () => { @@ -289,6 +290,14 @@ export class DashboardExpectService extends FtrService { }); } + async controlCount(expectedCount: number) { + this.log.debug(`DashboardExpect.controlCount(${expectedCount})`); + await this.retry.try(async () => { + const controls = await this.testSubjects.findAll('control-frame'); + expect(controls.length).to.be(expectedCount); + }); + } + async lineChartPointsCount(expectedCount: number) { this.log.debug(`DashboardExpect.lineChartPointsCount(${expectedCount})`); await this.retry.try(async () => { diff --git a/test/functional/services/dashboard/panel_actions.ts b/test/functional/services/dashboard/panel_actions.ts index 17c2ffee733b2..79370e8e6af6a 100644 --- a/test/functional/services/dashboard/panel_actions.ts +++ b/test/functional/services/dashboard/panel_actions.ts @@ -179,6 +179,14 @@ export class DashboardPanelActionsService extends FtrService { return searchSessionId; } + async getSearchResponseByTitle(title: string) { + await this.openInspectorByTitle(title); + await this.inspector.openInspectorRequestsView(); + const response = await this.inspector.getResponse(); + await this.inspector.close(); + return response; + } + async openInspector(parent?: WebElementWrapper) { await this.openContextMenu(parent); const exists = await this.testSubjects.exists(OPEN_INSPECTOR_TEST_SUBJ); diff --git a/test/functional/services/inspector.ts b/test/functional/services/inspector.ts index 1917fa6dcdc50..0a7468a5b9be4 100644 --- a/test/functional/services/inspector.ts +++ b/test/functional/services/inspector.ts @@ -17,6 +17,7 @@ export class InspectorService extends FtrService { private readonly testSubjects = this.ctx.getService('testSubjects'); private readonly find = this.ctx.getService('find'); private readonly comboBox = this.ctx.getService('comboBox'); + private readonly monacoEditor = this.ctx.getService('monacoEditor'); private async getIsEnabled(): Promise { const ariaDisabled = await this.testSubjects.getAttribute('openInspectorButton', 'disabled'); @@ -212,6 +213,7 @@ export class InspectorService extends FtrService { * Opens inspector requests view */ public async openInspectorRequestsView(): Promise { + if (!(await this.testSubjects.exists('inspectorViewChooser'))) return; await this.openInspectorView('Requests'); } @@ -253,6 +255,15 @@ export class InspectorService extends FtrService { return this.testSubjects.find('inspectorRequestDetailResponse'); } + public async getResponse(): Promise> { + await (await this.getOpenRequestDetailResponseButton()).click(); + + await this.monacoEditor.waitCodeEditorReady('inspectorRequestCodeViewerContainer'); + const responseString = await this.monacoEditor.getCodeEditorValue(); + this.log.debug('Response string from inspector:', responseString); + return JSON.parse(responseString); + } + /** * Returns true if the value equals the combobox options list * @param value default combobox single option text diff --git a/test/interpreter_functional/snapshots/baseline/combined_test3.json b/test/interpreter_functional/snapshots/baseline/combined_test3.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/baseline/combined_test3.json +++ b/test/interpreter_functional/snapshots/baseline/combined_test3.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/final_output_test.json b/test/interpreter_functional/snapshots/baseline/final_output_test.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/baseline/final_output_test.json +++ b/test/interpreter_functional/snapshots/baseline/final_output_test.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_all_data.json b/test/interpreter_functional/snapshots/baseline/metric_all_data.json index 1c7a6cb857ed1..3b8553435624f 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_all_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_all_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"bytes","params":null},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"bytes","params":null},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_empty_data.json b/test/interpreter_functional/snapshots/baseline/metric_empty_data.json index 1f93a487bee2b..ef645bdb30afd 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_empty_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_empty_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json index 78135325fac66..90d572ab720f0 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"number"},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"number"},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json index 4ff228305a1d6..2bb96cbcb4c0a 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json index 7a91e2cae2bab..2c9c785e4ab2a 100644 --- a/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/baseline/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/partial_test_2.json b/test/interpreter_functional/snapshots/baseline/partial_test_2.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/baseline/partial_test_2.json +++ b/test/interpreter_functional/snapshots/baseline/partial_test_2.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/baseline/step_output_test3.json b/test/interpreter_functional/snapshots/baseline/step_output_test3.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/baseline/step_output_test3.json +++ b/test/interpreter_functional/snapshots/baseline/step_output_test3.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/combined_test3.json b/test/interpreter_functional/snapshots/session/combined_test3.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/session/combined_test3.json +++ b/test/interpreter_functional/snapshots/session/combined_test3.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/final_output_test.json b/test/interpreter_functional/snapshots/session/final_output_test.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/session/final_output_test.json +++ b/test/interpreter_functional/snapshots/session/final_output_test.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_all_data.json b/test/interpreter_functional/snapshots/session/metric_all_data.json index 1c7a6cb857ed1..3b8553435624f 100644 --- a/test/interpreter_functional/snapshots/session/metric_all_data.json +++ b/test/interpreter_functional/snapshots/session/metric_all_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"bytes","params":null},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":2,"format":{"id":"bytes","params":null},"type":"vis_dimension"},"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_empty_data.json b/test/interpreter_functional/snapshots/session/metric_empty_data.json index 1f93a487bee2b..ef645bdb30afd 100644 --- a/test/interpreter_functional/snapshots/session/metric_empty_data.json +++ b/test/interpreter_functional/snapshots/session/metric_empty_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json index 78135325fac66..90d572ab720f0 100644 --- a/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json +++ b/test/interpreter_functional/snapshots/session/metric_multi_metric_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"number"},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},{"accessor":1,"format":{"id":"number"},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json index 4ff228305a1d6..2bb96cbcb4c0a 100644 --- a/test/interpreter_functional/snapshots/session/metric_percentage_mode.json +++ b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":{"colors":["rgb(0,0,0,0)","rgb(100, 100, 100)"],"continuity":"none","gradient":false,"range":"number","rangeMax":10000,"rangeMin":0,"stops":[0,10000]},"percentageMode":true,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json index 7a91e2cae2bab..2c9c785e4ab2a 100644 --- a/test/interpreter_functional/snapshots/session/metric_single_metric_data.json +++ b/test/interpreter_functional/snapshots/session/metric_single_metric_data.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"metrics":[{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"},{"id":"col-2-1","meta":{"field":"bytes","index":"logstash-*","params":{"id":"bytes","params":null},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"field":"bytes"},"schema":"metric","type":"max"},"type":"number"},"name":"Max bytes"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891,"col-2-1":19986},{"col-0-2":"404","col-1-1":696,"col-2-1":19881},{"col-0-2":"503","col-1-1":417,"col-2-1":0}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/partial_test_2.json b/test/interpreter_functional/snapshots/session/partial_test_2.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/session/partial_test_2.json +++ b/test/interpreter_functional/snapshots/session/partial_test_2.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/interpreter_functional/snapshots/session/step_output_test3.json b/test/interpreter_functional/snapshots/session/step_output_test3.json index 49daaed3c5b85..922d266f7e187 100644 --- a/test/interpreter_functional/snapshots/session/step_output_test3.json +++ b/test/interpreter_functional/snapshots/session/step_output_test3.json @@ -1 +1 @@ -{"as":"legacyMetricVis","type":"render","value":{"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file +{"as":"legacyMetricVis","type":"render","value":{"canNavigateToLens":false,"visConfig":{"dimensions":{"bucket":{"accessor":0,"format":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"type":"vis_dimension"},"metrics":[{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"}]},"metric":{"autoScale":null,"colorFullBackground":false,"labels":{"position":"bottom","show":true,"style":{"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:24px;line-height:1","spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"24px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}},"metricColorMode":"None","palette":null,"percentageMode":false,"style":{"bgColor":false,"css":"font-family:'Open Sans', Helvetica, Arial, sans-serif;font-weight:normal;font-style:normal;text-decoration:none;text-align:center;font-size:60px;line-height:1","labelColor":false,"spec":{"fontFamily":"'Open Sans', Helvetica, Arial, sans-serif","fontSize":"60px","fontStyle":"normal","fontWeight":"normal","lineHeight":"1","textAlign":"center","textDecoration":"none"},"type":"style"}}},"visData":{"columns":[{"id":"col-0-2","meta":{"field":"response.raw","index":"logstash-*","params":{"id":"terms","params":{"id":"string","missingBucketLabel":"Missing","otherBucketLabel":"Other"}},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"2","indexPatternId":"logstash-*","params":{"excludeIsRegex":true,"field":"response.raw","includeIsRegex":true,"missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"schema":"segment","type":"terms"},"type":"string"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"field":null,"index":"logstash-*","params":{"id":"number"},"source":"esaggs","sourceParams":{"appliedTimeRange":null,"enabled":true,"hasPrecisionError":false,"id":"1","indexPatternId":"logstash-*","params":{"emptyAsNull":false},"schema":"metric","type":"count"},"type":"number"},"name":"Count"}],"meta":{"source":"logstash-*","statistics":{"totalCount":14004},"type":"esaggs"},"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"datatable"},"visType":"metric"}} \ No newline at end of file diff --git a/test/plugin_functional/config.ts b/test/plugin_functional/config.ts index b2dbc762ab657..750da63e27d1c 100644 --- a/test/plugin_functional/config.ts +++ b/test/plugin_functional/config.ts @@ -60,6 +60,14 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { '--corePluginDeprecations.noLongerUsed=still_using', // for testing set buffer duration to 0 to immediately flush counters into saved objects. '--usageCollection.usageCounters.bufferDuration=0', + // explicitly enable the cloud integration plugins to validate the rendered config keys + '--xpack.cloud_integrations.chat.enabled=true', + '--xpack.cloud_integrations.chat.chatURL=a_string', + '--xpack.cloud_integrations.experiments.enabled=true', + '--xpack.cloud_integrations.experiments.launch_darkly.sdk_key=a_string', + '--xpack.cloud_integrations.experiments.launch_darkly.client_id=a_string', + '--xpack.cloud_integrations.full_story.enabled=true', + '--xpack.cloud_integrations.full_story.org_id=a_string', ...plugins.map( (pluginDir) => `--plugin-path=${path.resolve(__dirname, 'plugins', pluginDir)}` ), diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index cbc98ec7bb07b..a3968330e1425 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -91,20 +91,14 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'unifiedSearch.autocomplete.valueSuggestions.tiers (array)', 'unifiedSearch.autocomplete.valueSuggestions.timeout (duration)', 'data.search.aggs.shardDelay.enabled (boolean)', - 'data.search.sessions.cleanupInterval (duration)', 'data.search.sessions.defaultExpiration (duration)', 'data.search.sessions.enabled (boolean)', - 'data.search.sessions.expireInterval (duration)', 'data.search.sessions.management.expiresSoonWarning (duration)', 'data.search.sessions.management.maxSessions (number)', 'data.search.sessions.management.refreshInterval (duration)', 'data.search.sessions.management.refreshTimeout (duration)', 'data.search.sessions.maxUpdateRetries (number)', - 'data.search.sessions.monitoringTaskTimeout (duration)', - 'data.search.sessions.notTouchedInProgressTimeout (duration)', 'data.search.sessions.notTouchedTimeout (duration)', - 'data.search.sessions.pageSize (number)', - 'data.search.sessions.trackingInterval (duration)', 'enterpriseSearch.host (string)', 'guidedOnboarding.ui (boolean)', 'home.disableWelcomeScreen (boolean)', @@ -171,14 +165,17 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.cases.markdownPlugins.lens (boolean)', 'xpack.ccr.ui.enabled (boolean)', 'xpack.cloud.base_url (string)', - 'xpack.cloud.chat.chatURL (string)', - 'xpack.cloud.chat.enabled (boolean)', 'xpack.cloud.cname (string)', 'xpack.cloud.deployment_url (string)', - 'xpack.cloud.full_story.enabled (boolean)', - 'xpack.cloud.full_story.org_id (any)', + 'xpack.cloud_integrations.chat.chatURL (string)', + // No PII. This is an escape patch to override LaunchDarkly's flag resolution mechanism for testing or quick fix. + 'xpack.cloud_integrations.experiments.flag_overrides (record)', + // Commented because it's inside a schema conditional, and the test is not able to resolve it. But it's shared. + // Added here for documentation purposes. + // 'xpack.cloud_integrations.experiments.launch_darkly.client_id (string)', + 'xpack.cloud_integrations.full_story.org_id (any)', // No PII. Just the list of event types we want to forward to FullStory. - 'xpack.cloud.full_story.eventTypesAllowlist (array)', + 'xpack.cloud_integrations.full_story.eventTypesAllowlist (array)', 'xpack.cloud.id (string)', 'xpack.cloud.organization_url (string)', 'xpack.cloud.profile_url (string)', diff --git a/tsconfig.base.json b/tsconfig.base.json index b62beb6650448..3054a36f2bb86 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -313,8 +313,14 @@ "@kbn/canvas-plugin/*": ["x-pack/plugins/canvas/*"], "@kbn/cases-plugin": ["x-pack/plugins/cases"], "@kbn/cases-plugin/*": ["x-pack/plugins/cases/*"], + "@kbn/cloud-chat-plugin": ["x-pack/plugins/cloud_integrations/cloud_chat"], + "@kbn/cloud-chat-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_chat/*"], "@kbn/cloud-experiments-plugin": ["x-pack/plugins/cloud_integrations/cloud_experiments"], "@kbn/cloud-experiments-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_experiments/*"], + "@kbn/cloud-full-story-plugin": ["x-pack/plugins/cloud_integrations/cloud_full_story"], + "@kbn/cloud-full-story-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_full_story/*"], + "@kbn/cloud-links-plugin": ["x-pack/plugins/cloud_integrations/cloud_links"], + "@kbn/cloud-links-plugin/*": ["x-pack/plugins/cloud_integrations/cloud_links/*"], "@kbn/cloud-security-posture-plugin": ["x-pack/plugins/cloud_security_posture"], "@kbn/cloud-security-posture-plugin/*": ["x-pack/plugins/cloud_security_posture/*"], "@kbn/cloud-plugin": ["x-pack/plugins/cloud"], diff --git a/versions.json b/versions.json index a39a1412c46f6..30514180e5c1e 100644 --- a/versions.json +++ b/versions.json @@ -14,7 +14,7 @@ "previousMinor": true }, { - "version": "8.4.3", + "version": "8.4.4", "branch": "8.4", "currentMajor": true, "previousMinor": true diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 83466ba749605..4f89798c71faf 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -10,6 +10,8 @@ "xpack.canvas": "plugins/canvas", "xpack.cases": "plugins/cases", "xpack.cloud": "plugins/cloud", + "xpack.cloudChat": "plugins/cloud_integrations/cloud_chat", + "xpack.cloudLinks": "plugins/cloud_integrations/cloud_links", "xpack.csp": "plugins/cloud_security_posture", "xpack.dashboard": "plugins/dashboard_enhanced", "xpack.discover": "plugins/discover_enhanced", diff --git a/x-pack/examples/files_example/common/index.ts b/x-pack/examples/files_example/common/index.ts index b9b30fac5cb50..1586d92c4c05a 100644 --- a/x-pack/examples/files_example/common/index.ts +++ b/x-pack/examples/files_example/common/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FileKind } from '@kbn/files-plugin/common'; +import type { FileKind, FileImageMetadata } from '@kbn/files-plugin/common'; export const PLUGIN_ID = 'filesExample'; export const PLUGIN_NAME = 'filesExample'; @@ -27,3 +27,5 @@ export const exampleFileKind: FileKind = { update: httpTags, }, }; + +export type MyImageMetadata = FileImageMetadata; diff --git a/x-pack/examples/files_example/public/components/app.tsx b/x-pack/examples/files_example/public/components/app.tsx index 124bc842af5ce..cf0f4461b8b62 100644 --- a/x-pack/examples/files_example/public/components/app.tsx +++ b/x-pack/examples/files_example/public/components/app.tsx @@ -21,8 +21,9 @@ import { } from '@elastic/eui'; import { CoreStart } from '@kbn/core/public'; -import { DetailsFlyout } from './details_flyout'; +import type { MyImageMetadata } from '../../common'; import type { FileClients } from '../types'; +import { DetailsFlyout } from './details_flyout'; import { ConfirmButtonIcon } from './confirm_button'; import { Modal } from './modal'; @@ -31,7 +32,7 @@ interface FilesExampleAppDeps { notifications: CoreStart['notifications']; } -type ListResponse = FilesClientResponses['list']; +type ListResponse = FilesClientResponses['list']; export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) => { const { data, isLoading, error, refetch } = useQuery(['files'], () => @@ -39,7 +40,7 @@ export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) = ); const [showUploadModal, setShowUploadModal] = useState(false); const [isDeletingFile, setIsDeletingFile] = useState(false); - const [selectedItem, setSelectedItem] = useState(); + const [selectedItem, setSelectedItem] = useState>(); const renderToolsRight = () => { return [ @@ -55,7 +56,7 @@ export const FilesExampleApp = ({ files, notifications }: FilesExampleAppDeps) = const items = [...(data?.files ?? [])].reverse(); - const columns: EuiInMemoryTableProps['columns'] = [ + const columns: EuiInMemoryTableProps>['columns'] = [ { field: 'name', name: 'Name', diff --git a/x-pack/examples/files_example/public/components/details_flyout.tsx b/x-pack/examples/files_example/public/components/details_flyout.tsx index 48eaa9a6ab8e4..a417752d1a666 100644 --- a/x-pack/examples/files_example/public/components/details_flyout.tsx +++ b/x-pack/examples/files_example/public/components/details_flyout.tsx @@ -7,7 +7,6 @@ import moment from 'moment'; import type { FunctionComponent } from 'react'; import React from 'react'; -import { css } from '@emotion/react'; import { EuiFlyout, EuiFlyoutHeader, @@ -22,11 +21,13 @@ import { EuiSpacer, } from '@elastic/eui'; import type { FileJSON } from '@kbn/files-plugin/common'; +import { css } from '@emotion/react'; +import type { MyImageMetadata } from '../../common'; import { FileClients } from '../types'; import { Image } from '../imports'; interface Props { - file: FileJSON; + file: FileJSON; files: FileClients; onDismiss: () => void; } @@ -40,8 +41,24 @@ export const DetailsFlyout: FunctionComponent = ({ files, file, onDismiss +
+ {file.alt +
+ = ({ files, file, onDismiss }, ]} /> - - {file.alt
diff --git a/x-pack/examples/files_example/public/components/modal.tsx b/x-pack/examples/files_example/public/components/modal.tsx index a4b54b694713f..9d323b240f416 100644 --- a/x-pack/examples/files_example/public/components/modal.tsx +++ b/x-pack/examples/files_example/public/components/modal.tsx @@ -8,11 +8,11 @@ import type { FunctionComponent } from 'react'; import React from 'react'; import { EuiModal, EuiModalHeader, EuiModalBody, EuiText } from '@elastic/eui'; -import { exampleFileKind } from '../../common'; +import { exampleFileKind, MyImageMetadata } from '../../common'; import { FilesClient, UploadFile } from '../imports'; interface Props { - client: FilesClient; + client: FilesClient; onDismiss: () => void; onUploaded: () => void; } diff --git a/x-pack/examples/files_example/public/plugin.ts b/x-pack/examples/files_example/public/plugin.ts index 5dd961278dbd0..98a6b6f6e4608 100644 --- a/x-pack/examples/files_example/public/plugin.ts +++ b/x-pack/examples/files_example/public/plugin.ts @@ -6,7 +6,7 @@ */ import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; -import { PLUGIN_ID, PLUGIN_NAME, exampleFileKind } from '../common'; +import { PLUGIN_ID, PLUGIN_NAME, exampleFileKind, MyImageMetadata } from '../common'; import { FilesExamplePluginsStart, FilesExamplePluginsSetup } from './types'; export class FilesExamplePlugin @@ -28,8 +28,8 @@ export class FilesExamplePlugin coreStart, { files: { - unscoped: deps.files.filesClientFactory.asUnscoped(), - example: deps.files.filesClientFactory.asScoped(exampleFileKind.id), + unscoped: deps.files.filesClientFactory.asUnscoped(), + example: deps.files.filesClientFactory.asScoped(exampleFileKind.id), }, }, params diff --git a/x-pack/examples/files_example/public/types.ts b/x-pack/examples/files_example/public/types.ts index b1e19b13d1b9b..fbc058d9aec30 100644 --- a/x-pack/examples/files_example/public/types.ts +++ b/x-pack/examples/files_example/public/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { MyImageMetadata } from '../common'; import type { FilesSetup, FilesStart, ScopedFilesClient, FilesClient } from './imports'; export interface FilesExamplePluginsSetup { @@ -16,9 +17,9 @@ export interface FilesExamplePluginsStart { } export interface FileClients { - unscoped: FilesClient; + unscoped: FilesClient; // Example file kind - example: ScopedFilesClient; + example: ScopedFilesClient; } export interface AppPluginStartDependencies { diff --git a/x-pack/examples/third_party_maps_source_example/public/classes/custom_raster_source.tsx b/x-pack/examples/third_party_maps_source_example/public/classes/custom_raster_source.tsx index 8521e4333be7d..d36ed2485b5ba 100644 --- a/x-pack/examples/third_party_maps_source_example/public/classes/custom_raster_source.tsx +++ b/x-pack/examples/third_party_maps_source_example/public/classes/custom_raster_source.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import _ from 'lodash'; import { ReactElement } from 'react'; import { calculateBounds } from '@kbn/data-plugin/common'; import { FieldFormatter, MIN_ZOOM, MAX_ZOOM } from '@kbn/maps-plugin/common'; @@ -16,15 +17,18 @@ import type { Timeslice, } from '@kbn/maps-plugin/common/descriptor_types'; import type { + DataRequest, IField, ImmutableSourceProperty, - ITMSSource, + IRasterSource, SourceEditorArgs, } from '@kbn/maps-plugin/public'; +import { RasterTileSourceData } from '@kbn/maps-plugin/public/classes/sources/raster_source'; +import { RasterTileSource } from 'maplibre-gl'; type CustomRasterSourceDescriptor = AbstractSourceDescriptor; -export class CustomRasterSource implements ITMSSource { +export class CustomRasterSource implements IRasterSource { static type = 'CUSTOM_RASTER'; readonly _descriptor: CustomRasterSourceDescriptor; @@ -39,6 +43,25 @@ export class CustomRasterSource implements ITMSSource { this._descriptor = sourceDescriptor; } + async canSkipSourceUpdate( + dataRequest: DataRequest, + nextRequestMeta: DataRequestMeta + ): Promise { + const prevMeta = dataRequest.getMeta(); + if (!prevMeta) { + return Promise.resolve(false); + } + + return Promise.resolve(_.isEqual(prevMeta.timeslice, nextRequestMeta.timeslice)); + } + + isSourceStale(mbSource: RasterTileSource, sourceData: RasterTileSourceData): boolean { + if (!sourceData.url) { + return false; + } + return mbSource.tiles?.[0] !== sourceData.url; + } + cloneDescriptor(): CustomRasterSourceDescriptor { return { type: this._descriptor.type, diff --git a/x-pack/performance/journeys/ecommerce_dashboard.ts b/x-pack/performance/journeys/ecommerce_dashboard.ts index 89f05902f4153..05e46eab851b9 100644 --- a/x-pack/performance/journeys/ecommerce_dashboard.ts +++ b/x-pack/performance/journeys/ecommerce_dashboard.ts @@ -52,5 +52,5 @@ export const journey = new Journey({ await page.click(subj('launchSampleDataSetecommerce')); await page.click(subj('viewSampleDataSetecommerce-dashboard')); - await waitForVisualizations(page, 13); + await waitForVisualizations(page, 12); }); diff --git a/x-pack/performance/journeys/flight_dashboard.ts b/x-pack/performance/journeys/flight_dashboard.ts index ac6e589d391a5..1fbf2e3e77cb2 100644 --- a/x-pack/performance/journeys/flight_dashboard.ts +++ b/x-pack/performance/journeys/flight_dashboard.ts @@ -52,7 +52,7 @@ export const journey = new Journey({ await page.click(subj('launchSampleDataSetflights')); await page.click(subj('viewSampleDataSetflights-dashboard')); - await waitForVisualizations(page, 15); + await waitForVisualizations(page, 14); }) .step('Go to Airport Connections Visualizations Edit', async ({ page }) => { diff --git a/x-pack/performance/journeys/web_logs_dashboard.ts b/x-pack/performance/journeys/web_logs_dashboard.ts index 64ea47d412e0e..efba62acc517e 100644 --- a/x-pack/performance/journeys/web_logs_dashboard.ts +++ b/x-pack/performance/journeys/web_logs_dashboard.ts @@ -52,5 +52,5 @@ export const journey = new Journey({ await page.click(subj('launchSampleDataSetlogs')); await page.click(subj('viewSampleDataSetlogs-dashboard')); - await waitForVisualizations(page, 12); + await waitForVisualizations(page, 11); }); diff --git a/x-pack/plugins/actions/server/actions_config.test.ts b/x-pack/plugins/actions/server/actions_config.test.ts index a6b68d907cb44..b1af4a843b496 100644 --- a/x-pack/plugins/actions/server/actions_config.test.ts +++ b/x-pack/plugins/actions/server/actions_config.test.ts @@ -43,6 +43,15 @@ const defaultActionsConfig: ActionsConfig = { }; describe('ensureUriAllowed', () => { + test('throws an error when the Uri is an empty string', () => { + const config: ActionsConfig = defaultActionsConfig; + expect(() => + getActionsConfigurationUtilities(config).ensureUriAllowed('') + ).toThrowErrorMatchingInlineSnapshot( + `"target url \\"\\" is not added to the Kibana config xpack.actions.allowedHosts"` + ); + }); + test('returns true when "any" hostnames are allowed', () => { const config: ActionsConfig = { ...defaultActionsConfig, diff --git a/x-pack/plugins/actions/server/index.ts b/x-pack/plugins/actions/server/index.ts index 7f9b45c368e90..1c7a66978ffb3 100644 --- a/x-pack/plugins/actions/server/index.ts +++ b/x-pack/plugins/actions/server/index.ts @@ -139,3 +139,5 @@ export const config: PluginConfigDescriptor = { }, ], }; + +export { urlAllowListValidator } from './sub_action_framework/helpers'; diff --git a/x-pack/plugins/actions/server/sub_action_framework/README.md b/x-pack/plugins/actions/server/sub_action_framework/README.md index 90951692f5457..d3ca9c7143462 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/README.md +++ b/x-pack/plugins/actions/server/sub_action_framework/README.md @@ -6,6 +6,7 @@ The Kibana actions plugin provides a framework to create executable actions that - Register a sub action and map it to a function of your choice. - Define a schema for the parameters of your sub action. +- Define custom validators (or use the provided helpers) for the parameters of your sub action. - Define a response schema for responses from external services. - Create connectors that are supported by the Cases management system. @@ -350,7 +351,23 @@ plugins.actions.registerSubActionConnectorType({ minimumLicenseRequired: 'platinum' as const, schema: { config: TestConfigSchema, secrets: TestSecretsSchema }, Service: TestSubActionConnector, + renderParameterTemplates: renderTestTemplate }); ``` -You can see a full example in [x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/sub_action_connector.ts](../../../../test/alerting_api_integration/common/fixtures/plugins/alerts/server/sub_action_connector.ts) \ No newline at end of file +You can see a full example in [x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/sub_action_connector.ts](../../../../test/alerting_api_integration/common/fixtures/plugins/alerts/server/sub_action_connector.ts) + +### Example: Register sub action connector with custom validators + +The sub actions framework allows custom validators during registration of the connector type. Below is an example of including the URL validation for the `TestSubActionConnector` `url` configuration field. + +```typescript +plugins.actions.registerSubActionConnectorType({ + id: '.test-sub-action-connector', + name: 'Test: Sub action connector', + minimumLicenseRequired: 'platinum' as const, + schema: { config: TestConfigSchema, secrets: TestSecretsSchema }, + validators: [{type: ValidatorType.CONFIG, validate: urlAllowListValidator('url')}] + Service: TestSubActionConnector, +}); +``` diff --git a/x-pack/plugins/triggers_actions_ui/.storybook/main.js b/x-pack/plugins/actions/server/sub_action_framework/helpers/index.ts similarity index 81% rename from x-pack/plugins/triggers_actions_ui/.storybook/main.js rename to x-pack/plugins/actions/server/sub_action_framework/helpers/index.ts index 86b48c32f103e..c69caff6b0c71 100644 --- a/x-pack/plugins/triggers_actions_ui/.storybook/main.js +++ b/x-pack/plugins/actions/server/sub_action_framework/helpers/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -module.exports = require('@kbn/storybook').defaultConfig; +export { urlAllowListValidator } from './validators'; diff --git a/x-pack/plugins/actions/server/sub_action_framework/helpers/validators.ts b/x-pack/plugins/actions/server/sub_action_framework/helpers/validators.ts new file mode 100644 index 0000000000000..7618fef0f3ea4 --- /dev/null +++ b/x-pack/plugins/actions/server/sub_action_framework/helpers/validators.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { get } from 'lodash'; +import { ValidatorServices } from '../../types'; + +export const urlAllowListValidator = (urlKey: string) => { + return (obj: T, validatorServices: ValidatorServices) => { + const { configurationUtilities } = validatorServices; + try { + const url = get(obj, urlKey, ''); + + configurationUtilities.ensureUriAllowed(url); + } catch (allowListError) { + throw new Error( + i18n.translate('xpack.actions.subActionsFramework.urlValidationError', { + defaultMessage: 'error validating url: {message}', + values: { + message: allowListError.message, + }, + }) + ); + } + }; +}; diff --git a/x-pack/plugins/actions/server/sub_action_framework/register.test.ts b/x-pack/plugins/actions/server/sub_action_framework/register.test.ts index d4c9290b2de25..6788ca6e5e6fb 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/register.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/register.test.ts @@ -18,6 +18,9 @@ import { import { register } from './register'; describe('Registration', () => { + const renderedVariables = { body: '' }; + const mockRenderParameterTemplates = jest.fn().mockReturnValue(renderedVariables); + const connector = { id: '.test', name: 'Test', @@ -28,6 +31,7 @@ describe('Registration', () => { secrets: TestSecretsSchema, }, Service: TestSubActionConnector, + renderParameterTemplates: mockRenderParameterTemplates, }; const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -35,7 +39,6 @@ describe('Registration', () => { const logger = loggingSystemMock.createLogger(); beforeEach(() => { - jest.resetAllMocks(); jest.clearAllMocks(); }); @@ -54,7 +57,27 @@ describe('Registration', () => { minimumLicenseRequired: connector.minimumLicenseRequired, supportedFeatureIds: connector.supportedFeatureIds, validate: expect.anything(), - executor: expect.anything(), + executor: expect.any(Function), + renderParameterTemplates: expect.any(Function), + }); + }); + + it('registers the renderParameterTemplates correctly', async () => { + register({ + actionTypeRegistry, + connector, + configurationUtilities: mockedActionsConfig, + logger, }); + + const params = {}; + const variables = {}; + const actionId = 'action-id'; + + const { renderParameterTemplates } = actionTypeRegistry.register.mock.calls[0][0]; + const rendered = renderParameterTemplates?.(params, variables, actionId); + + expect(mockRenderParameterTemplates).toHaveBeenCalledWith(params, variables, actionId); + expect(rendered).toBe(renderedVariables); }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/register.ts b/x-pack/plugins/actions/server/sub_action_framework/register.ts index 077339731a2af..9d5bd91a88866 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/register.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/register.ts @@ -54,5 +54,6 @@ export const register = { responseSchema, headers, ...config - }: { - url: string; - responseSchema: Type; - method?: Method; - } & AxiosRequestConfig): Promise> { + }: SubActionRequestParams): Promise> { try { this.assertURL(url); this.ensureUriAllowed(url); diff --git a/x-pack/plugins/actions/server/sub_action_framework/types.ts b/x-pack/plugins/actions/server/sub_action_framework/types.ts index cdc05524cf842..26b1fd20020d2 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/types.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/types.ts @@ -6,12 +6,18 @@ */ import type { Type } from '@kbn/config-schema'; -import { Logger } from '@kbn/logging'; +import type { Logger } from '@kbn/logging'; import type { LicenseType } from '@kbn/licensing-plugin/common/types'; -import { ActionsConfigurationUtilities } from '../actions_config'; -import { ActionTypeParams, Services } from '../types'; -import { SubActionConnector } from './sub_action_connector'; +import type { Method, AxiosRequestConfig } from 'axios'; +import type { ActionsConfigurationUtilities } from '../actions_config'; +import type { + ActionTypeParams, + RenderParameterTemplates, + Services, + ValidatorType as ValidationSchema, +} from '../types'; +import type { SubActionConnector } from './sub_action_connector'; export interface ServiceParams { /** @@ -26,6 +32,12 @@ export interface ServiceParams { services: Services; } +export type SubActionRequestParams = { + url: string; + responseSchema: Type; + method?: Method; +} & AxiosRequestConfig; + export type IService = new ( params: ServiceParams ) => SubActionConnector; @@ -34,6 +46,29 @@ export type IServiceAbstract = abstract new ( params: ServiceParams ) => SubActionConnector; +export enum ValidatorType { + CONFIG, + SECRETS, +} + +interface Validate { + validator: ValidateFn; +} + +export type ValidateFn = NonNullable['customValidator']>; + +interface ConfigValidator extends Validate { + type: ValidatorType.CONFIG; +} + +interface SecretsValidator extends Validate { + type: ValidatorType.SECRETS; +} + +export type Validators = Array< + ConfigValidator | SecretsValidator +>; + export interface SubActionConnectorType { id: string; name: string; @@ -43,7 +78,9 @@ export interface SubActionConnectorType { config: Type; secrets: Type; }; + validators?: Array | SecretsValidator>; Service: IService; + renderParameterTemplates?: RenderParameterTemplates; } export interface ExecutorParams extends ActionTypeParams { diff --git a/x-pack/plugins/actions/server/sub_action_framework/validators.test.ts b/x-pack/plugins/actions/server/sub_action_framework/validators.test.ts index 6cae35141b498..b28adc0b545bf 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/validators.test.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/validators.test.ts @@ -14,7 +14,7 @@ import { TestSecrets, TestSubActionConnector, } from './mocks'; -import { IService } from './types'; +import { IService, SubActionConnectorType, ValidatorType } from './types'; import { buildValidators } from './validators'; describe('Validators', () => { @@ -36,6 +36,39 @@ describe('Validators', () => { return buildValidators({ configurationUtilities: mockedActionsConfig, connector }); }; + const createValidatorWithCustomValidation = (Service: IService) => { + const configValidator = jest.fn(); + const secretsValidator = jest.fn(); + + const connector: SubActionConnectorType = { + id: '.test', + name: 'Test', + minimumLicenseRequired: 'basic' as const, + supportedFeatureIds: ['alerting'], + schema: { + config: TestConfigSchema, + secrets: TestSecretsSchema, + }, + validators: [ + { + type: ValidatorType.CONFIG, + validator: configValidator, + }, + { + type: ValidatorType.SECRETS, + validator: secretsValidator, + }, + ], + Service, + }; + + return { + validators: buildValidators({ configurationUtilities: mockedActionsConfig, connector }), + configValidator, + secretsValidator, + }; + }; + beforeEach(() => { jest.resetAllMocks(); jest.clearAllMocks(); @@ -96,4 +129,28 @@ describe('Validators', () => { const { params } = validator; expect(() => params.schema.validate({ subAction, subActionParams: {} })).toThrow(); }); + + it('calls the config and secrets custom validator functions', () => { + const validator = createValidatorWithCustomValidation(TestSubActionConnector); + + validator.validators.config.customValidator?.( + { url: 'http://www.example.com' }, + { configurationUtilities: mockedActionsConfig } + ); + + validator.validators.secrets.customValidator?.( + { password: '123', username: 'sam' }, + { configurationUtilities: mockedActionsConfig } + ); + + expect(validator.configValidator).toHaveBeenCalledWith( + { url: 'http://www.example.com' }, + expect.anything() + ); + + expect(validator.secretsValidator).toHaveBeenCalledWith( + { password: '123', username: 'sam' }, + expect.anything() + ); + }); }); diff --git a/x-pack/plugins/actions/server/sub_action_framework/validators.ts b/x-pack/plugins/actions/server/sub_action_framework/validators.ts index be6dafed28163..e9cbbb3ae8f80 100644 --- a/x-pack/plugins/actions/server/sub_action_framework/validators.ts +++ b/x-pack/plugins/actions/server/sub_action_framework/validators.ts @@ -7,8 +7,8 @@ import { schema } from '@kbn/config-schema'; import { ActionsConfigurationUtilities } from '../actions_config'; -import { ActionTypeConfig, ActionTypeSecrets } from '../types'; -import { SubActionConnectorType } from './types'; +import { ActionTypeConfig, ActionTypeSecrets, ValidatorServices } from '../types'; +import { SubActionConnectorType, ValidateFn, Validators, ValidatorType } from './types'; export const buildValidators = < Config extends ActionTypeConfig, @@ -20,12 +20,16 @@ export const buildValidators = < configurationUtilities: ActionsConfigurationUtilities; connector: SubActionConnectorType; }) => { + const { config, secrets } = buildCustomValidators(connector.validators); + return { config: { schema: connector.schema.config, + customValidator: config, }, secrets: { schema: connector.schema.secrets, + customValidator: secrets, }, params: { schema: schema.object({ @@ -42,3 +46,35 @@ export const buildValidators = < }, }; }; + +const buildCustomValidators = (validators?: Validators) => { + const partitionedValidators: { + config: Array>; + secrets: Array>; + } = { config: [], secrets: [] }; + + for (const validatorInfo of validators ?? []) { + if (validatorInfo.type === ValidatorType.CONFIG) { + partitionedValidators.config.push(validatorInfo.validator); + } else { + partitionedValidators.secrets.push(validatorInfo.validator); + } + } + + return { + config: createCustomValidatorFunction(partitionedValidators.config), + secrets: createCustomValidatorFunction(partitionedValidators.secrets), + }; +}; + +const createCustomValidatorFunction = (validators: Array>) => { + if (validators.length <= 0) { + return; + } + + return (value: T, validatorServices: ValidatorServices) => { + for (const validate of validators) { + validate(value, validatorServices); + } + }; +}; diff --git a/x-pack/plugins/actions/server/types.ts b/x-pack/plugins/actions/server/types.ts index ae344d4f62dbc..3806dae00c237 100644 --- a/x-pack/plugins/actions/server/types.ts +++ b/x-pack/plugins/actions/server/types.ts @@ -91,7 +91,7 @@ export type ExecutorType = ( options: ActionTypeExecutorOptions ) => Promise>; -interface ValidatorType { +export interface ValidatorType { schema: { validate(value: unknown): Type; }; @@ -108,6 +108,12 @@ export interface ActionValidationService { isUriAllowed(uri: string): boolean; } +export type RenderParameterTemplates = ( + params: Params, + variables: Record, + actionId?: string +) => Params; + export interface ActionType< Config extends ActionTypeConfig = ActionTypeConfig, Secrets extends ActionTypeSecrets = ActionTypeSecrets, @@ -126,11 +132,7 @@ export interface ActionType< connector?: (config: Config, secrets: Secrets) => string | null; }; - renderParameterTemplates?( - params: Params, - variables: Record, - actionId?: string - ): Params; + renderParameterTemplates?: RenderParameterTemplates; executor: ExecutorType; } diff --git a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts index e050946a489be..7c4e3a47f8b79 100644 --- a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts +++ b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/actions.ts @@ -18,6 +18,7 @@ export const API_ACTION_NAME = { ADD_CHANGE_POINTS_GROUP: 'add_change_point_group', ADD_CHANGE_POINTS_GROUP_HISTOGRAM: 'add_change_point_group_histogram', ADD_ERROR: 'add_error', + PING: 'ping', RESET: 'reset', UPDATE_LOADING_STATE: 'update_loading_state', } as const; @@ -89,6 +90,14 @@ export function addErrorAction(payload: ApiActionAddError['payload']): ApiAction }; } +interface ApiActionPing { + type: typeof API_ACTION_NAME.PING; +} + +export function pingAction(): ApiActionPing { + return { type: API_ACTION_NAME.PING }; +} + interface ApiActionReset { type: typeof API_ACTION_NAME.RESET; } @@ -121,5 +130,6 @@ export type AiopsExplainLogRateSpikesApiAction = | ApiActionAddChangePointsHistogram | ApiActionAddChangePointsGroupHistogram | ApiActionAddError + | ApiActionPing | ApiActionReset | ApiActionUpdateLoadingState; diff --git a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts index 5628b509980ad..c092b34c8b2b6 100644 --- a/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts +++ b/x-pack/plugins/aiops/common/api/explain_log_rate_spikes/index.ts @@ -11,6 +11,7 @@ export { addChangePointsGroupHistogramAction, addChangePointsHistogramAction, addErrorAction, + pingAction, resetAction, updateLoadingStateAction, API_ACTION_NAME, diff --git a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx index 2425161615915..9949ec537b77a 100644 --- a/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx +++ b/x-pack/plugins/aiops/public/components/explain_log_rate_spikes/explain_log_rate_spikes_analysis.tsx @@ -172,6 +172,33 @@ export const ExplainLogRateSpikesAnalysis: FC onCancel={cancel} shouldRerunAnalysis={shouldRerunAnalysis} /> + {errors.length > 0 ? ( + <> + + + {errors.length === 1 ? ( +

{errors[0]}

+ ) : ( +
    + {errors.map((e, i) => ( +
  • {e}
  • + ))} +
+ )} +
+
+ + + ) : null} {showSpikeAnalysisTable && foundGroups && ( } /> )} - {errors.length > 0 && ( - <> - - - {errors.length === 1 ? ( -

{errors[0]}

- ) : ( -
    - {errors.map((e, i) => ( -
  • {e}
  • - ))} -
- )} -
-
- - - )} {showSpikeAnalysisTable && groupResults && foundGroups ? ( { + logInfoMessage('aborted$ subscription trigger.'); shouldStop = true; controller.abort(); }); request.events.completed$.subscribe(() => { + logInfoMessage('completed$ subscription trigger.'); shouldStop = true; controller.abort(); }); - const { end, push, responseWithHeaders } = streamFactory( - request.headers, - logger, - true - ); + const { + end: streamEnd, + push, + responseWithHeaders, + } = streamFactory(request.headers, logger, true); + + function pushPing() { + push(pingAction()); + } + + const pingInterval = setInterval(pushPing, 1000); + + function end() { + logInfoMessage('Ending analysis.'); + clearInterval(pingInterval); + streamEnd(); + } function endWithUpdatedLoadingState() { push( @@ -114,9 +138,16 @@ export const defineExplainLogRateSpikesRoute = ( end(); } + function pushError(m: string) { + logInfoMessage('Push error.'); + push(addErrorAction(m)); + } + // Async IIFE to run the analysis while not blocking returning `responseWithHeaders`. (async () => { + logInfoMessage('Reset.'); push(resetAction()); + logInfoMessage('Load field candidates.'); push( updateLoadingStateAction({ ccsWarning: false, @@ -134,7 +165,8 @@ export const defineExplainLogRateSpikesRoute = ( try { fieldCandidates = await fetchFieldCandidates(client, request.body); } catch (e) { - push(addErrorAction(e.toString())); + logger.error(`Failed to fetch field candidates, got: \n${e.toString()}`); + pushError(`Failed to fetch field candidates.`); end(); return; } @@ -168,17 +200,33 @@ export const defineExplainLogRateSpikesRoute = ( const changePoints: ChangePoint[] = []; const fieldsToSample = new Set(); const chunkSize = 10; + let chunkCount = 0; const fieldCandidatesChunks = chunk(fieldCandidates, chunkSize); + logInfoMessage('Fetch p-values.'); + for (const fieldCandidatesChunk of fieldCandidatesChunks) { + chunkCount++; + logInfoMessage(`Fetch p-values. Chunk ${chunkCount} of ${fieldCandidatesChunks.length}`); let pValues: Awaited>; try { - pValues = await fetchChangePointPValues(client, request.body, fieldCandidatesChunk); + pValues = await fetchChangePointPValues( + client, + request.body, + fieldCandidatesChunk, + logger, + pushError + ); } catch (e) { - push(addErrorAction(e.toString())); - end(); - return; + logger.error( + `Failed to fetch p-values for ${JSON.stringify( + fieldCandidatesChunk + )}, got: \n${e.toString()}` + ); + pushError(`Failed to fetch p-values for ${JSON.stringify(fieldCandidatesChunk)}.`); + // Still continue the analysis even if chunks of p-value queries fail. + continue; } if (pValues.length > 0) { @@ -210,12 +258,15 @@ export const defineExplainLogRateSpikesRoute = ( ); if (shouldStop) { + logInfoMessage('shouldStop fetching p-values.'); + end(); return; } } if (changePoints?.length === 0) { + logInfoMessage('Stopping analysis, did not find change points.'); endWithUpdatedLoadingState(); return; } @@ -224,16 +275,27 @@ export const defineExplainLogRateSpikesRoute = ( { fieldName: request.body.timeFieldName, type: KBN_FIELD_TYPES.DATE }, ]; - const [overallTimeSeries] = (await fetchHistogramsForFields( - client, - request.body.index, - { match_all: {} }, - // fields - histogramFields, - // samplerShardSize - -1, - undefined - )) as [NumericChartData]; + logInfoMessage('Fetch overall histogram.'); + + let overallTimeSeries: NumericChartData | undefined; + try { + overallTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + { match_all: {} }, + // fields + histogramFields, + // samplerShardSize + -1, + undefined + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error(`Failed to fetch the overall histogram data, got: \n${e.toString()}`); + pushError(`Failed to fetch overall histogram data.`); + // Still continue the analysis even if loading the overall histogram fails. + } function pushHistogramDataLoadingState() { push( @@ -251,6 +313,8 @@ export const defineExplainLogRateSpikesRoute = ( } if (groupingEnabled) { + logInfoMessage('Group results.'); + push( updateLoadingStateAction({ ccsWarning: false, @@ -283,208 +347,242 @@ export const defineExplainLogRateSpikesRoute = ( (g) => g.group.length > 1 ); - const { fields, df } = await fetchFrequentItems( - client, - request.body.index, - JSON.parse(request.body.searchQuery) as estypes.QueryDslQueryContainer, - deduplicatedChangePoints, - request.body.timeFieldName, - request.body.deviationMin, - request.body.deviationMax - ); - - // The way the `frequent_items` aggregations works could return item sets that include - // field/value pairs that are not part of the original list of significant change points. - // This cleans up groups and removes those unrelated field/value pairs. - const filteredDf = df - .map((fi) => { - fi.set = Object.entries(fi.set).reduce( - (set, [field, value]) => { - if ( - changePoints.some((cp) => cp.fieldName === field && cp.fieldValue === value) - ) { - set[field] = value; + try { + const { fields, df } = await fetchFrequentItems( + client, + request.body.index, + JSON.parse(request.body.searchQuery) as estypes.QueryDslQueryContainer, + deduplicatedChangePoints, + request.body.timeFieldName, + request.body.deviationMin, + request.body.deviationMax, + logger, + pushError + ); + + if (fields.length > 0 && df.length > 0) { + // The way the `frequent_items` aggregations works could return item sets that include + // field/value pairs that are not part of the original list of significant change points. + // This cleans up groups and removes those unrelated field/value pairs. + const filteredDf = df + .map((fi) => { + fi.set = Object.entries(fi.set).reduce( + (set, [field, value]) => { + if ( + changePoints.some((cp) => cp.fieldName === field && cp.fieldValue === value) + ) { + set[field] = value; + } + return set; + }, + {} + ); + fi.size = Object.keys(fi.set).length; + return fi; + }) + .filter((fi) => fi.size > 1); + + // `frequent_items` returns lot of different small groups of field/value pairs that co-occur. + // The following steps analyse these small groups, identify overlap between these groups, + // and then summarize them in larger groups where possible. + + // Get a tree structure based on `frequent_items`. + const { root } = getSimpleHierarchicalTree(filteredDf, true, false, fields); + + // Each leave of the tree will be a summarized group of co-occuring field/value pairs. + const treeLeaves = getSimpleHierarchicalTreeLeaves(root, []); + + // To be able to display a more cleaned up results table in the UI, we identify field/value pairs + // that occur in multiple groups. This will allow us to highlight field/value pairs that are + // unique to a group in a better way. This step will also re-add duplicates we identified in the + // beginning and didn't pass on to the `frequent_items` agg. + const fieldValuePairCounts = getFieldValuePairCounts(treeLeaves); + const changePointGroups = markDuplicates(treeLeaves, fieldValuePairCounts).map( + (g) => { + const group = [...g.group]; + + for (const groupItem of g.group) { + const { duplicate } = groupItem; + const duplicates = groupedChangePoints.find((d) => + d.group.some( + (dg) => + dg.fieldName === groupItem.fieldName && + dg.fieldValue === groupItem.fieldValue + ) + ); + + if (duplicates !== undefined) { + group.push( + ...duplicates.group.map((d) => { + return { + fieldName: d.fieldName, + fieldValue: d.fieldValue, + duplicate, + }; + }) + ); + } } - return set; - }, - {} - ); - fi.size = Object.keys(fi.set).length; - return fi; - }) - .filter((fi) => fi.size > 1); - - // `frequent_items` returns lot of different small groups of field/value pairs that co-occur. - // The following steps analyse these small groups, identify overlap between these groups, - // and then summarize them in larger groups where possible. - - // Get a tree structure based on `frequent_items`. - const { root } = getSimpleHierarchicalTree(filteredDf, true, false, fields); - - // Each leave of the tree will be a summarized group of co-occuring field/value pairs. - const treeLeaves = getSimpleHierarchicalTreeLeaves(root, []); - - // To be able to display a more cleaned up results table in the UI, we identify field/value pairs - // that occur in multiple groups. This will allow us to highlight field/value pairs that are - // unique to a group in a better way. This step will also re-add duplicates we identified in the - // beginning and didn't pass on to the `frequent_items` agg. - const fieldValuePairCounts = getFieldValuePairCounts(treeLeaves); - const changePointGroups = markDuplicates(treeLeaves, fieldValuePairCounts).map((g) => { - const group = [...g.group]; - - for (const groupItem of g.group) { - const { duplicate } = groupItem; - const duplicates = groupedChangePoints.find((d) => - d.group.some( - (dg) => - dg.fieldName === groupItem.fieldName && dg.fieldValue === groupItem.fieldValue - ) - ); - - if (duplicates !== undefined) { - group.push( - ...duplicates.group.map((d) => { - return { - fieldName: d.fieldName, - fieldValue: d.fieldValue, - duplicate, - }; - }) - ); - } - } - return { - ...g, - group, - }; - }); - - // Some field/value pairs might not be part of the `frequent_items` result set, for example - // because they don't co-occur with other field/value pairs or because of the limits we set on the query. - // In this next part we identify those missing pairs and add them as individual groups. - const missingChangePoints = deduplicatedChangePoints.filter((cp) => { - return !changePointGroups.some((cpg) => { - return cpg.group.some( - (d) => d.fieldName === cp.fieldName && d.fieldValue === cp.fieldValue + return { + ...g, + group, + }; + } ); - }); - }); - changePointGroups.push( - ...missingChangePoints.map(({ fieldName, fieldValue, doc_count: docCount, pValue }) => { - const duplicates = groupedChangePoints.find((d) => - d.group.some((dg) => dg.fieldName === fieldName && dg.fieldValue === fieldValue) + // Some field/value pairs might not be part of the `frequent_items` result set, for example + // because they don't co-occur with other field/value pairs or because of the limits we set on the query. + // In this next part we identify those missing pairs and add them as individual groups. + const missingChangePoints = deduplicatedChangePoints.filter((cp) => { + return !changePointGroups.some((cpg) => { + return cpg.group.some( + (d) => d.fieldName === cp.fieldName && d.fieldValue === cp.fieldValue + ); + }); + }); + + changePointGroups.push( + ...missingChangePoints.map( + ({ fieldName, fieldValue, doc_count: docCount, pValue }) => { + const duplicates = groupedChangePoints.find((d) => + d.group.some( + (dg) => dg.fieldName === fieldName && dg.fieldValue === fieldValue + ) + ); + if (duplicates !== undefined) { + return { + id: `${stringHash( + JSON.stringify( + duplicates.group.map((d) => ({ + fieldName: d.fieldName, + fieldValue: d.fieldValue, + })) + ) + )}`, + group: duplicates.group.map((d) => ({ + fieldName: d.fieldName, + fieldValue: d.fieldValue, + duplicate: false, + })), + docCount, + pValue, + }; + } else { + return { + id: `${stringHash(JSON.stringify({ fieldName, fieldValue }))}`, + group: [ + { + fieldName, + fieldValue, + duplicate: false, + }, + ], + docCount, + pValue, + }; + } + } + ) ); - if (duplicates !== undefined) { - return { - id: `${stringHash( - JSON.stringify( - duplicates.group.map((d) => ({ - fieldName: d.fieldName, - fieldValue: d.fieldValue, - })) - ) - )}`, - group: duplicates.group.map((d) => ({ - fieldName: d.fieldName, - fieldValue: d.fieldValue, - duplicate: false, - })), - docCount, - pValue, - }; - } else { - return { - id: `${stringHash(JSON.stringify({ fieldName, fieldValue }))}`, - group: [ - { - fieldName, - fieldValue, - duplicate: false, - }, - ], - docCount, - pValue, - }; - } - }) - ); - - // Finally, we'll find out if there's at least one group with at least two items, - // only then will we return the groups to the clients and make the grouping option available. - const maxItems = Math.max(...changePointGroups.map((g) => g.group.length)); - if (maxItems > 1) { - push(addChangePointsGroupAction(changePointGroups)); - } + // Finally, we'll find out if there's at least one group with at least two items, + // only then will we return the groups to the clients and make the grouping option available. + const maxItems = Math.max(...changePointGroups.map((g) => g.group.length)); - loaded += PROGRESS_STEP_GROUPING; + if (maxItems > 1) { + push(addChangePointsGroupAction(changePointGroups)); + } - pushHistogramDataLoadingState(); + loaded += PROGRESS_STEP_GROUPING; - if (changePointGroups) { - await asyncForEach(changePointGroups, async (cpg, index) => { - const histogramQuery = { - bool: { - filter: cpg.group.map((d) => ({ - term: { [d.fieldName]: d.fieldValue }, - })), - }, - }; + pushHistogramDataLoadingState(); - const [cpgTimeSeries] = (await fetchHistogramsForFields( - client, - request.body.index, - histogramQuery, - // fields - [ - { - fieldName: request.body.timeFieldName, - type: KBN_FIELD_TYPES.DATE, - interval: overallTimeSeries.interval, - min: overallTimeSeries.stats[0], - max: overallTimeSeries.stats[1], - }, - ], - // samplerShardSize - -1, - undefined - )) as [NumericChartData]; + logInfoMessage('Fetch group histograms.'); - const histogram = - overallTimeSeries.data.map((o, i) => { - const current = cpgTimeSeries.data.find( - (d1) => d1.key_as_string === o.key_as_string - ) ?? { - doc_count: 0, - }; - return { - key: o.key, - key_as_string: o.key_as_string ?? '', - doc_count_change_point: current.doc_count, - doc_count_overall: Math.max(0, o.doc_count - current.doc_count), + await asyncForEach(changePointGroups, async (cpg) => { + if (overallTimeSeries !== undefined) { + const histogramQuery = { + bool: { + filter: cpg.group.map((d) => ({ + term: { [d.fieldName]: d.fieldValue }, + })), + }, }; - }) ?? []; - push( - addChangePointsGroupHistogramAction([ - { - id: cpg.id, - histogram, - }, - ]) - ); - }); + let cpgTimeSeries: NumericChartData; + try { + cpgTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + histogramQuery, + // fields + [ + { + fieldName: request.body.timeFieldName, + type: KBN_FIELD_TYPES.DATE, + interval: overallTimeSeries.interval, + min: overallTimeSeries.stats[0], + max: overallTimeSeries.stats[1], + }, + ], + // samplerShardSize + -1, + undefined + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error( + `Failed to fetch the histogram data for group #${ + cpg.id + }, got: \n${e.toString()}` + ); + pushError(`Failed to fetch the histogram data for group #${cpg.id}.`); + return; + } + const histogram = + overallTimeSeries.data.map((o, i) => { + const current = cpgTimeSeries.data.find( + (d1) => d1.key_as_string === o.key_as_string + ) ?? { + doc_count: 0, + }; + return { + key: o.key, + key_as_string: o.key_as_string ?? '', + doc_count_change_point: current.doc_count, + doc_count_overall: Math.max(0, o.doc_count - current.doc_count), + }; + }) ?? []; + + push( + addChangePointsGroupHistogramAction([ + { + id: cpg.id, + histogram, + }, + ]) + ); + } + }); + } + } catch (e) { + logger.error( + `Failed to transform field/value pairs into groups, got: \n${e.toString()}` + ); + pushError(`Failed to transform field/value pairs into groups.`); } } loaded += PROGRESS_STEP_HISTOGRAMS_GROUPS; + logInfoMessage('Fetch field/value histograms.'); + // time series filtered by fields - if (changePoints) { - await asyncForEach(changePoints, async (cp, index) => { - if (changePoints) { + if (changePoints && overallTimeSeries !== undefined) { + await asyncForEach(changePoints, async (cp) => { + if (overallTimeSeries !== undefined) { const histogramQuery = { bool: { filter: [ @@ -495,24 +593,40 @@ export const defineExplainLogRateSpikesRoute = ( }, }; - const [cpTimeSeries] = (await fetchHistogramsForFields( - client, - request.body.index, - histogramQuery, - // fields - [ - { - fieldName: request.body.timeFieldName, - type: KBN_FIELD_TYPES.DATE, - interval: overallTimeSeries.interval, - min: overallTimeSeries.stats[0], - max: overallTimeSeries.stats[1], - }, - ], - // samplerShardSize - -1, - undefined - )) as [NumericChartData]; + let cpTimeSeries: NumericChartData; + + try { + cpTimeSeries = ( + (await fetchHistogramsForFields( + client, + request.body.index, + histogramQuery, + // fields + [ + { + fieldName: request.body.timeFieldName, + type: KBN_FIELD_TYPES.DATE, + interval: overallTimeSeries.interval, + min: overallTimeSeries.stats[0], + max: overallTimeSeries.stats[1], + }, + ], + // samplerShardSize + -1, + undefined + )) as [NumericChartData] + )[0]; + } catch (e) { + logger.error( + `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${ + cp.fieldValue + }", got: \n${e.toString()}` + ); + pushError( + `Failed to fetch the histogram data for field/value pair "${cp.fieldName}:${cp.fieldValue}".` + ); + return; + } const histogram = overallTimeSeries.data.map((o, i) => { diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts index 03242a4bc8ae5..0fb7f90c89c12 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_change_point_p_values.ts @@ -8,6 +8,7 @@ import { uniqBy } from 'lodash'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from '@kbn/core/server'; +import type { Logger } from '@kbn/logging'; import { ChangePoint } from '@kbn/ml-agg-utils'; import { SPIKE_ANALYSIS_THRESHOLD } from '../../../common/constants'; import type { AiopsExplainLogRateSpikesSchema } from '../../../common/api/explain_log_rate_spikes'; @@ -92,7 +93,9 @@ interface Aggs extends estypes.AggregationsSignificantLongTermsAggregate { export const fetchChangePointPValues = async ( esClient: ElasticsearchClient, params: AiopsExplainLogRateSpikesSchema, - fieldNames: string[] + fieldNames: string[], + logger: Logger, + emitError: (m: string) => void ): Promise => { const result: ChangePoint[] = []; @@ -101,7 +104,16 @@ export const fetchChangePointPValues = async ( const resp = await esClient.search(request); if (resp.aggregations === undefined) { - throw new Error('fetchChangePoint failed, did not return aggregations.'); + logger.error( + `Failed to fetch p-value aggregation for fieldName "${fieldName}", got: \n${JSON.stringify( + resp, + null, + 2 + )}` + ); + emitError(`Failed to fetch p-value aggregation for fieldName "${fieldName}".`); + // Still continue the analysis even if individual p-value queries fail. + continue; } const overallResult = resp.aggregations.change_point_p_value; diff --git a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts index 055c22397064f..c9444aaca22af 100644 --- a/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts +++ b/x-pack/plugins/aiops/server/routes/queries/fetch_frequent_items.ts @@ -10,6 +10,7 @@ import { uniq, uniqWith, pick, isEqual } from 'lodash'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import type { Logger } from '@kbn/logging'; import type { ChangePoint, FieldValuePair } from '@kbn/ml-agg-utils'; interface FrequentItemsAggregation extends estypes.AggregationsSamplerAggregation { @@ -53,9 +54,11 @@ export async function fetchFrequentItems( changePoints: ChangePoint[], timeFieldName: string, deviationMin: number, - deviationMax: number + deviationMax: number, + logger: Logger, + emitError: (m: string) => void ) { - // get unique fields that are left + // get unique fields from change points const fields = [...new Set(changePoints.map((t) => t.fieldName))]; // TODO add query params @@ -91,6 +94,8 @@ export async function fetchFrequentItems( sampleProbability = Math.min(0.5, minDocCount / totalDocCount); } + logger.debug(`frequent_items sample probability: ${sampleProbability}`); + // frequent items can be slow, so sample and use 10% min_support const aggs: Record = { sample: { @@ -103,7 +108,7 @@ export async function fetchFrequentItems( frequent_items: { minimum_set_size: 2, size: 200, - minimum_support: 0.01, + minimum_support: 0.1, fields: aggFields, }, }, @@ -125,12 +130,18 @@ export async function fetchFrequentItems( { maxRetries: 0 } ); - const totalDocCountFi = (body.hits.total as estypes.SearchTotalHits).value; - if (body.aggregations === undefined) { - throw new Error('fetchFrequentItems failed, did not return aggregations.'); + logger.error(`Failed to fetch frequent_items, got: \n${JSON.stringify(body, null, 2)}`); + emitError(`Failed to fetch frequent_items.`); + return { + fields: [], + df: [], + totalDocCount: 0, + }; } + const totalDocCountFi = (body.hits.total as estypes.SearchTotalHits).value; + const shape = body.aggregations.sample.fi.buckets.length; let maximum = shape; if (maximum > 50000) { diff --git a/x-pack/plugins/alerting/server/routes/resolve_rule.ts b/x-pack/plugins/alerting/server/routes/resolve_rule.ts index cde747f9272fe..b3576c0c5ed44 100644 --- a/x-pack/plugins/alerting/server/routes/resolve_rule.ts +++ b/x-pack/plugins/alerting/server/routes/resolve_rule.ts @@ -75,7 +75,7 @@ export const resolveRuleRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = (await context.alerting).getRulesClient(); const { id } = req.params; - const rule = await rulesClient.resolve({ id }); + const rule = await rulesClient.resolve({ id, includeSnoozeData: true }); return res.ok({ body: rewriteBodyRes(rule), }); diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 89ce20b59ae9b..d08f12f054a50 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -41,7 +41,11 @@ import { InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult, } from '@kbn/security-plugin/server'; import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; -import { TaskManagerStartContract, TaskStatus } from '@kbn/task-manager-plugin/server'; +import { + ConcreteTaskInstance, + TaskManagerStartContract, + TaskStatus, +} from '@kbn/task-manager-plugin/server'; import { IEvent, IEventLogClient, @@ -711,9 +715,11 @@ export class RulesClient { public async resolve({ id, includeLegacyId, + includeSnoozeData = false, }: { id: string; includeLegacyId?: boolean; + includeSnoozeData?: boolean; }): Promise> { const { saved_object: result, ...resolveResponse } = await this.unsecuredSavedObjectsClient.resolve('alert', id); @@ -746,7 +752,9 @@ export class RulesClient { result.attributes.alertTypeId, result.attributes, result.references, - includeLegacyId + includeLegacyId, + false, + includeSnoozeData ); return { @@ -2977,9 +2985,27 @@ export class RulesClient { this.ruleTypeRegistry.ensureRuleTypeEnabled(attributes.alertTypeId); - const taskDoc = attributes.scheduledTaskId - ? await this.taskManager.get(attributes.scheduledTaskId) - : null; + // Check that the rule is enabled + if (!attributes.enabled) { + return i18n.translate('xpack.alerting.rulesClient.runSoon.disabledRuleError', { + defaultMessage: 'Error running rule: rule is disabled', + }); + } + + let taskDoc: ConcreteTaskInstance | null = null; + try { + taskDoc = attributes.scheduledTaskId + ? await this.taskManager.get(attributes.scheduledTaskId) + : null; + } catch (err) { + return i18n.translate('xpack.alerting.rulesClient.runSoon.getTaskError', { + defaultMessage: 'Error running rule: {errMessage}', + values: { + errMessage: err.message, + }, + }); + } + if ( taskDoc && (taskDoc.status === TaskStatus.Claiming || taskDoc.status === TaskStatus.Running) @@ -2989,7 +3015,16 @@ export class RulesClient { }); } - await this.taskManager.runSoon(id); + try { + await this.taskManager.runSoon(attributes.scheduledTaskId ? attributes.scheduledTaskId : id); + } catch (err) { + return i18n.translate('xpack.alerting.rulesClient.runSoon.runSoonError', { + defaultMessage: 'Error running rule: {errMessage}', + values: { + errMessage: err.message, + }, + }); + } } public async listAlertTypes() { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts index 297c4b6d60fcc..b4a48be3a37fc 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts @@ -201,6 +201,58 @@ describe('resolve()', () => { `); }); + test('calls saved objects client with id and includeSnoozeData params', async () => { + const rulesClient = new RulesClient(rulesClientParams); + unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ + saved_object: { + id: '1', + type: 'alert', + attributes: { + legacyId: 'some-legacy-id', + alertTypeId: '123', + schedule: { interval: '10s' }, + params: { + bar: true, + }, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + snoozeSchedule: [ + { + duration: 10000, + rRule: { + dtstart: new Date().toISOString(), + tzid: 'UTC', + count: 1, + }, + }, + ], + muteAll: false, + actions: [ + { + group: 'default', + actionRef: 'action_0', + params: { + foo: true, + }, + }, + ], + notifyWhen: 'onActiveAlert', + }, + references: [ + { + name: 'action_0', + type: 'action', + id: '1', + }, + ], + }, + outcome: 'aliasMatch', + alias_target_id: '2', + }); + const result = await rulesClient.resolve({ id: '1', includeSnoozeData: true }); + expect(result.isSnoozedUntil).toBeTruthy(); + }); + test('should call useSavedObjectReferences.injectReferences if defined for rule type', async () => { const injectReferencesFn = jest.fn().mockReturnValue({ bar: true, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts index bea66a31ead25..138b167549c09 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts @@ -59,7 +59,7 @@ describe('runSoon()', () => { consumer: 'myApp', schedule: { interval: '10s' }, alertTypeId: 'myType', - enabled: false, + enabled: true, apiKey: 'MTIzOmFiYw==', apiKeyOwner: 'elastic', actions: [ @@ -179,7 +179,7 @@ describe('runSoon()', () => { }); test('does not run a rule if that rule is already running', async () => { - taskManager.get.mockResolvedValue({ + taskManager.get.mockResolvedValueOnce({ id: '1', scheduledAt: new Date(), attempts: 0, @@ -196,4 +196,32 @@ describe('runSoon()', () => { expect(message).toBe('Rule is already running'); expect(taskManager.runSoon).not.toHaveBeenCalled(); }); + + test('does not run a rule if that rule is disabled', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValue({ + ...existingRule, + attributes: { + ...existingRule.attributes, + enabled: false, + }, + }); + const message = await rulesClient.runSoon({ id: '1' }); + expect(message).toBe('Error running rule: rule is disabled'); + expect(taskManager.get).not.toHaveBeenCalled(); + expect(taskManager.runSoon).not.toHaveBeenCalled(); + }); + + test('gracefully handles errors getting task document', async () => { + taskManager.get.mockRejectedValueOnce(new Error('oh no!')); + const message = await rulesClient.runSoon({ id: '1' }); + expect(message).toBe('Error running rule: oh no!'); + expect(taskManager.runSoon).not.toHaveBeenCalled(); + }); + + test('gracefully handles errors calling runSoon', async () => { + taskManager.runSoon.mockRejectedValueOnce(new Error('fail!')); + const message = await rulesClient.runSoon({ id: '1' }); + expect(message).toBe('Error running rule: fail!'); + expect(taskManager.runSoon).toHaveBeenCalled(); + }); }); diff --git a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap index 1e340f6ffc755..508d8aac06dad 100644 --- a/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/apm_telemetry.test.ts.snap @@ -1075,6 +1075,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the "properties": { "kuery_fields": { "type": "keyword" + }, + "total": { + "type": "long" } } }, diff --git a/x-pack/plugins/apm/ftr_e2e/cypress.config.ts b/x-pack/plugins/apm/ftr_e2e/cypress.config.ts index 7a92b84ac36bd..bcccae43adc7e 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress.config.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress.config.ts @@ -6,9 +6,10 @@ */ import { defineConfig } from 'cypress'; -import { plugin } from './cypress/plugins'; +import { setupNodeEvents } from './setup_cypress_node_events'; module.exports = defineConfig({ + projectId: 'omwh6f', fileServerFolder: './cypress', fixturesFolder: './cypress/fixtures', screenshotsFolder: './cypress/screenshots', @@ -18,16 +19,16 @@ module.exports = defineConfig({ defaultCommandTimeout: 30000, execTimeout: 120000, pageLoadTimeout: 120000, - viewportHeight: 900, + viewportHeight: 1800, viewportWidth: 1440, - video: false, - screenshotOnRunFailure: false, + video: true, + videoUploadOnPasses: false, + screenshotOnRunFailure: true, + retries: { + runMode: 1, + }, e2e: { - // We've imported your old cypress plugins here. - // You may want to clean this up later by importing these. - setupNodeEvents(on, config) { - plugin(on, config); - }, + setupNodeEvents, baseUrl: 'http://localhost:5601', supportFile: './cypress/support/e2e.ts', specPattern: './cypress/e2e/**/*.cy.{js,jsx,ts,tsx}', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts index d1159efd0fc90..7d40105db192e 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/feature_flag/comparison.cy.ts @@ -36,19 +36,19 @@ describe('Comparison feature flag', () => { it('shows the comparison feature enabled in services overview', () => { cy.visitKibana('/app/apm/services'); cy.get('input[type="checkbox"]#comparison').should('be.checked'); - cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled'); + cy.getByTestSubj('comparisonSelect').should('not.be.disabled'); }); it('shows the comparison feature enabled in dependencies overview', () => { cy.visitKibana('/app/apm/dependencies'); cy.get('input[type="checkbox"]#comparison').should('be.checked'); - cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled'); + cy.getByTestSubj('comparisonSelect').should('not.be.disabled'); }); it('shows the comparison feature disabled in service map overview page', () => { cy.visitKibana('/app/apm/service-map'); cy.get('input[type="checkbox"]#comparison').should('be.checked'); - cy.get('[data-test-subj="comparisonSelect"]').should('not.be.disabled'); + cy.getByTestSubj('comparisonSelect').should('not.be.disabled'); }); }); @@ -71,7 +71,7 @@ describe('Comparison feature flag', () => { it('shows the comparison feature disabled in services overview', () => { cy.visitKibana('/app/apm/services'); cy.get('input[type="checkbox"]#comparison').should('not.be.checked'); - cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); + cy.getByTestSubj('comparisonSelect').should('be.disabled'); }); it('shows the comparison feature disabled in dependencies overview page', () => { @@ -81,13 +81,13 @@ describe('Comparison feature flag', () => { cy.visitKibana('/app/apm/dependencies'); cy.wait('@topDependenciesRequest'); cy.get('input[type="checkbox"]#comparison').should('not.be.checked'); - cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); + cy.getByTestSubj('comparisonSelect').should('be.disabled'); }); it('shows the comparison feature disabled in service map overview page', () => { cy.visitKibana('/app/apm/service-map'); cy.get('input[type="checkbox"]#comparison').should('not.be.checked'); - cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); + cy.getByTestSubj('comparisonSelect').should('be.disabled'); }); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/integration_settings/integration_policy.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/integration_settings/integration_policy.cy.ts index c25e6a6800311..5d275770e462d 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/integration_settings/integration_policy.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/integration_settings/integration_policy.cy.ts @@ -60,21 +60,19 @@ describe('when navigating to integration page', () => { cy.visitKibana(integrationsPath); // open integration policy form - cy.get('[data-test-subj="integration-card:epr:apm:featured').click(); + cy.getByTestSubj('integration-card:epr:apm:featured').click(); cy.contains('Elastic APM in Fleet').click(); cy.contains('a', 'APM integration').click(); - cy.get('[data-test-subj="addIntegrationPolicyButton"]').click(); + cy.getByTestSubj('addIntegrationPolicyButton').click(); }); it('checks validators for required fields', () => { const requiredFields = policyFormFields.filter((field) => field.required); requiredFields.map((field) => { - cy.get(`[data-test-subj="${field.selector}"`).clear(); - cy.get('[data-test-subj="createPackagePolicySaveButton"').should( - 'be.disabled' - ); - cy.get(`[data-test-subj="${field.selector}"`).type(field.value); + cy.getByTestSubj(field.selector).clear(); + cy.getByTestSubj('createPackagePolicySaveButton').should('be.disabled'); + cy.getByTestSubj(field.selector).type(field.value); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts index 5be39b4f082dc..47f8c537b100c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/agent_configurations.cy.ts @@ -90,7 +90,7 @@ describe('Agent configuration', () => { '/api/apm/settings/agent-configuration/environments?*' ).as('serviceEnvironmentApi'); cy.contains('Create configuration').click(); - cy.get('[data-test-subj="serviceNameComboBox"]') + cy.getByTestSubj('serviceNameComboBox') .click() .type('opbeans-node') .type('{enter}'); @@ -98,7 +98,7 @@ describe('Agent configuration', () => { cy.contains('opbeans-node').realClick(); cy.wait('@serviceEnvironmentApi'); - cy.get('[data-test-subj="serviceEnviromentComboBox"]') + cy.getByTestSubj('serviceEnviromentComboBox') .click({ force: true }) .type('prod') .type('{enter}'); @@ -115,14 +115,11 @@ describe('Agent configuration', () => { '/api/apm/settings/agent-configuration/environments' ).as('serviceEnvironmentApi'); cy.contains('Create configuration').click(); - cy.get('[data-test-subj="serviceNameComboBox"]') - .click() - .type('All') - .type('{enter}'); + cy.getByTestSubj('serviceNameComboBox').click().type('All').type('{enter}'); cy.contains('All').realClick(); cy.wait('@serviceEnvironmentApi'); - cy.get('[data-test-subj="serviceEnviromentComboBox"]') + cy.getByTestSubj('serviceEnviromentComboBox') .click({ force: true }) .type('All'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/custom_links.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/custom_links.cy.ts index 615ff2b49a85a..b680f745609bc 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/custom_links.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/settings/custom_links.cy.ts @@ -52,7 +52,7 @@ describe('Custom links', () => { it('creates custom link', () => { cy.visitKibana(basePath); - const emptyPrompt = cy.get('[data-test-subj="customLinksEmptyPrompt"]'); + const emptyPrompt = cy.getByTestSubj('customLinksEmptyPrompt'); cy.contains('Create custom link').click(); cy.contains('Create link'); cy.contains('Save').should('be.disabled'); @@ -63,7 +63,7 @@ describe('Custom links', () => { emptyPrompt.should('not.exist'); cy.contains('foo'); cy.contains('https://foo.com'); - cy.get('[data-test-subj="editCustomLink"]').click(); + cy.getByTestSubj('editCustomLink').click(); cy.contains('Delete').click(); }); @@ -71,14 +71,14 @@ describe('Custom links', () => { cy.visitKibana(basePath); // wait for empty prompt - cy.get('[data-test-subj="customLinksEmptyPrompt"]').should('be.visible'); + cy.getByTestSubj('customLinksEmptyPrompt').should('be.visible'); cy.contains('Create custom link').click(); - cy.get('[data-test-subj="filter-0"]').select('service.name'); + cy.getByTestSubj('filter-0').select('service.name'); cy.get( '[data-test-subj="service.name.value"] [data-test-subj="comboBoxSearchInput"]' ).type('foo'); - cy.get('[data-test-subj="filter-0"]').select('service.environment'); + cy.getByTestSubj('filter-0').select('service.environment'); cy.get( '[data-test-subj="service.environment.value"] [data-test-subj="comboBoxInput"]' ).should('not.contain', 'foo'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts index e989ea5cf0faf..2efebecf25756 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/power_user/storage_explorer/storage_explorer.cy.ts @@ -85,18 +85,31 @@ describe('Storage Explorer', () => { }); it('renders the storage timeseries chart', () => { - cy.get('[data-test-subj="storageExplorerTimeseriesChart"]'); + cy.getByTestSubj('storageExplorerTimeseriesChart'); }); it('has a list of services and environments', () => { - cy.contains('opbeans-node'); - cy.contains('opbeans-java'); - cy.contains('opbeans-rum'); + cy.contains( + '[data-test-subj="apmStorageExplorerServiceLink"]', + 'opbeans-node' + ); + cy.contains( + '[data-test-subj="apmStorageExplorerServiceLink"]', + 'opbeans-java' + ); + cy.contains( + '[data-test-subj="apmStorageExplorerServiceLink"]', + 'opbeans-rum' + ); cy.get('td:contains(production)').should('have.length', 3); }); it('when clicking on a service it loads the service overview for that service', () => { - cy.contains('opbeans-node').click({ force: true }); + cy.contains( + '[data-test-subj="apmStorageExplorerServiceLink"]', + 'opbeans-node' + ).click(); + cy.url().should('include', '/apm/services/opbeans-node/overview'); cy.contains('h1', 'opbeans-node'); }); @@ -115,7 +128,7 @@ describe('Storage Explorer', () => { it('with the correct environment when changing the environment', () => { cy.wait(mainAliasNames); - cy.get('[data-test-subj="environmentFilter"]').type('production'); + cy.getByTestSubj('environmentFilter').type('production'); cy.contains('button', 'production').click({ force: true }); @@ -148,7 +161,7 @@ describe('Storage Explorer', () => { it('with the correct lifecycle phase when changing the lifecycle phase', () => { cy.wait(mainAliasNames); - cy.get('[data-test-subj="storageExplorerLifecyclePhaseSelect"]').click(); + cy.getByTestSubj('storageExplorerLifecyclePhaseSelect').click(); cy.contains('button', 'Warm').click(); cy.expectAPIsToHaveBeenCalledWith({ @@ -180,13 +193,13 @@ describe('Storage Explorer', () => { cy.wait(mainAliasNames); cy.contains('opbeans-node'); - cy.get('[data-test-subj="storageDetailsButton_opbeans-node"]').click(); - cy.get('[data-test-subj="loadingSpinner"]').should('be.visible'); + cy.getByTestSubj('storageDetailsButton_opbeans-node').click(); + cy.getByTestSubj('loadingSpinner').should('be.visible'); cy.wait('@storageDetailsRequest'); cy.contains('Service storage details'); - cy.get('[data-test-subj="storageExplorerTimeseriesChart"]'); - cy.get('[data-test-subj="serviceStorageDetailsTable"]'); + cy.getByTestSubj('storageExplorerTimeseriesChart'); + cy.getByTestSubj('serviceStorageDetailsTable'); }); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/deep_links.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/deep_links.cy.ts index cfcabe85b5b2a..00b842f3265c7 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/deep_links.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/deep_links.cy.ts @@ -11,7 +11,7 @@ describe('APM deep links', () => { }); it('navigates to apm links on search elastic', () => { cy.visitKibana('/'); - cy.get('[data-test-subj="nav-search-input"]').type('APM'); + cy.getByTestSubj('nav-search-input').type('APM'); cy.contains('APM'); cy.contains('APM / Services'); cy.contains('APM / Traces'); @@ -23,17 +23,17 @@ describe('APM deep links', () => { cy.contains('APM').click({ force: true }); cy.url().should('include', '/apm/services'); - cy.get('[data-test-subj="nav-search-input"]').type('APM'); + cy.getByTestSubj('nav-search-input').type('APM'); // navigates to services page cy.contains('APM / Services').click({ force: true }); cy.url().should('include', '/apm/services'); - cy.get('[data-test-subj="nav-search-input"]').type('APM'); + cy.getByTestSubj('nav-search-input').type('APM'); // navigates to traces page cy.contains('APM / Traces').click({ force: true }); cy.url().should('include', '/apm/traces'); - cy.get('[data-test-subj="nav-search-input"]').type('APM'); + cy.getByTestSubj('nav-search-input').type('APM'); // navigates to service maps cy.contains('APM / Service Map').click({ force: true }); cy.url().should('include', '/apm/service-map'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts index 653809a8e04d3..2ef3ae42b1aac 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/dependencies.cy.ts @@ -66,9 +66,9 @@ describe('Dependencies', () => { })}` ); - cy.get('[data-test-subj="latencyChart"]'); - cy.get('[data-test-subj="throughputChart"]'); - cy.get('[data-test-subj="errorRateChart"]'); + cy.getByTestSubj('latencyChart'); + cy.getByTestSubj('throughputChart'); + cy.getByTestSubj('errorRateChart'); cy.contains('opbeans-java').click({ force: true }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts index 19de523c7ab1f..d00d8036df3bb 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/error_details.cy.ts @@ -68,13 +68,13 @@ describe('Error details', () => { it('shows errors distribution chart', () => { cy.visitKibana(errorDetailsPageHref); cy.contains('Error group 00000'); - cy.get('[data-test-subj="errorDistribution"]').contains('Occurrences'); + cy.getByTestSubj('errorDistribution').contains('Occurrences'); }); it('shows top erroneous transactions table', () => { cy.visitKibana(errorDetailsPageHref); cy.contains('Top 5 affected transactions'); - cy.get('[data-test-subj="topErroneousTransactionsTable"]') + cy.getByTestSubj('topErroneousTransactionsTable') .contains('a', 'GET /apple 🍎') .click(); cy.url().should('include', 'opbeans-java/transactions/view'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts index 301b3384ee2eb..8ac95d509d0bd 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/errors/errors_page.cy.ts @@ -81,14 +81,14 @@ describe('Errors page', () => { it('clicking on type adds a filter in the kuerybar', () => { cy.visitKibana(javaServiceErrorsPageHref); - cy.get('[data-test-subj="headerFilterKuerybar"]') + cy.getByTestSubj('headerFilterKuerybar') .invoke('val') .should('be.empty'); // `force: true` because Cypress says the element is 0x0 cy.contains('exception 0').click({ force: true, }); - cy.get('[data-test-subj="headerFilterKuerybar"]') + cy.getByTestSubj('headerFilterKuerybar') .its('length') .should('be.gt', 0); cy.get('table') @@ -158,7 +158,7 @@ describe('Check detailed statistics API with multiple errors', () => { ]) ); }); - cy.get('[data-test-subj="pagination-button-1"]').click(); + cy.getByTestSubj('pagination-button-1').click(); cy.wait('@errorsDetailedStatistics').then((payload) => { expect(payload.request.body.groupIds).eql( JSON.stringify([ diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts index 2ee2f4f019b12..e0c4a3aedd2b3 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/home.cy.ts @@ -69,7 +69,7 @@ describe('Home page', () => { cy.contains('Services'); cy.contains('opbeans-rum').click({ force: true }); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'page-load' ); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts index c4e87ac15fbe1..4f72e968d81f8 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/header_filters/header_filters.cy.ts @@ -44,7 +44,7 @@ describe('Service inventory - header filters', () => { cy.contains('Services'); cy.contains('opbeans-node'); cy.contains('service 1'); - cy.get('[data-test-subj="headerFilterKuerybar"]') + cy.getByTestSubj('headerFilterKuerybar') .type(`service.name: "${specialServiceName}"`) .type('{enter}'); cy.contains('service 1'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts index 015df91d792e9..2d40c690a8c92 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_inventory/service_inventory.cy.ts @@ -93,7 +93,7 @@ describe('Service inventory', () => { it('with the correct environment when changing the environment', () => { cy.wait(mainAliasNames); - cy.get('[data-test-subj="environmentFilter"]').type('production'); + cy.getByTestSubj('environmentFilter').type('production'); cy.contains('button', 'production').click(); @@ -175,7 +175,7 @@ describe('Service inventory', () => { ]) ); }); - cy.get('[data-test-subj="pagination-button-1"]').click(); + cy.getByTestSubj('pagination-button-1').click(); cy.wait('@detailedStatisticsRequest').then((payload) => { expect(payload.request.body.serviceNames).eql( JSON.stringify([ diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lamba.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lambda.cy.ts similarity index 100% rename from x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lamba.cy.ts rename to x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/aws_lambda/aws_lambda.cy.ts diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts index b175eb0430ed4..d693148010c7e 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/errors_table.cy.ts @@ -50,16 +50,12 @@ describe('Errors table', () => { it('clicking on type adds a filter in the kuerybar and navigates to errors page', () => { cy.visitKibana(serviceOverviewHref); - cy.get('[data-test-subj="headerFilterKuerybar"]') - .invoke('val') - .should('be.empty'); + cy.getByTestSubj('headerFilterKuerybar').invoke('val').should('be.empty'); // `force: true` because Cypress says the element is 0x0 cy.contains('Exception').click({ force: true, }); - cy.get('[data-test-subj="headerFilterKuerybar"]') - .its('length') - .should('be.gt', 0); + cy.getByTestSubj('headerFilterKuerybar').its('length').should('be.gt', 0); cy.get('table').find('td:contains("Exception")').should('have.length', 1); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts index 6376d544821aa..8a25024506696 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/header_filters.cy.ts @@ -77,13 +77,13 @@ describe('Service overview - header filters', () => { cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-node'); cy.url().should('not.include', 'transactionType'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'request' ); - cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker'); + cy.getByTestSubj('headerFilterTransactionType').select('Worker'); cy.url().should('include', 'transactionType=Worker'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); @@ -94,7 +94,7 @@ describe('Service overview - header filters', () => { cy.intercept('GET', endpoint).as(name); }); cy.visitKibana(serviceOverviewHref); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'request' ); @@ -104,9 +104,9 @@ describe('Service overview - header filters', () => { value: 'transactionType=request', }); - cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker'); + cy.getByTestSubj('headerFilterTransactionType').select('Worker'); cy.url().should('include', 'transactionType=Worker'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); @@ -129,18 +129,12 @@ describe('Service overview - header filters', () => { }) ); cy.contains('opbeans-java'); - cy.get('[data-test-subj="headerFilterKuerybar"]').type('transaction.n'); + cy.getByTestSubj('headerFilterKuerybar').type('transaction.n'); cy.contains('transaction.name'); - cy.get('[data-test-subj="suggestionContainer"]') - .find('li') - .first() - .click(); - cy.get('[data-test-subj="headerFilterKuerybar"]').type(':'); - cy.get('[data-test-subj="suggestionContainer"]') - .find('li') - .first() - .click(); - cy.get('[data-test-subj="headerFilterKuerybar"]').type('{enter}'); + cy.getByTestSubj('suggestionContainer').find('li').first().click(); + cy.getByTestSubj('headerFilterKuerybar').type(':'); + cy.getByTestSubj('suggestionContainer').find('li').first().click(); + cy.getByTestSubj('headerFilterKuerybar').type('{enter}'); cy.url().should('include', '&kuery=transaction.name'); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts index 03653df2b0bb6..578b116a10592 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/instances_table.cy.ts @@ -63,7 +63,7 @@ describe('Instances table', () => { it('shows empty message', () => { cy.visitKibana(testServiveHref); cy.contains('test-service'); - cy.get('[data-test-subj="serviceInstancesTableContainer"]').contains( + cy.getByTestSubj('serviceInstancesTableContainer').contains( 'No instances found' ); }); @@ -77,9 +77,7 @@ describe('Instances table', () => { it('hides instances table', () => { cy.visitKibana(serviceRumOverviewHref); cy.contains('opbeans-rum'); - cy.get('[data-test-subj="serviceInstancesTableContainer"]').should( - 'not.exist' - ); + cy.getByTestSubj('serviceInstancesTableContainer').should('not.exist'); }); }); @@ -109,10 +107,8 @@ describe('Instances table', () => { cy.contains(serviceNodeName); cy.wait('@instancesDetailsRequest'); - cy.get( - `[data-test-subj="instanceDetailsButton_${serviceNodeName}"]` - ).realClick(); - cy.get('[data-test-subj="loadingSpinner"]').should('be.visible'); + cy.getByTestSubj(`instanceDetailsButton_${serviceNodeName}`).realClick(); + cy.getByTestSubj('loadingSpinner').should('be.visible'); cy.wait('@instanceDetailsRequest').then(() => { cy.contains('Service'); }); @@ -130,9 +126,7 @@ describe('Instances table', () => { cy.contains(serviceNodeName); cy.wait('@instancesDetailsRequest'); - cy.get( - `[data-test-subj="instanceActionsButton_${serviceNodeName}"]` - ).click(); + cy.getByTestSubj(`instanceActionsButton_${serviceNodeName}`).click(); cy.contains('Pod logs'); cy.contains('Pod metrics'); // cy.contains('Container logs'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts index e8319c8efafeb..8173e94557b29 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/service_overview.cy.ts @@ -109,13 +109,13 @@ describe('Service Overview', () => { cy.contains('opbeans-node'); // set skipFailures to true to not fail the test when there are accessibility failures checkA11y({ skipFailures: true }); - cy.get('[data-test-subj="latencyChart"]'); - cy.get('[data-test-subj="throughput"]'); - cy.get('[data-test-subj="transactionsGroupTable"]'); - cy.get('[data-test-subj="serviceOverviewErrorsTable"]'); - cy.get('[data-test-subj="dependenciesTable"]'); - cy.get('[data-test-subj="instancesLatencyDistribution"]'); - cy.get('[data-test-subj="serviceOverviewInstancesTable"]'); + cy.getByTestSubj('latencyChart'); + cy.getByTestSubj('throughput'); + cy.getByTestSubj('transactionsGroupTable'); + cy.getByTestSubj('serviceOverviewErrorsTable'); + cy.getByTestSubj('dependenciesTable'); + cy.getByTestSubj('instancesLatencyDistribution'); + cy.getByTestSubj('serviceOverviewInstancesTable'); }); }); @@ -134,17 +134,17 @@ describe('Service Overview', () => { cy.wait('@transactionTypesRequest'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'request' ); - cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').select('Worker'); + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); cy.contains('Transactions').click(); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); @@ -159,18 +159,18 @@ describe('Service Overview', () => { cy.visitKibana(baseUrl); cy.wait('@transactionTypesRequest'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'request' ); - cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').select('Worker'); + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); cy.contains('View transactions').click(); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); @@ -226,7 +226,7 @@ describe('Service Overview', () => { 'suggestionsRequest' ); - cy.get('[data-test-subj="environmentFilter"] input').type('production', { + cy.getByTestSubj('environmentFilter').find('input').type('production', { force: true, }); @@ -235,9 +235,7 @@ describe('Service Overview', () => { value: 'fieldValue=production', }); - cy.get( - '[data-test-subj="comboBoxOptionsList environmentFilter-optionsList"]' - ) + cy.getByTestSubj('comboBoxOptionsList environmentFilter-optionsList') .contains('production') .click({ force: true }); @@ -271,11 +269,11 @@ describe('Service Overview', () => { }); it('when selecting a different comparison window', () => { - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d'); + cy.getByTestSubj('comparisonSelect').should('have.value', '1d'); // selects another comparison type - cy.get('[data-test-subj="comparisonSelect"]').select('1w'); - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1w'); + cy.getByTestSubj('comparisonSelect').select('1w'); + cy.getByTestSubj('comparisonSelect').should('have.value', '1w'); cy.expectAPIsToHaveBeenCalledWith({ apisIntercepted: aliasNamesWithComparison, value: 'offset', diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts index 718a2a4a06cf7..bce3da42d5a3f 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/time_comparison.cy.ts @@ -101,18 +101,18 @@ describe('Service overview: Time Comparison', () => { cy.visitKibana(serviceOverviewPath); cy.contains('opbeans-java'); // opens the page with "Day before" selected - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d'); + cy.getByTestSubj('comparisonSelect').should('have.value', '1d'); // selects another comparison type - cy.get('[data-test-subj="comparisonSelect"]').select('1w'); - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1w'); + cy.getByTestSubj('comparisonSelect').select('1w'); + cy.getByTestSubj('comparisonSelect').should('have.value', '1w'); }); it('changes comparison type when a new time range is selected', () => { cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); // Time comparison default value - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d'); + cy.getByTestSubj('comparisonSelect').should('have.value', '1d'); cy.contains('Day before'); cy.contains('Week before'); @@ -121,17 +121,14 @@ describe('Service overview: Time Comparison', () => { '2021-10-20T00:00:00.000Z' ); - cy.get('[data-test-subj="superDatePickerApplyTimeButton"]').click(); + cy.getByTestSubj('superDatePickerApplyTimeButton').click(); - cy.get('[data-test-subj="comparisonSelect"]').should( - 'have.value', - '864000000ms' - ); - cy.get('[data-test-subj="comparisonSelect"]').should( + cy.getByTestSubj('comparisonSelect').should('have.value', '864000000ms'); + cy.getByTestSubj('comparisonSelect').should( 'not.contain.text', 'Day before' ); - cy.get('[data-test-subj="comparisonSelect"]').should( + cy.getByTestSubj('comparisonSelect').should( 'not.contain.text', 'Week before' ); @@ -141,17 +138,14 @@ describe('Service overview: Time Comparison', () => { cy.contains('Week before'); cy.changeTimeRange('Last 24 hours'); - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1d'); + cy.getByTestSubj('comparisonSelect').should('have.value', '1d'); cy.contains('Day before'); cy.contains('Week before'); cy.changeTimeRange('Last 7 days'); - cy.get('[data-test-subj="comparisonSelect"]').should('have.value', '1w'); - cy.get('[data-test-subj="comparisonSelect"]').should( - 'contain.text', - 'Week before' - ); - cy.get('[data-test-subj="comparisonSelect"]').should( + cy.getByTestSubj('comparisonSelect').should('have.value', '1w'); + cy.getByTestSubj('comparisonSelect').should('contain.text', 'Week before'); + cy.getByTestSubj('comparisonSelect').should( 'not.contain.text', 'Day before' ); @@ -170,7 +164,7 @@ describe('Service overview: Time Comparison', () => { ); cy.contains('opbeans-java'); cy.wait('@throughputChartRequest'); - cy.get('[data-test-subj="throughput"]') + cy.getByTestSubj('throughput') .get('#echHighlighterClipPath__throughput') .realHover({ position: 'center' }); cy.contains('Week before'); @@ -186,17 +180,17 @@ describe('Service overview: Time Comparison', () => { cy.contains('opbeans-java'); // Comparison is enabled by default - cy.get('[data-test-subj="comparisonSelect"]').should('be.enabled'); + cy.getByTestSubj('comparisonSelect').should('be.enabled'); // toggles off comparison cy.contains('Comparison').click(); - cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); + cy.getByTestSubj('comparisonSelect').should('be.disabled'); }); it('calls APIs without comparison time range', () => { cy.visitKibana(serviceOverviewHref); - cy.get('[data-test-subj="comparisonSelect"]').should('be.enabled'); + cy.getByTestSubj('comparisonSelect').should('be.enabled'); const offset = `offset=1d`; // When the page loads it fetches all APIs with comparison time range @@ -212,7 +206,7 @@ describe('Service overview: Time Comparison', () => { // toggles off comparison cy.contains('Comparison').click(); - cy.get('[data-test-subj="comparisonSelect"]').should('be.disabled'); + cy.getByTestSubj('comparisonSelect').should('be.disabled'); // When comparison is disabled APIs are called withou comparison time range cy.wait(apisToIntercept.map(({ name }) => `@${name}`)).then( (interceptions) => { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts index cddba048e8a18..60b36b10ee4a3 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/span_links.cy.ts @@ -50,8 +50,8 @@ describe('Span links', () => { ); cy.contains('Transaction A').click(); cy.contains('2 Span links'); - cy.get( - `[data-test-subj="spanLinksBadge_${ids.producerInternalOnlyIds.spanAId}"]` + cy.getByTestSubj( + `spanLinksBadge_${ids.producerInternalOnlyIds.spanAId}` ).realHover(); cy.contains('2 Span links found'); cy.contains('2 incoming'); @@ -64,8 +64,8 @@ describe('Span links', () => { ); cy.contains('Transaction B').click(); cy.contains('2 Span links'); - cy.get( - `[data-test-subj="spanLinksBadge_${ids.producerExternalOnlyIds.spanBId}"]` + cy.getByTestSubj( + `spanLinksBadge_${ids.producerExternalOnlyIds.spanBId}` ).realHover(); cy.contains('2 Span links found'); cy.contains('1 incoming'); @@ -78,8 +78,8 @@ describe('Span links', () => { ); cy.contains('Transaction C').click(); cy.contains('2 Span links'); - cy.get( - `[data-test-subj="spanLinksBadge_${ids.producerConsumerIds.transactionCId}"]` + cy.getByTestSubj( + `spanLinksBadge_${ids.producerConsumerIds.transactionCId}` ).realHover(); cy.contains('2 Span links found'); cy.contains('1 incoming'); @@ -92,8 +92,8 @@ describe('Span links', () => { ); cy.contains('Transaction C').click(); cy.contains('1 Span link'); - cy.get( - `[data-test-subj="spanLinksBadge_${ids.producerConsumerIds.spanCId}"]` + cy.getByTestSubj( + `spanLinksBadge_${ids.producerConsumerIds.spanCId}` ).realHover(); cy.contains('1 Span link found'); cy.contains('1 incoming'); @@ -106,8 +106,8 @@ describe('Span links', () => { ); cy.contains('Transaction D').click(); cy.contains('2 Span links'); - cy.get( - `[data-test-subj="spanLinksBadge_${ids.producerMultipleIds.transactionDId}"]` + cy.getByTestSubj( + `spanLinksBadge_${ids.producerMultipleIds.transactionDId}` ).realHover(); cy.contains('2 Span links found'); cy.contains('0 incoming'); @@ -120,8 +120,8 @@ describe('Span links', () => { ); cy.contains('Transaction D').click(); cy.contains('2 Span links'); - cy.get( - `[data-test-subj="spanLinksBadge_${ids.producerMultipleIds.spanEId}"]` + cy.getByTestSubj( + `spanLinksBadge_${ids.producerMultipleIds.spanEId}` ).realHover(); cy.contains('2 Span links found'); cy.contains('0 incoming'); @@ -136,7 +136,7 @@ describe('Span links', () => { ); cy.contains('Transaction A').click(); cy.contains('Span A').click(); - cy.get('[data-test-subj="spanLinksTab"]').click(); + cy.getByTestSubj('spanLinksTab').click(); cy.contains('producer-consumer') .should('have.attr', 'href') .and('include', '/services/producer-consumer/overview'); @@ -155,7 +155,7 @@ describe('Span links', () => { 'include', `link-to/transaction/${ids.producerMultipleIds.transactionDId}?waterfallItemId=${ids.producerMultipleIds.transactionDId}` ); - cy.get('[data-test-subj="spanLinkTypeSelect"]').should( + cy.getByTestSubj('spanLinkTypeSelect').should( 'contain.text', 'Outgoing links (0)' ); @@ -167,7 +167,7 @@ describe('Span links', () => { ); cy.contains('Transaction B').click(); cy.contains('Span B').click(); - cy.get('[data-test-subj="spanLinksTab"]').click(); + cy.getByTestSubj('spanLinksTab').click(); cy.contains('consumer-multiple') .should('have.attr', 'href') @@ -178,9 +178,7 @@ describe('Span links', () => { 'include', `link-to/transaction/${ids.producerMultipleIds.transactionDId}?waterfallItemId=${ids.producerMultipleIds.spanEId}` ); - cy.get('[data-test-subj="spanLinkTypeSelect"]').select( - 'Outgoing links (1)' - ); + cy.getByTestSubj('spanLinkTypeSelect').select('Outgoing links (1)'); cy.contains('Unknown'); cy.contains('trace#1-span#1'); }); @@ -193,7 +191,7 @@ describe('Span links', () => { cy.get( `[aria-controls="${ids.producerConsumerIds.transactionCId}"]` ).click(); - cy.get('[data-test-subj="spanLinksTab"]').click(); + cy.getByTestSubj('spanLinksTab').click(); cy.contains('consumer-multiple') .should('have.attr', 'href') @@ -205,9 +203,7 @@ describe('Span links', () => { `link-to/transaction/${ids.producerMultipleIds.transactionDId}?waterfallItemId=${ids.producerMultipleIds.spanEId}` ); - cy.get('[data-test-subj="spanLinkTypeSelect"]').select( - 'Outgoing links (1)' - ); + cy.getByTestSubj('spanLinkTypeSelect').select('Outgoing links (1)'); cy.contains('producer-internal-only') .should('have.attr', 'href') .and('include', '/services/producer-internal-only/overview'); @@ -225,7 +221,7 @@ describe('Span links', () => { ); cy.contains('Transaction C').click(); cy.contains('Span C').click(); - cy.get('[data-test-subj="spanLinksTab"]').click(); + cy.getByTestSubj('spanLinksTab').click(); cy.contains('consumer-multiple') .should('have.attr', 'href') @@ -237,7 +233,7 @@ describe('Span links', () => { `link-to/transaction/${ids.producerMultipleIds.transactionDId}?waterfallItemId=${ids.producerMultipleIds.transactionDId}` ); - cy.get('[data-test-subj="spanLinkTypeSelect"]').should( + cy.getByTestSubj('spanLinkTypeSelect').should( 'contain.text', 'Outgoing links (0)' ); @@ -251,7 +247,7 @@ describe('Span links', () => { cy.get( `[aria-controls="${ids.producerMultipleIds.transactionDId}"]` ).click(); - cy.get('[data-test-subj="spanLinksTab"]').click(); + cy.getByTestSubj('spanLinksTab').click(); cy.contains('producer-consumer') .should('have.attr', 'href') @@ -273,7 +269,7 @@ describe('Span links', () => { `link-to/transaction/${ids.producerInternalOnlyIds.transactionAId}?waterfallItemId=${ids.producerInternalOnlyIds.spanAId}` ); - cy.get('[data-test-subj="spanLinkTypeSelect"]').should( + cy.getByTestSubj('spanLinkTypeSelect').should( 'contain.text', 'Incoming links (0)' ); @@ -285,7 +281,7 @@ describe('Span links', () => { ); cy.contains('Transaction D').click(); cy.contains('Span E').click(); - cy.get('[data-test-subj="spanLinksTab"]').click(); + cy.getByTestSubj('spanLinksTab').click(); cy.contains('producer-external-only') .should('have.attr', 'href') @@ -307,7 +303,7 @@ describe('Span links', () => { `link-to/transaction/${ids.producerConsumerIds.transactionCId}?waterfallItemId=${ids.producerConsumerIds.transactionCId}` ); - cy.get('[data-test-subj="spanLinkTypeSelect"]').should( + cy.getByTestSubj('spanLinkTypeSelect').should( 'contain.text', 'Incoming links (0)' ); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts index 5172a5f167fc9..09bd37f5b0b6c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transaction_details/transaction_details.cy.ts @@ -42,15 +42,15 @@ describe('Transaction details', () => { it('shows transaction name and transaction charts', () => { cy.contains('h2', 'GET /api/product'); - cy.get('[data-test-subj="latencyChart"]'); - cy.get('[data-test-subj="throughput"]'); - cy.get('[data-test-subj="transactionBreakdownChart"]'); - cy.get('[data-test-subj="errorRate"]'); + cy.getByTestSubj('latencyChart'); + cy.getByTestSubj('throughput'); + cy.getByTestSubj('transactionBreakdownChart'); + cy.getByTestSubj('errorRate'); }); it('shows top errors table', () => { cy.contains('Top 5 errors'); - cy.get('[data-test-subj="topErrorsForTransactionTable"]') + cy.getByTestSubj('topErrorsForTransactionTable') .contains('a', '[MockError] Foo') .click(); cy.url().should('include', 'opbeans-java/errors'); @@ -58,7 +58,7 @@ describe('Transaction details', () => { describe('when navigating to a trace sample', () => { it('keeps the same trace sample after reloading the page', () => { - cy.get('[data-test-subj="pagination-button-last"]').click(); + cy.getByTestSubj('pagination-button-last').click(); cy.url().then((url) => { cy.reload(); cy.url().should('eq', url); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts index 83753b7fe2595..2e7e0d336cd5d 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/transactions_overview/transactions_overview.cy.ts @@ -49,17 +49,17 @@ describe('Transactions Overview', () => { it('persists transaction type selected when navigating to Overview tab', () => { cy.visitKibana(serviceTransactionsHref); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'request' ); - cy.get('[data-test-subj="headerFilterTransactionType"]').select('Worker'); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').select('Worker'); + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); cy.get('a[href*="/app/apm/services/opbeans-node/overview"]').click(); - cy.get('[data-test-subj="headerFilterTransactionType"]').should( + cy.getByTestSubj('headerFilterTransactionType').should( 'have.value', 'Worker' ); 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 7830e791c3655..9e6e0189e636c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -52,15 +52,19 @@ Cypress.Commands.add( } ); +Cypress.Commands.add('getByTestSubj', (selector: string) => { + return cy.get(`[data-test-subj="${selector}"]`); +}); + Cypress.Commands.add('changeTimeRange', (value: string) => { - cy.get('[data-test-subj="superDatePickerToggleQuickMenuButton"]').click(); + cy.getByTestSubj('superDatePickerToggleQuickMenuButton').click(); cy.contains(value).click(); }); Cypress.Commands.add('visitKibana', (url: string) => { cy.visit(url); - cy.get('[data-test-subj="kbnLoadingMessage"]').should('exist'); - cy.get('[data-test-subj="kbnLoadingMessage"]').should('not.exist', { + cy.getByTestSubj('kbnLoadingMessage').should('exist'); + cy.getByTestSubj('kbnLoadingMessage').should('not.exist', { timeout: 50000, }); }); @@ -70,13 +74,13 @@ Cypress.Commands.add( (start: string, end: string) => { const format = 'MMM D, YYYY @ HH:mm:ss.SSS'; - cy.get('[data-test-subj="superDatePickerstartDatePopoverButton"]').click(); - cy.get('[data-test-subj="superDatePickerAbsoluteDateInput"]') + cy.getByTestSubj('superDatePickerstartDatePopoverButton').click(); + cy.getByTestSubj('superDatePickerAbsoluteDateInput') .eq(0) .clear({ force: true }) .type(moment(start).format(format), { force: true }); - cy.get('[data-test-subj="superDatePickerendDatePopoverButton"]').click(); - cy.get('[data-test-subj="superDatePickerAbsoluteDateInput"]') + cy.getByTestSubj('superDatePickerendDatePopoverButton').click(); + cy.getByTestSubj('superDatePickerAbsoluteDateInput') .eq(1) .clear({ force: true }) .type(moment(end).format(format), { force: true }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts index 2235847e584a4..5d59d4691820a 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/types.d.ts @@ -22,5 +22,6 @@ declare namespace Cypress { value: string; }): void; updateAdvancedSettings(settings: Record): void; + getByTestSubj(selector: string): Chainable>; } } diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/plugins/index.ts b/x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts similarity index 62% rename from x-pack/plugins/apm/ftr_e2e/cypress/plugins/index.ts rename to x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts index 8adaad0b71c63..0e3cd47966960 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/plugins/index.ts +++ b/x-pack/plugins/apm/ftr_e2e/setup_cypress_node_events.ts @@ -11,28 +11,13 @@ import { LogLevel, } from '@kbn/apm-synthtrace'; import { createEsClientForTesting } from '@kbn/test'; +import { some } from 'lodash'; +import del from 'del'; -// *********************************************************** -// This example plugins/index.ts can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -/** - * @type {Cypress.PluginConfig} - */ - -export const plugin: Cypress.PluginConfig = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config - +export function setupNodeEvents( + on: Cypress.PluginEvents, + config: Cypress.PluginConfigOptions +) { const client = createEsClientForTesting({ esUrl: config.env.ES_NODE, requestTimeout: config.env.ES_REQUEST_TIMEOUT, @@ -65,4 +50,24 @@ export const plugin: Cypress.PluginConfig = (on, config) => { return null; }, }); -}; + + on('after:spec', (spec, results) => { + // Delete videos that have no failures or retries + if (results && results.video) { + const failures = some(results.tests, (test) => { + return some(test.attempts, { state: 'failed' }); + }); + if (!failures) { + del(results.video); + } + } + }); + + on('before:browser:launch', (browser, launchOptions) => { + if (browser.name === 'electron' && browser.isHeadless) { + launchOptions.preferences.width = 1440; + launchOptions.preferences.height = 1600; + } + return launchOptions; + }); +} diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index 0a0b17a4e273b..c1bda0d2acfe6 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -267,9 +267,9 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { label: i18n.translate('xpack.apm.serviceDetails.metricsTabLabel', { defaultMessage: 'Metrics', }), - append: isServerlessAgent(runtimeName) ? ( + append: isServerlessAgent(runtimeName) && ( - ) : undefined, + ), hidden: isMetricsTabHidden({ agentName, runtimeName, @@ -318,6 +318,9 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { label: i18n.translate('xpack.apm.home.serviceLogsTabLabel', { defaultMessage: 'Logs', }), + append: isServerlessAgent(runtimeName) && ( + + ), hidden: !agentName || isRumAgentName(agentName) || isMobileAgentName(agentName), }, diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts index b69aa1e6e0196..bf03b999f1046 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { savedObjectsClientMock } from '@kbn/core-saved-objects-api-server-mocks'; import { ApmIndicesConfig } from '../../../routes/settings/apm_indices/get_apm_indices'; import { tasks } from './tasks'; import { @@ -444,4 +445,49 @@ describe('data telemetry collection tasks', () => { }); }); }); + + describe('service groups', () => { + const task = tasks.find((t) => t.name === 'service_groups'); + const savedObjectsClient = savedObjectsClientMock.create(); + + savedObjectsClient.find.mockResolvedValue({ + page: 1, + per_page: 500, + total: 2, + saved_objects: [ + { + type: 'apm-service-group', + id: '0b6157f0-44bd-11ed-bdb7-bffab551cd4d', + namespaces: ['default'], + attributes: { + color: '#5094C4', + kuery: 'service.environment: production', + groupName: 'production', + }, + references: [], + score: 1, + }, + { + type: 'apm-service-group', + id: '0b6157f0-44bd-11ed-bdb7-bffab551cd4d', + namespaces: ['default'], + attributes: { + color: '#5094C4', + kuery: 'agent.name: go', + groupName: 'agent', + }, + references: [], + score: 0, + }, + ], + }); + it('returns service group stats', async () => { + expect(await task?.executor({ savedObjectsClient } as any)).toEqual({ + service_groups: { + kuery_fields: ['service.environment', 'agent.name'], + total: 2, + }, + }); + }); + }); }); diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts index 430930fb3f916..12e89ef32832c 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/collect_data_telemetry/tasks.ts @@ -15,6 +15,7 @@ import { AGENT_NAMES, RUM_AGENT_NAMES } from '../../../../common/agent_name'; import { SavedServiceGroup, APM_SERVICE_GROUP_SAVED_OBJECT_TYPE, + MAX_NUMBER_OF_SERVICE_GROUPS, } from '../../../../common/service_groups'; import { getKueryFields } from '../../helpers/get_kuery_fields'; import { @@ -1134,7 +1135,7 @@ export const tasks: TelemetryTask[] = [ const response = await savedObjectsClient.find({ type: APM_SERVICE_GROUP_SAVED_OBJECT_TYPE, page: 1, - perPage: 50, + perPage: MAX_NUMBER_OF_SERVICE_GROUPS, sortField: 'updated_at', sortOrder: 'desc', }); @@ -1148,6 +1149,7 @@ export const tasks: TelemetryTask[] = [ return { service_groups: { kuery_fields: kueryFields, + total: response.total ?? 0, }, }; }, diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts index f33c9e03f6caa..4430389785e1d 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/schema.ts @@ -235,6 +235,7 @@ export const apmSchema: MakeSchemaFrom = { }, service_groups: { kuery_fields: { type: 'array', items: { type: 'keyword' } }, + total: long, }, per_service: { type: 'array', items: { ...apmPerServiceSchema } }, tasks: { diff --git a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts index 16e1b926d578e..ceadcbfc1ded2 100644 --- a/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts +++ b/x-pack/plugins/apm/server/lib/apm_telemetry/types.ts @@ -173,6 +173,7 @@ export interface APMUsage { }; service_groups: { kuery_fields: string[]; + total: number; }; per_service: APMPerService[]; tasks: Record< diff --git a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts index 4cd9df6bf2137..5cc9f8bb427cf 100644 --- a/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/create_es_client/create_infra_metrics_client/create_infra_metrics_client.ts @@ -9,7 +9,10 @@ import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { APMRouteHandlerResources } from '../../../../routes/typings'; import { getInfraMetricIndices } from '../../get_infra_metric_indices'; -type InfraMetricsSearchParams = Omit; +type InfraMetricsSearchParams = Omit & { + size: number; + track_total_hits: boolean | number; +}; export type InfraMetricsClient = ReturnType; diff --git a/x-pack/plugins/apm/server/routes/infrastructure/get_host_names.ts b/x-pack/plugins/apm/server/routes/infrastructure/get_host_names.ts index 8f47c2d1664bf..257233fada9cb 100644 --- a/x-pack/plugins/apm/server/routes/infrastructure/get_host_names.ts +++ b/x-pack/plugins/apm/server/routes/infrastructure/get_host_names.ts @@ -29,6 +29,7 @@ export async function getContainerHostNames({ const response = await infraMetricsClient.search({ size: 0, + track_total_hits: false, query: { bool: { filter: [ diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts index e66d855d1be99..5a78f5d97d5e8 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/cold_start_duration.ts @@ -11,6 +11,7 @@ import { FAAS_COLDSTART_DURATION } from '../../../../../common/elasticsearch_fie import { Setup } from '../../../../lib/helpers/setup_request'; import { fetchAndTransformMetrics } from '../../fetch_and_transform_metrics'; import { ChartBase } from '../../types'; +import { isFiniteNumber } from '../../../../../common/utils/is_finite_number'; const chartBase: ChartBase = { title: i18n.translate('xpack.apm.agentMetrics.serverless.coldStartDuration', { @@ -37,7 +38,7 @@ const chartBase: ChartBase = { ), }; -export function getColdStartDuration({ +export async function getColdStartDuration({ environment, kuery, setup, @@ -52,7 +53,7 @@ export function getColdStartDuration({ start: number; end: number; }) { - return fetchAndTransformMetrics({ + const coldStartDurationMetric = await fetchAndTransformMetrics({ environment, kuery, setup, @@ -64,4 +65,24 @@ export function getColdStartDuration({ additionalFilters: [{ exists: { field: FAAS_COLDSTART_DURATION } }], operationName: 'get_cold_start_duration', }); + + const [series] = coldStartDurationMetric.series; + + const data = series.data.map(({ x, y }) => ({ + x, + // Cold start duration duration is stored in ms, convert it to microseconds so it uses the same unit as the other charts + y: isFiniteNumber(y) ? y * 1000 : y, + })); + + return { + ...coldStartDurationMetric, + series: [ + { + ...series, + // Cold start duration duration is stored in ms, convert it to microseconds + overallValue: series.overallValue * 1000, + data, + }, + ], + }; } diff --git a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts b/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts index 0db9385615d2a..0a27c66ef036b 100644 --- a/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts +++ b/x-pack/plugins/apm/server/routes/metrics/by_agent/serverless/serverless_function_latency.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import { euiLightVars as theme } from '@kbn/ui-theme'; import { FAAS_BILLED_DURATION } from '../../../../../common/elasticsearch_fieldnames'; import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types'; +import { isFiniteNumber } from '../../../../../common/utils/is_finite_number'; import { getVizColorForIndex } from '../../../../../common/viz_colors'; import { Setup } from '../../../../lib/helpers/setup_request'; import { getLatencyTimeseries } from '../../../transactions/get_latency_charts'; @@ -123,8 +124,23 @@ export async function getServerlessFunctionLatency({ getServerlessLantecySeries({ ...options, searchAggregatedTransactions }), ]); + const [series] = billedDurationMetrics.series; + const data = series.data.map(({ x, y }) => ({ + x, + // Billed duration is stored in ms, convert it to microseconds so it uses the same unit as the other chart + y: isFiniteNumber(y) ? y * 1000 : y, + })); + return { ...billedDurationMetrics, - series: [...billedDurationMetrics.series, ...serverlessDurationSeries], + series: [ + { + ...series, + // Billed duration is stored in ms, convert it to microseconds + overallValue: series.overallValue * 1000, + data, + }, + ...serverlessDurationSeries, + ], }; } diff --git a/x-pack/plugins/apm/server/routes/services/get_service_instance_container_metadata.ts b/x-pack/plugins/apm/server/routes/services/get_service_instance_container_metadata.ts index ebce4f9338714..b5b98890ac636 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_instance_container_metadata.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_instance_container_metadata.ts @@ -51,6 +51,7 @@ export const getServiceInstanceContainerMetadata = async ({ const response = await infraMetricsClient.search({ size: 1, + track_total_hits: false, query: { bool: { filter: [ diff --git a/x-pack/plugins/apm/server/routes/services/get_service_overview_container_metadata.ts b/x-pack/plugins/apm/server/routes/services/get_service_overview_container_metadata.ts index c1dcfe97e208b..4b8d979a7dd85 100644 --- a/x-pack/plugins/apm/server/routes/services/get_service_overview_container_metadata.ts +++ b/x-pack/plugins/apm/server/routes/services/get_service_overview_container_metadata.ts @@ -43,6 +43,7 @@ export const getServiceOverviewContainerMetadata = async ({ const response = await infraMetricsClient.search({ size: 0, + track_total_hits: false, query: { bool: { filter: [ diff --git a/x-pack/plugins/cases/docs/openapi/README.md b/x-pack/plugins/cases/docs/openapi/README.md index 1ff3e24c2e91f..cf0ea6c76da7c 100644 --- a/x-pack/plugins/cases/docs/openapi/README.md +++ b/x-pack/plugins/cases/docs/openapi/README.md @@ -22,8 +22,13 @@ command in the `x-pack/plugins/cases/docs/openapi/` folder: Then you can generate the `bundled` files by running the following commands: - ``` - npx @redocly/openapi-cli bundle --ext yaml --output bundled.yaml entrypoint.yaml - npx @redocly/openapi-cli bundle --ext json --output bundled.json entrypoint.yaml - ``` + ``` + npx @redocly/cli bundle entrypoint.yaml --output bundled.yaml --ext yaml + npx @redocly/cli bundle entrypoint.yaml --output bundled.json --ext json + ``` + +You can run additional linting with the following command: + ``` + npx @redocly/cli lint bundled.json + ``` diff --git a/x-pack/plugins/cases/docs/openapi/bundled-min.json b/x-pack/plugins/cases/docs/openapi/bundled-min.json new file mode 100644 index 0000000000000..b039f5065d456 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/bundled-min.json @@ -0,0 +1,1277 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Cases", + "description": "OpenAPI schema for Cases endpoints", + "version": "0.2", + "contact": { + "name": "Cases Team" + }, + "license": { + "name": "Elastic License 2.0", + "url": "https://www.elastic.co/licensing/elastic-license" + } + }, + "tags": [ + { + "name": "cases", + "description": "Case APIs enable you to open and track issues." + } + ], + "servers": [ + { + "url": "http://localhost:5601", + "description": "local" + } + ], + "paths": { + "/s/{spaceId}/api/cases/{caseId}/comments": { + "post": { + "summary": "Adds a comment or alert to a case.", + "operationId": "addCaseComment", + "description": "You must have `all` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the case you're creating.\n", + "tags": [ + "cases" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/case_id" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/add_case_comment_request" + }, + "examples": { + "createCaseCommentRequest": { + "$ref": "#/components/examples/add_comment_request" + } + } + } + } + }, + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/case_response_properties" + }, + "examples": { + "createCaseCommentResponse": { + "$ref": "#/components/examples/add_comment_response" + } + } + } + } + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, + "delete": { + "summary": "Deletes all comments and alerts from a case.", + "operationId": "deleteCaseComments", + "description": "You must have `all` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases you're deleting.\n", + "tags": [ + "cases" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/case_id" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "responses": { + "204": { + "description": "Indicates a successful call." + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, + "patch": { + "summary": "Updates a comment or alert in a case.", + "operationId": "updateCaseComment", + "description": "You must have `all` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the case you're updating. NOTE: You cannot change the comment type or the owner of a comment.\n", + "tags": [ + "cases" + ], + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + }, + { + "$ref": "#/components/parameters/case_id" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/update_case_comment_request" + }, + "examples": { + "updateCaseCommentRequest": { + "$ref": "#/components/examples/update_comment_request" + } + } + } + } + }, + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/case_response_properties" + }, + "examples": { + "updateCaseCommentResponse": { + "$ref": "#/components/examples/update_comment_response" + } + } + } + } + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, + "get": { + "summary": "Retrieves all the comments from a case.", + "operationId": "getAllCaseComments", + "description": "You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases with the comments you're seeking.\n", + "deprecated": true, + "tags": [ + "cases" + ], + "parameters": [ + { + "$ref": "#/components/parameters/case_id" + }, + { + "$ref": "#/components/parameters/space_id" + } + ], + "responses": { + "200": { + "description": "Indicates a successful call.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/case_response_properties" + } + } + } + } + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + }, + "servers": [ + { + "url": "https://localhost:5601" + } + ] + } + }, + "components": { + "securitySchemes": { + "basicAuth": { + "type": "http", + "scheme": "basic" + }, + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "ApiKey" + } + }, + "parameters": { + "case_id": { + "in": "path", + "name": "caseId", + "description": "The identifier for the case. To retrieve case IDs, use the find cases API. All non-ASCII characters must be URL encoded.", + "required": true, + "schema": { + "type": "string", + "example": "9c235210-6834-11ea-a78c-6ffb38a34414" + } + }, + "space_id": { + "in": "path", + "name": "spaceId", + "description": "An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used.", + "required": true, + "schema": { + "type": "string", + "example": "default" + } + }, + "kbn_xsrf": { + "schema": { + "type": "string" + }, + "in": "header", + "name": "kbn-xsrf", + "required": true + } + }, + "schemas": { + "case_response_closed_by_properties": { + "title": "Case response properties for closed_by", + "type": "object", + "nullable": true, + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + }, + "required": [ + "email", + "full_name", + "username" + ] + }, + "owners": { + "type": "string", + "description": "The application that owns the cases: Stack Management, Observability, or Elastic Security.\n", + "enum": [ + "cases", + "observability", + "securitySolution" + ], + "example": "cases" + }, + "alert_comment_response_properties": { + "title": "Add case comment response properties for alerts", + "type": "object", + "required": [ + "type" + ], + "properties": { + "alertId": { + "type": "string", + "example": "6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42" + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2022-03-24T02:31:03.210Z" + }, + "created_by": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + } + }, + "id": { + "type": "string", + "example": "73362370-ab1a-11ec-985f-97e55adae8b9" + }, + "index": { + "type": "string", + "example": ".internal.alerts-security.alerts-default-000001" + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "pushed_at": { + "type": "string", + "format": "date-time", + "example": null, + "nullable": true + }, + "pushed_by": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + }, + "nullable": true + }, + "rule": { + "type": "object", + "properties": { + "id": { + "description": "The rule identifier.", + "type": "string", + "example": "94d80550-aaf4-11ec-985f-97e55adae8b9" + }, + "name": { + "description": "The rule name.", + "type": "string", + "example": "security_rule" + } + } + }, + "type": { + "type": "string", + "example": "alert", + "enum": [ + "alert" + ] + }, + "updated_at": { + "type": "string", + "format": "date-time", + "example": null + }, + "updated_by": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + } + }, + "version": { + "type": "string", + "example": "WzMwNDgsMV0=" + } + } + }, + "case_response_created_by_properties": { + "title": "Case response properties for created_by", + "type": "object", + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + }, + "required": [ + "email", + "full_name", + "username" + ] + }, + "case_response_pushed_by_properties": { + "title": "Case response properties for pushed_by", + "type": "object", + "nullable": true, + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + }, + "required": [ + "email", + "full_name", + "username" + ] + }, + "case_response_updated_by_properties": { + "title": "Case response properties for updated_by", + "type": "object", + "nullable": true, + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + }, + "required": [ + "email", + "full_name", + "username" + ] + }, + "user_comment_response_properties": { + "title": "Case response properties for user comments", + "type": "object", + "required": [ + "type" + ], + "properties": { + "comment": { + "type": "string", + "example": "A new comment." + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2022-05-13T09:16:17.416Z" + }, + "created_by": { + "$ref": "#/components/schemas/case_response_created_by_properties" + }, + "id": { + "type": "string", + "example": "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "pushed_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "example": null + }, + "pushed_by": { + "$ref": "#/components/schemas/case_response_pushed_by_properties" + }, + "type": { + "type": "string", + "example": "user", + "enum": [ + "user" + ] + }, + "updated_at": { + "type": "string", + "format": "date-time", + "nullable": true, + "example": null + }, + "updated_by": { + "$ref": "#/components/schemas/case_response_updated_by_properties" + }, + "version": { + "type": "string", + "example": "WzIwNDMxLDFd" + } + } + }, + "case_response_connector_field_properties": { + "title": "Case response properties for connector fields", + "type": "object", + "description": "An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value.", + "nullable": true, + "properties": { + "caseId": { + "description": "The case identifier for Swimlane connectors.", + "type": "string" + }, + "category": { + "description": "The category of the incident for ServiceNow ITSM and ServiceNow SecOps connectors.", + "type": "string" + }, + "destIp": { + "description": "A comma-separated list of destination IPs for ServiceNow SecOps connectors.", + "type": "string" + }, + "impact": { + "description": "The effect an incident had on business for ServiceNow ITSM connectors.", + "type": "string" + }, + "issueType": { + "description": "The type of issue for Jira connectors.", + "type": "string" + }, + "issueTypes": { + "description": "The type of incident for IBM Resilient connectors.", + "type": "array", + "items": { + "type": "number" + } + }, + "malwareHash": { + "description": "A comma-separated list of malware hashes for ServiceNow SecOps connectors.", + "type": "string" + }, + "malwareUrl": { + "description": "A comma-separated list of malware URLs for ServiceNow SecOps connectors.", + "type": "string" + }, + "parent": { + "description": "The key of the parent issue, when the issue type is sub-task for Jira connectors.", + "type": "string" + }, + "priority": { + "description": "The priority of the issue for Jira and ServiceNow SecOps connectors.", + "type": "string" + }, + "severity": { + "description": "The severity of the incident for ServiceNow ITSM connectors.", + "type": "string" + }, + "severityCode": { + "description": "The severity code of the incident for IBM Resilient connectors.", + "type": "number" + }, + "sourceIp": { + "description": "A comma-separated list of source IPs for ServiceNow SecOps connectors.", + "type": "string" + }, + "subcategory": { + "description": "The subcategory of the incident for ServiceNow ITSM connectors.", + "type": "string" + }, + "urgency": { + "description": "The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors.", + "type": "string" + } + } + }, + "connector_types": { + "type": "string", + "description": "The type of connector.", + "enum": [ + ".cases-webhook", + ".jira", + ".none", + ".resilient", + ".servicenow", + ".servicenow-sir", + ".swimlane" + ], + "example": ".none" + }, + "external_service": { + "type": "object", + "nullable": true, + "properties": { + "connector_id": { + "type": "string" + }, + "connector_name": { + "type": "string" + }, + "external_id": { + "type": "string" + }, + "external_title": { + "type": "string" + }, + "external_url": { + "type": "string" + }, + "pushed_at": { + "type": "string", + "format": "date-time" + }, + "pushed_by": { + "type": "object", + "properties": { + "email": { + "type": "string", + "example": null, + "nullable": true + }, + "full_name": { + "type": "string", + "example": null, + "nullable": true + }, + "username": { + "type": "string", + "example": "elastic", + "nullable": true + }, + "profile_uid": { + "type": "string", + "example": "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" + } + }, + "nullable": true + } + } + }, + "settings": { + "type": "object", + "description": "An object that contains the case settings.", + "properties": { + "syncAlerts": { + "description": "Turns alert syncing on or off.", + "type": "boolean", + "example": true + } + } + }, + "severity_property": { + "type": "string", + "description": "The severity of the case.", + "enum": [ + "critical", + "high", + "low", + "medium" + ], + "default": "low" + }, + "status": { + "type": "string", + "description": "The status of the case.", + "enum": [ + "closed", + "in-progress", + "open" + ] + }, + "case_response_properties": { + "title": "Case response properties", + "type": "object", + "required": [ + "closed_at", + "closed_by", + "comments", + "connector", + "created_at", + "created_by", + "description", + "duration", + "external_service", + "id", + "owner", + "settings", + "severity", + "status", + "tags", + "title", + "totalAlerts", + "totalComment", + "updated_at", + "updated_by", + "version" + ], + "properties": { + "closed_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "closed_by": { + "$ref": "#/components/schemas/case_response_closed_by_properties" + }, + "comments": { + "title": "Case response properties for comments", + "description": "An array of comment objects for the case.", + "type": "array", + "items": { + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/alert_comment_response_properties" + }, + { + "$ref": "#/components/schemas/user_comment_response_properties" + } + ] + } + }, + "connector": { + "title": "Case response properties for connectors", + "type": "object", + "properties": { + "fields": { + "$ref": "#/components/schemas/case_response_connector_field_properties" + }, + "id": { + "description": "The identifier for the connector. To create a case without a connector, use `none`.", + "type": "string", + "example": "none" + }, + "name": { + "description": "The name of the connector. To create a case without a connector, use `none`.", + "type": "string", + "example": "none" + }, + "type": { + "$ref": "#/components/schemas/connector_types" + } + } + }, + "created_at": { + "type": "string", + "format": "date-time", + "example": "2022-05-13T09:16:17.416Z" + }, + "created_by": { + "$ref": "#/components/schemas/case_response_created_by_properties" + }, + "description": { + "type": "string", + "example": "A case description." + }, + "duration": { + "type": "integer", + "description": "The elapsed time from the creation of the case to its closure (in seconds). If the case has not been closed, the duration is set to null. If the case was closed after less than half a second, the duration is rounded down to zero.\n", + "nullable": true, + "example": 120 + }, + "external_service": { + "$ref": "#/components/schemas/external_service" + }, + "id": { + "type": "string", + "example": "66b9aa00-94fa-11ea-9f74-e7e108796192" + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "settings": { + "$ref": "#/components/schemas/settings" + }, + "severity": { + "$ref": "#/components/schemas/severity_property" + }, + "status": { + "$ref": "#/components/schemas/status" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "tag-1" + ] + }, + "title": { + "type": "string", + "example": "Case title 1" + }, + "totalAlerts": { + "type": "integer", + "example": 0 + }, + "totalComment": { + "type": "integer", + "example": 0 + }, + "updated_at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "updated_by": { + "$ref": "#/components/schemas/case_response_updated_by_properties" + }, + "version": { + "type": "string", + "example": "WzUzMiwxXQ==" + } + } + }, + "alert_identifiers": { + "title": "Alert identifiers", + "description": "The alert identifier. It is required only when `type` is `alert`. If it is an array, `index` must also be an array with the same length or number of elements. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "x-technical-preview": true, + "example": "6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42" + }, + "alert_indices": { + "title": "Alert indices", + "description": "The alert index. It is required only when `type` is `alert`. If it is an array, `alertId` must also be an array with the same length or number of elements. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "x-technical-preview": true + }, + "rule": { + "title": "Alerting rule", + "description": "The rule that is associated with the alert. It is required only when `type` is `alert`. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "type": "object", + "x-technical-preview": true, + "properties": { + "id": { + "description": "The rule identifier.", + "type": "string", + "example": "94d80550-aaf4-11ec-985f-97e55adae8b9" + }, + "name": { + "description": "The rule name.", + "type": "string", + "example": "security_rule" + } + } + }, + "add_alert_comment_request_properties": { + "title": "Add case comment request properties for alerts", + "required": [ + "alertId", + "index", + "owner", + "rule", + "type" + ], + "description": "Defines properties for case comment requests when type is alert.", + "type": "object", + "properties": { + "alertId": { + "$ref": "#/components/schemas/alert_identifiers" + }, + "index": { + "$ref": "#/components/schemas/alert_indices" + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "rule": { + "$ref": "#/components/schemas/rule" + }, + "type": { + "description": "The type of comment.", + "type": "string", + "example": "alert", + "enum": [ + "alert" + ] + } + } + }, + "add_user_comment_request_properties": { + "title": "Add case comment request properties for user comments", + "description": "Defines properties for case comment requests when type is user.", + "type": "object", + "properties": { + "comment": { + "description": "The new comment. It is required only when `type` is `user`.", + "type": "string", + "example": "A new comment." + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "type": { + "type": "string", + "description": "The type of comment.", + "example": "user", + "enum": [ + "user" + ] + } + }, + "required": [ + "comment", + "owner", + "type" + ] + }, + "add_case_comment_request": { + "title": "Add case comment request", + "description": "The add comment to case API request body varies depending on whether you are adding an alert or a comment.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/add_alert_comment_request_properties" + }, + { + "$ref": "#/components/schemas/add_user_comment_request_properties" + } + ] + }, + "update_alert_comment_request_properties": { + "title": "Update case comment request properties for alerts", + "description": "Defines properties for case comment requests when type is alert.", + "required": [ + "alertId", + "id", + "index", + "owner", + "rule", + "type", + "version" + ], + "type": "object", + "properties": { + "alertId": { + "$ref": "#/components/schemas/alert_identifiers" + }, + "id": { + "type": "string", + "description": "The identifier for the comment. To retrieve comment IDs, use the get comments API.\n", + "example": "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + }, + "index": { + "$ref": "#/components/schemas/alert_indices" + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "rule": { + "$ref": "#/components/schemas/rule" + }, + "type": { + "description": "The type of comment.", + "type": "string", + "enum": [ + "alert" + ], + "example": "alert" + }, + "version": { + "description": "The current comment version. To retrieve version values, use the get comments API.\n", + "type": "string", + "example": "Wzk1LDFd" + } + } + }, + "update_user_comment_request_properties": { + "title": "Update case comment request properties for user comments", + "description": "Defines properties for case comment requests when type is user.", + "type": "object", + "properties": { + "comment": { + "description": "The new comment. It is required only when `type` is `user`.", + "type": "string", + "example": "A new comment." + }, + "id": { + "type": "string", + "description": "The identifier for the comment. To retrieve comment IDs, use the get comments API.\n", + "example": "8af6ac20-74f6-11ea-b83a-553aecdb28b6" + }, + "owner": { + "$ref": "#/components/schemas/owners" + }, + "type": { + "type": "string", + "description": "The type of comment.", + "enum": [ + "user" + ], + "example": "user" + }, + "version": { + "description": "The current comment version. To retrieve version values, use the get comments API.\n", + "type": "string", + "example": "Wzk1LDFd" + } + }, + "required": [ + "comment", + "id", + "owner", + "type", + "version" + ] + }, + "update_case_comment_request": { + "title": "Update case comment request", + "description": "The update case comment API request body varies depending on whether you are updating an alert or a comment.", + "discriminator": { + "propertyName": "type" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/update_alert_comment_request_properties" + }, + { + "$ref": "#/components/schemas/update_user_comment_request_properties" + } + ] + } + }, + "examples": { + "add_comment_request": { + "summary": "Adds a comment to a case.", + "value": { + "type": "user", + "comment": "A new comment.", + "owner": "cases" + } + }, + "add_comment_response": { + "summary": "The add comment to case API returns a JSON object that contains details about the case and its comments.", + "value": { + "comments": [ + { + "id": "8af6ac20-74f6-11ea-b83a-553aecdb28b6", + "version": "WzIwNDMxLDFd", + "type": "user", + "owner": "cases", + "comment": "A new comment.", + "created_at": "2022-06-02T00:49:47.716Z", + "created_by": { + "username": "elastic", + "email": null, + "full_name": null + } + } + ], + "totalAlerts": 0, + "id": "293f1bc0-74f6-11ea-b83a-553aecdb28b6", + "version": "WzIzMzgsMV0=", + "totalComment": 1, + "title": "Case title 1", + "tags": [ + "tag 1" + ], + "description": "A case description.", + "settings": { + "syncAlerts": false + }, + "owner": "cases", + "duration": null, + "severity": "low", + "closed_at": null, + "closed_by": null, + "created_at": "2022-03-24T00:37:03.906Z", + "created_by": { + "username": "elastic", + "full_name": null, + "email": null + }, + "status": "open", + "updated_at": "2022-06-03T00:49:47.716Z", + "updated_by": { + "username": "elastic", + "email": null, + "full_name": null + }, + "connector": { + "id": "none", + "name": "none", + "type": ".none", + "fields": null + }, + "external_service": null + } + }, + "update_comment_request": { + "summary": "Updates a comment of a case.", + "value": { + "id": "8af6ac20-74f6-11ea-b83a-553aecdb28b6", + "version": "Wzk1LDFd", + "type": "user", + "comment": "An updated comment.", + "owner": "cases" + } + }, + "update_comment_response": { + "summary": "The add comment to case API returns a JSON object that contains details about the case and its comments.", + "value": { + "comments": [ + { + "id": "8af6ac20-74f6-11ea-b83a-553aecdb28b6", + "version": "WzIwNjM3LDFd", + "comment": "An updated comment.", + "type": "user", + "owner": "cases", + "created_at": "2022-03-24T00:37:10.832Z", + "created_by": { + "username": "elastic", + "full_name": null, + "email": null + }, + "pushed_at": null, + "pushed_by": null, + "updated_at": "2022-03-24T01:27:06.210Z", + "updated_by": { + "username": "elastic", + "full_name": null, + "email": null + } + } + ], + "totalAlerts": 0, + "id": "293f1bc0-74f6-11ea-b83a-553aecdb28b6", + "version": "WzIwNjM2LDFd", + "totalComment": 1, + "title": "Case title 1", + "tags": [ + "tag 1" + ], + "description": "A case description.", + "settings": { + "syncAlerts": false + }, + "owner": "cases", + "duration": null, + "severity": "low", + "closed_at": null, + "closed_by": null, + "created_at": "2022-03-24T00:37:03.906Z", + "created_by": { + "username": "elastic", + "full_name": null, + "email": null + }, + "status": "open", + "updated_at": "2022-03-24T01:27:06.210Z", + "updated_by": { + "username": "elastic", + "full_name": null, + "email": null + }, + "connector": { + "id": "none", + "name": "none", + "type": ".none", + "fields": null + }, + "external_service": null + } + } + } + }, + "security": [ + { + "basicAuth": [] + }, + { + "apiKeyAuth": [] + } + ] +} \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/bundled-min.yaml b/x-pack/plugins/cases/docs/openapi/bundled-min.yaml new file mode 100644 index 0000000000000..75f982011a137 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/bundled-min.yaml @@ -0,0 +1,923 @@ +openapi: 3.0.1 +info: + title: Cases + description: OpenAPI schema for Cases endpoints + version: '0.2' + contact: + name: Cases Team + license: + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license +tags: + - name: cases + description: Case APIs enable you to open and track issues. +servers: + - url: http://localhost:5601 + description: local +paths: + /s/{spaceId}/api/cases/{caseId}/comments: + post: + summary: Adds a comment or alert to a case. + operationId: addCaseComment + description: | + You must have `all` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the case you're creating. + tags: + - cases + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/case_id' + - $ref: '#/components/parameters/space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/add_case_comment_request' + examples: + createCaseCommentRequest: + $ref: '#/components/examples/add_comment_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/case_response_properties' + examples: + createCaseCommentResponse: + $ref: '#/components/examples/add_comment_response' + servers: + - url: https://localhost:5601 + delete: + summary: Deletes all comments and alerts from a case. + operationId: deleteCaseComments + description: | + You must have `all` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases you're deleting. + tags: + - cases + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/case_id' + - $ref: '#/components/parameters/space_id' + responses: + '204': + description: Indicates a successful call. + servers: + - url: https://localhost:5601 + patch: + summary: Updates a comment or alert in a case. + operationId: updateCaseComment + description: | + You must have `all` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the case you're updating. NOTE: You cannot change the comment type or the owner of a comment. + tags: + - cases + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + - $ref: '#/components/parameters/case_id' + - $ref: '#/components/parameters/space_id' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/update_case_comment_request' + examples: + updateCaseCommentRequest: + $ref: '#/components/examples/update_comment_request' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/case_response_properties' + examples: + updateCaseCommentResponse: + $ref: '#/components/examples/update_comment_response' + servers: + - url: https://localhost:5601 + get: + summary: Retrieves all the comments from a case. + operationId: getAllCaseComments + description: | + You must have `read` privileges for the **Cases** feature in the **Management**, **Observability**, or **Security** section of the Kibana feature privileges, depending on the owner of the cases with the comments you're seeking. + deprecated: true + tags: + - cases + parameters: + - $ref: '#/components/parameters/case_id' + - $ref: '#/components/parameters/space_id' + responses: + '200': + description: Indicates a successful call. + content: + application/json: + schema: + $ref: '#/components/schemas/case_response_properties' + servers: + - url: https://localhost:5601 + servers: + - url: https://localhost:5601 +components: + securitySchemes: + basicAuth: + type: http + scheme: basic + apiKeyAuth: + type: apiKey + in: header + name: ApiKey + parameters: + case_id: + in: path + name: caseId + description: The identifier for the case. To retrieve case IDs, use the find cases API. All non-ASCII characters must be URL encoded. + required: true + schema: + type: string + example: 9c235210-6834-11ea-a78c-6ffb38a34414 + space_id: + in: path + name: spaceId + description: An identifier for the space. If `/s/` and the identifier are omitted from the path, the default space is used. + required: true + schema: + type: string + example: default + kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + required: true + schemas: + case_response_closed_by_properties: + title: Case response properties for closed_by + type: object + nullable: true + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + required: + - email + - full_name + - username + owners: + type: string + description: | + The application that owns the cases: Stack Management, Observability, or Elastic Security. + enum: + - cases + - observability + - securitySolution + example: cases + alert_comment_response_properties: + title: Add case comment response properties for alerts + type: object + required: + - type + properties: + alertId: + type: string + example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 + created_at: + type: string + format: date-time + example: '2022-03-24T02:31:03.210Z' + created_by: + type: object + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + id: + type: string + example: 73362370-ab1a-11ec-985f-97e55adae8b9 + index: + type: string + example: .internal.alerts-security.alerts-default-000001 + owner: + $ref: '#/components/schemas/owners' + pushed_at: + type: string + format: date-time + example: null + nullable: true + pushed_by: + type: object + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + nullable: true + rule: + type: object + properties: + id: + description: The rule identifier. + type: string + example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + name: + description: The rule name. + type: string + example: security_rule + type: + type: string + example: alert + enum: + - alert + updated_at: + type: string + format: date-time + example: null + updated_by: + type: object + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + version: + type: string + example: WzMwNDgsMV0= + case_response_created_by_properties: + title: Case response properties for created_by + type: object + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + required: + - email + - full_name + - username + case_response_pushed_by_properties: + title: Case response properties for pushed_by + type: object + nullable: true + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + required: + - email + - full_name + - username + case_response_updated_by_properties: + title: Case response properties for updated_by + type: object + nullable: true + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + required: + - email + - full_name + - username + user_comment_response_properties: + title: Case response properties for user comments + type: object + required: + - type + properties: + comment: + type: string + example: A new comment. + created_at: + type: string + format: date-time + example: '2022-05-13T09:16:17.416Z' + created_by: + $ref: '#/components/schemas/case_response_created_by_properties' + id: + type: string + example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + owner: + $ref: '#/components/schemas/owners' + pushed_at: + type: string + format: date-time + nullable: true + example: null + pushed_by: + $ref: '#/components/schemas/case_response_pushed_by_properties' + type: + type: string + example: user + enum: + - user + updated_at: + type: string + format: date-time + nullable: true + example: null + updated_by: + $ref: '#/components/schemas/case_response_updated_by_properties' + version: + type: string + example: WzIwNDMxLDFd + case_response_connector_field_properties: + title: Case response properties for connector fields + type: object + description: An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. + nullable: true + properties: + caseId: + description: The case identifier for Swimlane connectors. + type: string + category: + description: The category of the incident for ServiceNow ITSM and ServiceNow SecOps connectors. + type: string + destIp: + description: A comma-separated list of destination IPs for ServiceNow SecOps connectors. + type: string + impact: + description: The effect an incident had on business for ServiceNow ITSM connectors. + type: string + issueType: + description: The type of issue for Jira connectors. + type: string + issueTypes: + description: The type of incident for IBM Resilient connectors. + type: array + items: + type: number + malwareHash: + description: A comma-separated list of malware hashes for ServiceNow SecOps connectors. + type: string + malwareUrl: + description: A comma-separated list of malware URLs for ServiceNow SecOps connectors. + type: string + parent: + description: The key of the parent issue, when the issue type is sub-task for Jira connectors. + type: string + priority: + description: The priority of the issue for Jira and ServiceNow SecOps connectors. + type: string + severity: + description: The severity of the incident for ServiceNow ITSM connectors. + type: string + severityCode: + description: The severity code of the incident for IBM Resilient connectors. + type: number + sourceIp: + description: A comma-separated list of source IPs for ServiceNow SecOps connectors. + type: string + subcategory: + description: The subcategory of the incident for ServiceNow ITSM connectors. + type: string + urgency: + description: The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors. + type: string + connector_types: + type: string + description: The type of connector. + enum: + - .cases-webhook + - .jira + - .none + - .resilient + - .servicenow + - .servicenow-sir + - .swimlane + example: .none + external_service: + type: object + nullable: true + properties: + connector_id: + type: string + connector_name: + type: string + external_id: + type: string + external_title: + type: string + external_url: + type: string + pushed_at: + type: string + format: date-time + pushed_by: + type: object + properties: + email: + type: string + example: null + nullable: true + full_name: + type: string + example: null + nullable: true + username: + type: string + example: elastic + nullable: true + profile_uid: + type: string + example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 + nullable: true + settings: + type: object + description: An object that contains the case settings. + properties: + syncAlerts: + description: Turns alert syncing on or off. + type: boolean + example: true + severity_property: + type: string + description: The severity of the case. + enum: + - critical + - high + - low + - medium + default: low + status: + type: string + description: The status of the case. + enum: + - closed + - in-progress + - open + case_response_properties: + title: Case response properties + type: object + required: + - closed_at + - closed_by + - comments + - connector + - created_at + - created_by + - description + - duration + - external_service + - id + - owner + - settings + - severity + - status + - tags + - title + - totalAlerts + - totalComment + - updated_at + - updated_by + - version + properties: + closed_at: + type: string + format: date-time + nullable: true + closed_by: + $ref: '#/components/schemas/case_response_closed_by_properties' + comments: + title: Case response properties for comments + description: An array of comment objects for the case. + type: array + items: + discriminator: + propertyName: type + oneOf: + - $ref: '#/components/schemas/alert_comment_response_properties' + - $ref: '#/components/schemas/user_comment_response_properties' + connector: + title: Case response properties for connectors + type: object + properties: + fields: + $ref: '#/components/schemas/case_response_connector_field_properties' + id: + description: The identifier for the connector. To create a case without a connector, use `none`. + type: string + example: none + name: + description: The name of the connector. To create a case without a connector, use `none`. + type: string + example: none + type: + $ref: '#/components/schemas/connector_types' + created_at: + type: string + format: date-time + example: '2022-05-13T09:16:17.416Z' + created_by: + $ref: '#/components/schemas/case_response_created_by_properties' + description: + type: string + example: A case description. + duration: + type: integer + description: | + The elapsed time from the creation of the case to its closure (in seconds). If the case has not been closed, the duration is set to null. If the case was closed after less than half a second, the duration is rounded down to zero. + nullable: true + example: 120 + external_service: + $ref: '#/components/schemas/external_service' + id: + type: string + example: 66b9aa00-94fa-11ea-9f74-e7e108796192 + owner: + $ref: '#/components/schemas/owners' + settings: + $ref: '#/components/schemas/settings' + severity: + $ref: '#/components/schemas/severity_property' + status: + $ref: '#/components/schemas/status' + tags: + type: array + items: + type: string + example: + - tag-1 + title: + type: string + example: Case title 1 + totalAlerts: + type: integer + example: 0 + totalComment: + type: integer + example: 0 + updated_at: + type: string + format: date-time + nullable: true + updated_by: + $ref: '#/components/schemas/case_response_updated_by_properties' + version: + type: string + example: WzUzMiwxXQ== + alert_identifiers: + title: Alert identifiers + description: | + The alert identifier. It is required only when `type` is `alert`. If it is an array, `index` must also be an array with the same length or number of elements. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + oneOf: + - type: string + - type: array + items: + type: string + x-technical-preview: true + example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 + alert_indices: + title: Alert indices + description: | + The alert index. It is required only when `type` is `alert`. If it is an array, `alertId` must also be an array with the same length or number of elements. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + oneOf: + - type: string + - type: array + items: + type: string + x-technical-preview: true + rule: + title: Alerting rule + description: | + The rule that is associated with the alert. It is required only when `type` is `alert`. This functionality is in technical preview and may be changed or removed in a future release. Elastic will apply best effort to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. + type: object + x-technical-preview: true + properties: + id: + description: The rule identifier. + type: string + example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + name: + description: The rule name. + type: string + example: security_rule + add_alert_comment_request_properties: + title: Add case comment request properties for alerts + required: + - alertId + - index + - owner + - rule + - type + description: Defines properties for case comment requests when type is alert. + type: object + properties: + alertId: + $ref: '#/components/schemas/alert_identifiers' + index: + $ref: '#/components/schemas/alert_indices' + owner: + $ref: '#/components/schemas/owners' + rule: + $ref: '#/components/schemas/rule' + type: + description: The type of comment. + type: string + example: alert + enum: + - alert + add_user_comment_request_properties: + title: Add case comment request properties for user comments + description: Defines properties for case comment requests when type is user. + type: object + properties: + comment: + description: The new comment. It is required only when `type` is `user`. + type: string + example: A new comment. + owner: + $ref: '#/components/schemas/owners' + type: + type: string + description: The type of comment. + example: user + enum: + - user + required: + - comment + - owner + - type + add_case_comment_request: + title: Add case comment request + description: The add comment to case API request body varies depending on whether you are adding an alert or a comment. + discriminator: + propertyName: type + oneOf: + - $ref: '#/components/schemas/add_alert_comment_request_properties' + - $ref: '#/components/schemas/add_user_comment_request_properties' + update_alert_comment_request_properties: + title: Update case comment request properties for alerts + description: Defines properties for case comment requests when type is alert. + required: + - alertId + - id + - index + - owner + - rule + - type + - version + type: object + properties: + alertId: + $ref: '#/components/schemas/alert_identifiers' + id: + type: string + description: | + The identifier for the comment. To retrieve comment IDs, use the get comments API. + example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + index: + $ref: '#/components/schemas/alert_indices' + owner: + $ref: '#/components/schemas/owners' + rule: + $ref: '#/components/schemas/rule' + type: + description: The type of comment. + type: string + enum: + - alert + example: alert + version: + description: | + The current comment version. To retrieve version values, use the get comments API. + type: string + example: Wzk1LDFd + update_user_comment_request_properties: + title: Update case comment request properties for user comments + description: Defines properties for case comment requests when type is user. + type: object + properties: + comment: + description: The new comment. It is required only when `type` is `user`. + type: string + example: A new comment. + id: + type: string + description: | + The identifier for the comment. To retrieve comment IDs, use the get comments API. + example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + owner: + $ref: '#/components/schemas/owners' + type: + type: string + description: The type of comment. + enum: + - user + example: user + version: + description: | + The current comment version. To retrieve version values, use the get comments API. + type: string + example: Wzk1LDFd + required: + - comment + - id + - owner + - type + - version + update_case_comment_request: + title: Update case comment request + description: The update case comment API request body varies depending on whether you are updating an alert or a comment. + discriminator: + propertyName: type + oneOf: + - $ref: '#/components/schemas/update_alert_comment_request_properties' + - $ref: '#/components/schemas/update_user_comment_request_properties' + examples: + add_comment_request: + summary: Adds a comment to a case. + value: + type: user + comment: A new comment. + owner: cases + add_comment_response: + summary: The add comment to case API returns a JSON object that contains details about the case and its comments. + value: + comments: + - id: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + version: WzIwNDMxLDFd + type: user + owner: cases + comment: A new comment. + created_at: '2022-06-02T00:49:47.716Z' + created_by: + username: elastic + email: null + full_name: null + totalAlerts: 0 + id: 293f1bc0-74f6-11ea-b83a-553aecdb28b6 + version: WzIzMzgsMV0= + totalComment: 1 + title: Case title 1 + tags: + - tag 1 + description: A case description. + settings: + syncAlerts: false + owner: cases + duration: null + severity: low + closed_at: null + closed_by: null + created_at: '2022-03-24T00:37:03.906Z' + created_by: + username: elastic + full_name: null + email: null + status: open + updated_at: '2022-06-03T00:49:47.716Z' + updated_by: + username: elastic + email: null + full_name: null + connector: + id: none + name: none + type: .none + fields: null + external_service: null + update_comment_request: + summary: Updates a comment of a case. + value: + id: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + version: Wzk1LDFd + type: user + comment: An updated comment. + owner: cases + update_comment_response: + summary: The add comment to case API returns a JSON object that contains details about the case and its comments. + value: + comments: + - id: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + version: WzIwNjM3LDFd + comment: An updated comment. + type: user + owner: cases + created_at: '2022-03-24T00:37:10.832Z' + created_by: + username: elastic + full_name: null + email: null + pushed_at: null + pushed_by: null + updated_at: '2022-03-24T01:27:06.210Z' + updated_by: + username: elastic + full_name: null + email: null + totalAlerts: 0 + id: 293f1bc0-74f6-11ea-b83a-553aecdb28b6 + version: WzIwNjM2LDFd + totalComment: 1 + title: Case title 1 + tags: + - tag 1 + description: A case description. + settings: + syncAlerts: false + owner: cases + duration: null + severity: low + closed_at: null + closed_by: null + created_at: '2022-03-24T00:37:03.906Z' + created_by: + username: elastic + full_name: null + email: null + status: open + updated_at: '2022-03-24T01:27:06.210Z' + updated_by: + username: elastic + full_name: null + email: null + connector: + id: none + name: none + type: .none + fields: null + external_service: null +security: + - basicAuth: [] + - apiKeyAuth: [] diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/add_comment_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/add_comment_response.yaml index ea825da377a3b..382629e4fab08 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/add_comment_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/add_comment_response.yaml @@ -1,58 +1,46 @@ summary: The add comment to case API returns a JSON object that contains details about the case and its comments. value: - { - "comments":[ - { - "id": "8af6ac20-74f6-11ea-b83a-553aecdb28b6", - "version": "WzIwNDMxLDFd", - "type":"user", - "owner":"cases", - "comment":"A new comment.", - "created_at":"2022-06-02T00:49:47.716Z", - "created_by": { - "username": "elastic", - "email": null, - "full_name": null - }, - "pushed_at":null, - "pushed_by":null, - "updated_at":null, - "updated_by":null - } - ], - "totalAlerts":0, - "id":"293f1bc0-74f6-11ea-b83a-553aecdb28b6", - "version":"WzIzMzgsMV0=", - "totalComment":1, - "title": "Case title 1", - "tags": ["tag 1"], - "description": "A case description.", - "settings": { - "syncAlerts":false - }, - "owner": "cases", - "duration": null, - "severity": "low", - "closed_at": null, - "closed_by": null, - "created_at": "2022-03-24T00:37:03.906Z", - "created_by": { - "email": null, - "full_name": null, - "username": "elastic" - }, - "status": "open", - "updated_at": "2022-06-03T00:49:47.716Z", - "updated_by": { - "username": "elastic", - "email": null, - "full_name": null - }, - "connector": { - "id": "none", - "name": "none", - "type": ".none", - "fields": null - }, - "external_service": null - } \ No newline at end of file + comments: + - id: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + version: WzIwNDMxLDFd + type: user + owner: cases + comment: A new comment. + created_at: '2022-06-02T00:49:47.716Z' + created_by: + username: elastic + email: null + full_name: null + totalAlerts: 0 + id: 293f1bc0-74f6-11ea-b83a-553aecdb28b6 + version: WzIzMzgsMV0= + totalComment: 1 + title: Case title 1 + tags: + - tag 1 + description: A case description. + settings: + syncAlerts: false + owner: cases + duration: null + severity: low + closed_at: null + closed_by: null + created_at: '2022-03-24T00:37:03.906Z' + created_by: + username: elastic + full_name: null + email: null + status: open + updated_at: '2022-06-03T00:49:47.716Z' + updated_by: + username: elastic + email: null + full_name: null + connector: + id: none + name: none + type: .none + fields: null + external_service: null + \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_request.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_request.yaml index 066830ce20777..e09bb8ad35f2d 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_request.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_request.yaml @@ -4,5 +4,6 @@ value: "id": "8af6ac20-74f6-11ea-b83a-553aecdb28b6", "version": "Wzk1LDFd", "type": "user", - "comment": "An updated comment." + "comment": "An updated comment.", + "owner": "cases" } \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_response.yaml b/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_response.yaml index 9a3ba642d6ece..4c81e759a92f9 100644 --- a/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_response.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/examples/update_comment_response.yaml @@ -1,59 +1,52 @@ summary: The add comment to case API returns a JSON object that contains details about the case and its comments. value: - { - "comments":[{ - "id": "8af6ac20-74f6-11ea-b83a-553aecdb28b6", - "version": "WzIwNjM3LDFd", - "comment": "An updated comment.", - "type": "user", - "owner": "cases", - "created_at": "2022-03-24T00:37:10.832Z", - "created_by": { - "username": "elastic", - "full_name": null, - "email": null - }, - "pushed_at": null, - "pushed_by": null, - "updated_at": "2022-03-24T01:27:06.210Z", - "updated_by": { - "username": "elastic", - "full_name": null, - "email": null - } - } - ], - "totalAlerts": 0, - "id": "293f1bc0-74f6-11ea-b83a-553aecdb28b6", - "version": "WzIwNjM2LDFd", - "totalComment": 1, - "title": "Case title 1", - "tags": ["tag 1"], - "description": "A case description.", - "settings": {"syncAlerts":false}, - "owner": "cases", - "duration": null, - "severity": "low", - "closed_at": null, - "closed_by": null, - "created_at": "2022-03-24T00:37:03.906Z", - "created_by": { - "username": "elastic", - "full_name": null, - "email": null - }, - "status": "open", - "updated_at": "2022-03-24T01:27:06.210Z", - "updated_by": { - "username": "elastic", - "full_name": null, - "email": null - }, - "connector": { - "id": "none", - "name": "none", - "type": ".none", - "fields": null - }, - "external_service": null - } + comments: + - id: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 + version: WzIwNjM3LDFd + comment: An updated comment. + type: user + owner: cases + created_at: '2022-03-24T00:37:10.832Z' + created_by: + username: elastic + full_name: null + email: null + pushed_at: null + pushed_by: null + updated_at: '2022-03-24T01:27:06.210Z' + updated_by: + username: elastic + full_name: null + email: null + totalAlerts: 0 + id: 293f1bc0-74f6-11ea-b83a-553aecdb28b6 + version: WzIwNjM2LDFd + totalComment: 1 + title: Case title 1 + tags: + - tag 1 + description: A case description. + settings: + syncAlerts: false + owner: cases + duration: null + severity: low + closed_at: null + closed_by: null + created_at: '2022-03-24T00:37:03.906Z' + created_by: + username: elastic + full_name: null + email: null + status: open + updated_at: '2022-03-24T01:27:06.210Z' + updated_by: + username: elastic + full_name: null + email: null + connector: + id: none + name: none + type: .none + fields: null + external_service: null diff --git a/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml b/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml index beae115acce08..eebde85823746 100644 --- a/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/parameters/case_id.yaml @@ -4,4 +4,4 @@ description: The identifier for the case. To retrieve case IDs, use the find cas required: true schema: type: string - example: '9c235210-6834-11ea-a78c-6ffb38a34414' \ No newline at end of file + example: 9c235210-6834-11ea-a78c-6ffb38a34414 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml index ec2e69f66c1e4..c99ebb19cc818 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/add_alert_comment_request_properties.yaml @@ -1,55 +1,24 @@ +title: Add case comment request properties for alerts +required: + - alertId + - index + - owner + - rule + - type +description: Defines properties for case comment requests when type is alert. type: object properties: - alertId: - description: > - The alert identifier. It is required only when `type` is `alert`. If it is - an array, `index` must also be an array. This functionality is in - technical preview and may be changed or removed in a future release. - Elastic will apply best effort to fix any issues, but features in - technical preview are not subject to the support SLA of official GA - features. - oneOf: - - type: string - - type: array - items: - type: string - x-technical-preview: true - example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 + alertId: + $ref: 'alert_identifiers.yaml' index: - description: > - The alert index. It is required only when `type` is `alert`. If it is an - array, `alertId` must also be an array. This functionality is in technical - preview and may be changed or removed in a future release. Elastic will - apply best effort to fix any issues, but features in technical preview are - not subject to the support SLA of official GA features. - oneOf: - - type: string - - type: array - items: - type: string - x-technical-preview: true + $ref: 'alert_indices.yaml' owner: $ref: 'owners.yaml' rule: - description: > - The rule that is associated with the alert. It is required only when - `type` is `alert`. This functionality is in technical preview and may be - changed or removed in a future release. Elastic will apply best effort to - fix any issues, but features in technical preview are not subject to the - support SLA of official GA features. - type: object - x-technical-preview: true - properties: - $ref: 'rule_properties.yaml' + $ref: 'rule.yaml' type: description: The type of comment. type: string - enum: - - alert example: alert -required: - - alertId - - index - - owner - - rule - - type \ No newline at end of file + enum: + - alert \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/add_case_comment_request.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/add_case_comment_request.yaml new file mode 100644 index 0000000000000..70ed1324fde90 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/add_case_comment_request.yaml @@ -0,0 +1,9 @@ +title: Add case comment request +description: >- + The add comment to case API request body varies depending on whether you are + adding an alert or a comment. +discriminator: + propertyName: type +oneOf: + - $ref: 'add_alert_comment_request_properties.yaml' + - $ref: 'add_user_comment_request_properties.yaml' diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml index d09958e13fec8..40efb7f945f45 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/add_user_comment_request_properties.yaml @@ -1,3 +1,5 @@ +title: Add case comment request properties for user comments +description: Defines properties for case comment requests when type is user. type: object properties: comment: @@ -9,9 +11,9 @@ properties: type: type: string description: The type of comment. + example: user enum: - user - example: user required: - comment - owner diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml index 4fcbfe5527e96..056abad0a300b 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_comment_response_properties.yaml @@ -1,5 +1,7 @@ - +title: Add case comment response properties for alerts type: object +required: + - type properties: alertId: type: string @@ -37,6 +39,8 @@ properties: type: type: string example: alert + enum: + - alert updated_at: type: string format: date-time diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml new file mode 100644 index 0000000000000..4a470d8ff4475 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_identifiers.yaml @@ -0,0 +1,15 @@ +title: Alert identifiers +description: > + The alert identifier. It is required only when `type` is `alert`. If it is + an array, `index` must also be an array with the same length or number of + elements. This functionality is in technical preview and may be changed or + removed in a future release. Elastic will apply best effort to fix any issues, + but features in technical preview are not subject to the support SLA of + official GA features. +oneOf: + - type: string + - type: array + items: + type: string +x-technical-preview: true +example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/alert_indices.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_indices.yaml new file mode 100644 index 0000000000000..b265f4ee8ce3b --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/alert_indices.yaml @@ -0,0 +1,14 @@ +title: Alert indices +description: > + The alert index. It is required only when `type` is `alert`. If it is an + array, `alertId` must also be an array with the same length or number of + elements. This functionality is in technical preview and may be changed or + removed in a future release. Elastic will apply best effort to fix any issues, + but features in technical preview are not subject to the support SLA of + official GA features. +oneOf: + - type: string + - type: array + items: + type: string +x-technical-preview: true \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml new file mode 100644 index 0000000000000..95bd14e4957a3 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_closed_by_properties.yaml @@ -0,0 +1,9 @@ +title: Case response properties for closed_by +type: object +nullable: true +properties: + $ref: 'user_properties.yaml' +required: + - email + - full_name + - username \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml new file mode 100644 index 0000000000000..1f8aa7c90190c --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_connector_field_properties.yaml @@ -0,0 +1,52 @@ +title: Case response properties for connector fields +type: object +description: An object containing the connector fields. To create a case without a connector, specify null. If you want to omit any individual field, specify null as its value. +nullable: true +properties: + caseId: + description: The case identifier for Swimlane connectors. + type: string + category: + description: The category of the incident for ServiceNow ITSM and ServiceNow SecOps connectors. + type: string + destIp: + description: A comma-separated list of destination IPs for ServiceNow SecOps connectors. + type: string + impact: + description: The effect an incident had on business for ServiceNow ITSM connectors. + type: string + issueType: + description: The type of issue for Jira connectors. + type: string + issueTypes: + description: The type of incident for IBM Resilient connectors. + type: array + items: + type: number + malwareHash: + description: A comma-separated list of malware hashes for ServiceNow SecOps connectors. + type: string + malwareUrl: + description: A comma-separated list of malware URLs for ServiceNow SecOps connectors. + type: string + parent: + description: The key of the parent issue, when the issue type is sub-task for Jira connectors. + type: string + priority: + description: The priority of the issue for Jira and ServiceNow SecOps connectors. + type: string + severity: + description: The severity of the incident for ServiceNow ITSM connectors. + type: string + severityCode: + description: The severity code of the incident for IBM Resilient connectors. + type: number + sourceIp: + description: A comma-separated list of source IPs for ServiceNow SecOps connectors. + type: string + subcategory: + description: The subcategory of the incident for ServiceNow ITSM connectors. + type: string + urgency: + description: The extent to which the incident resolution can be delayed for ServiceNow ITSM connectors. + type: string \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_created_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_created_by_properties.yaml new file mode 100644 index 0000000000000..a58d7ff573868 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_created_by_properties.yaml @@ -0,0 +1,8 @@ +title: Case response properties for created_by +type: object +properties: + $ref: 'user_properties.yaml' +required: + - email + - full_name + - username \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml index 25f6296585192..1be19845c56ae 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_properties.yaml @@ -1,82 +1,112 @@ -closed_at: - type: string - format: date-time - nullable: true - example: null -closed_by: - type: object - properties: - $ref: 'user_properties.yaml' - nullable: true - example: null -comments: - type: array - items: - oneOf: - - $ref: 'alert_comment_response_properties.yaml' - - $ref: 'user_comment_response_properties.yaml' - example: [] -connector: - type: object - properties: - $ref: 'connector_properties.yaml' -created_at: - type: string - format: date-time - example: 2022-05-13T09:16:17.416Z -created_by: - type: object - properties: - $ref: 'user_properties.yaml' -description: - type: string - example: "A case description." -duration: - type: integer - description: > - The elapsed time from the creation of the case to its closure (in seconds). - If the case has not been closed, the duration is set to null. If the case - was closed after less than half a second, the duration is rounded down to - zero. - example: 120 -external_service: - $ref: 'external_service.yaml' -id: - type: string - example: 66b9aa00-94fa-11ea-9f74-e7e108796192 -owner: - $ref: 'owners.yaml' -settings: - $ref: 'settings.yaml' -severity: - $ref: 'severity_property.yaml' -status: - $ref: 'status.yaml' -tags: - type: array - items: +title: Case response properties +type: object +required: + - closed_at + - closed_by + - comments + - connector + - created_at + - created_by + - description + - duration + - external_service + - id + - owner + - settings + - severity + - status + - tags + - title + - totalAlerts + - totalComment + - updated_at + - updated_by + - version +properties: + closed_at: type: string - example: ["tag-1"] -title: - type: string - example: Case title 1 -totalAlerts: - type: integer - example: 0 -totalComment: - type: integer - example: 0 -updated_at: - type: string - format: date-time - nullable: true - example: null -updated_by: - type: object - properties: - $ref: 'user_properties.yaml' - nullable: true - example: null -version: - type: string - example: WzUzMiwxXQ== + format: date-time + nullable: true + closed_by: + $ref: 'case_response_closed_by_properties.yaml' + comments: + title: Case response properties for comments + description: An array of comment objects for the case. + type: array + items: + discriminator: + propertyName: type + oneOf: + - $ref: 'alert_comment_response_properties.yaml' + - $ref: 'user_comment_response_properties.yaml' + connector: + title: Case response properties for connectors + type: object + properties: + fields: + $ref: 'case_response_connector_field_properties.yaml' + id: + description: The identifier for the connector. To create a case without a connector, use `none`. + type: string + example: none + name: + description: The name of the connector. To create a case without a connector, use `none`. + type: string + example: none + type: + $ref: 'connector_types.yaml' + created_at: + type: string + format: date-time + example: '2022-05-13T09:16:17.416Z' + created_by: + $ref: 'case_response_created_by_properties.yaml' + description: + type: string + example: A case description. + duration: + type: integer + description: > + The elapsed time from the creation of the case to its closure (in seconds). + If the case has not been closed, the duration is set to null. If the case + was closed after less than half a second, the duration is rounded down to + zero. + nullable: true + example: 120 + external_service: + $ref: 'external_service.yaml' + id: + type: string + example: 66b9aa00-94fa-11ea-9f74-e7e108796192 + owner: + $ref: 'owners.yaml' + settings: + $ref: 'settings.yaml' + severity: + $ref: 'severity_property.yaml' + status: + $ref: 'status.yaml' + tags: + type: array + items: + type: string + example: + - tag-1 + title: + type: string + example: Case title 1 + totalAlerts: + type: integer + example: 0 + totalComment: + type: integer + example: 0 + updated_at: + type: string + format: date-time + nullable: true + updated_by: + $ref: 'case_response_updated_by_properties.yaml' + version: + type: string + example: WzUzMiwxXQ== diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml new file mode 100644 index 0000000000000..c59a5565c98b9 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_pushed_by_properties.yaml @@ -0,0 +1,9 @@ +title: Case response properties for pushed_by +type: object +nullable: true +properties: + $ref: 'user_properties.yaml' +required: + - email + - full_name + - username \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml new file mode 100644 index 0000000000000..cd1bae033f2ff --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/case_response_updated_by_properties.yaml @@ -0,0 +1,9 @@ +title: Case response properties for updated_by +type: object +nullable: true +properties: + $ref: 'user_properties.yaml' +required: + - email + - full_name + - username \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml index 950a2bab05603..b3b3182b8c964 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/external_service.yaml @@ -1,4 +1,5 @@ type: object +nullable: true properties: connector_id: type: string diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml new file mode 100644 index 0000000000000..8f18d420ae910 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/rule.yaml @@ -0,0 +1,18 @@ +title: Alerting rule +description: > + The rule that is associated with the alert. It is required only when + `type` is `alert`. This functionality is in technical preview and may be + changed or removed in a future release. Elastic will apply best effort to + fix any issues, but features in technical preview are not subject to the + support SLA of official GA features. +type: object +x-technical-preview: true +properties: + id: + description: The rule identifier. + type: string + example: 94d80550-aaf4-11ec-985f-97e55adae8b9 + name: + description: The rule name. + type: string + example: security_rule \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml index 2d91b007d4310..2c7bd5dcc1215 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_alert_comment_request_properties.yaml @@ -1,20 +1,17 @@ +title: Update case comment request properties for alerts +description: Defines properties for case comment requests when type is alert. +required: + - alertId + - id + - index + - owner + - rule + - type + - version type: object properties: - alertId: - description: > - The alert identifier. It is required only when `type` is `alert`. If it is - an array, `index` must also be an array. This functionality is in - technical preview and may be changed or removed in a future release. - Elastic will apply best effort to fix any issues, but features in - technical preview are not subject to the support SLA of official GA - features. - oneOf: - - type: string - - type: array - items: - type: string - x-technical-preview: true - example: 6b24c4dc44bc720cfc92797f3d61fff952f2b2627db1fb4f8cc49f4530c4ff42 + alertId: + $ref: 'alert_identifiers.yaml' id: type: string description: > @@ -22,31 +19,11 @@ properties: get comments API. example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 index: - description: > - The alert index. It is required only when `type` is `alert`. If it is an - array, `alertId` must also be an array. This functionality is in technical - preview and may be changed or removed in a future release. Elastic will - apply best effort to fix any issues, but features in technical preview are - not subject to the support SLA of official GA features. - oneOf: - - type: string - - type: array - items: - type: string - x-technical-preview: true + $ref: 'alert_indices.yaml' owner: $ref: 'owners.yaml' rule: - description: > - The rule that is associated with the alert. It is required only when - `type` is `alert`. This functionality is in technical preview and may be - changed or removed in a future release. Elastic will apply best effort to - fix any issues, but features in technical preview are not subject to the - support SLA of official GA features. - type: object - x-technical-preview: true - properties: - $ref: 'rule_properties.yaml' + $ref: 'rule.yaml' type: description: The type of comment. type: string @@ -58,12 +35,4 @@ properties: The current comment version. To retrieve version values, use the get comments API. type: string - example: Wzk1LDFd -required: - - alertId - - id - - index - - owner - - rule - - type - - version \ No newline at end of file + example: Wzk1LDFd \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_comment_request.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_comment_request.yaml new file mode 100644 index 0000000000000..cc3974c29194f --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_case_comment_request.yaml @@ -0,0 +1,9 @@ +title: Update case comment request +description: >- + The update case comment API request body varies depending on whether you are + updating an alert or a comment. +discriminator: + propertyName: type +oneOf: + - $ref: 'update_alert_comment_request_properties.yaml' + - $ref: 'update_user_comment_request_properties.yaml' diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml index 83d7f0715da21..22fb76d9bba74 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/update_user_comment_request_properties.yaml @@ -1,3 +1,5 @@ +title: Update case comment request properties for user comments +description: Defines properties for case comment requests when type is user. type: object properties: comment: diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml index 0df26aee07587..b1727d3279abe 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_comment_response_properties.yaml @@ -1,4 +1,7 @@ +title: Case response properties for user comments type: object +required: + - type properties: comment: type: string @@ -8,9 +11,7 @@ properties: format: date-time example: 2022-05-13T09:16:17.416Z created_by: - type: object - properties: - $ref: 'user_properties.yaml' + $ref: 'case_response_created_by_properties.yaml' id: type: string example: 8af6ac20-74f6-11ea-b83a-553aecdb28b6 @@ -22,25 +23,19 @@ properties: nullable: true example: null pushed_by: - type: object - properties: - $ref: 'user_properties.yaml' - nullable: true - example: null + $ref: 'case_response_pushed_by_properties.yaml' type: type: string example: user + enum: + - user updated_at: type: string format: date-time nullable: true example: null updated_by: - type: object - properties: - $ref: 'user_properties.yaml' - nullable: true - example: null + $ref: 'case_response_updated_by_properties.yaml' version: type: string example: WzIwNDMxLDFd \ No newline at end of file diff --git a/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml b/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml index 1c3596dc6f9b9..19b76a6000c02 100644 --- a/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml +++ b/x-pack/plugins/cases/docs/openapi/components/schemas/user_properties.yaml @@ -1,12 +1,15 @@ email: type: string example: null + nullable: true full_name: type: string example: null + nullable: true username: type: string example: elastic + nullable: true profile_uid: type: string example: u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0 diff --git a/x-pack/plugins/cases/docs/openapi/entrypoint-min.yaml b/x-pack/plugins/cases/docs/openapi/entrypoint-min.yaml new file mode 100644 index 0000000000000..595d33a7465d2 --- /dev/null +++ b/x-pack/plugins/cases/docs/openapi/entrypoint-min.yaml @@ -0,0 +1,59 @@ +openapi: 3.0.1 +info: + title: Cases + description: OpenAPI schema for Cases endpoints + version: '0.2' + contact: + name: Cases Team + license: + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license +tags: + - name: cases + description: Case APIs enable you to open and track issues. +servers: + - url: 'http://localhost:5601' + description: local +paths: +# '/s/{spaceId}/api/cases': +# $ref: 'paths/s@{spaceid}@api@cases.yaml' +# '/s/{spaceId}/api/cases/_find': +# $ref: 'paths/s@{spaceid}@api@cases@_find.yaml' +# '/s/{spaceId}/api/cases/alerts/{alertId}': +# $ref: 'paths/s@{spaceid}@api@cases@alerts@{alertid}.yaml' +# '/s/{spaceId}/api/cases/configure': +# $ref: paths/s@{spaceid}@api@cases@configure.yaml +# '/s/{spaceId}/api/cases/configure/{configurationId}': +# $ref: paths/s@{spaceid}@api@cases@configure@{configurationid}.yaml +# '/s/{spaceId}/api/cases/configure/connectors/_find': +# $ref: paths/s@{spaceid}@api@cases@configure@connectors@_find.yaml +# '/s/{spaceId}/api/cases/reporters': +# $ref: 'paths/s@{spaceid}@api@cases@reporters.yaml' +# '/s/{spaceId}/api/cases/status': +# $ref: 'paths/s@{spaceid}@api@cases@status.yaml' +# '/s/{spaceId}/api/cases/tags': +# $ref: 'paths/s@{spaceid}@api@cases@tags.yaml' +# '/s/{spaceId}/api/cases/{caseId}': +# $ref: 'paths/s@{spaceid}@api@cases@{caseid}.yaml' +# '/s/{spaceId}/api/cases/{caseId}/alerts': +# $ref: 'paths/s@{spaceid}@api@cases@{caseid}@alerts.yaml' + '/s/{spaceId}/api/cases/{caseId}/comments': + $ref: 'paths/s@{spaceid}@api@cases@{caseid}@comments.yaml' +# '/s/{spaceId}/api/cases/{caseId}/comments/{commentId}': +# $ref: 'paths/s@{spaceid}@api@cases@{caseid}@comments@{commentid}.yaml' +# '/s/{spaceId}/api/cases/{caseId}/connector/{connectorId}/_push': +# $ref: 'paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml' +# '/s/{spaceId}/api/cases/{caseId}/user_actions': +# $ref: 'paths/s@{spaceid}@api@cases@{caseid}@user_actions.yaml' +components: + securitySchemes: + basicAuth: + type: http + scheme: basic + apiKeyAuth: + type: apiKey + in: header + name: ApiKey +security: + - basicAuth: [] + - apiKeyAuth: [] diff --git a/x-pack/plugins/cases/docs/openapi/entrypoint.yaml b/x-pack/plugins/cases/docs/openapi/entrypoint.yaml index 6995d1482e0a9..6f467f77ef93c 100644 --- a/x-pack/plugins/cases/docs/openapi/entrypoint.yaml +++ b/x-pack/plugins/cases/docs/openapi/entrypoint.yaml @@ -11,8 +11,6 @@ info: tags: - name: cases description: Case APIs enable you to open and track issues. - - name: kibana - description: Kibana APIs enable you to interact with Kibana features. servers: - url: 'http://localhost:5601' description: local diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases.yaml index 59abb58531821..80092f32cbe60 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases.yaml @@ -57,11 +57,9 @@ post: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' examples: createCaseResponse: $ref: '../components/examples/create_case_response.yaml' @@ -160,11 +158,9 @@ patch: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' examples: updateCaseResponse: $ref: '../components/examples/update_case_response.yaml' diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@_find.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@_find.yaml index a260321248357..6d5bb0c2812cd 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@_find.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@_find.yaml @@ -138,9 +138,7 @@ get: cases: type: array items: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' count_closed_cases: type: integer count_in_progress_cases: diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml index 9e8ca4660c44d..d32d24b9fa01b 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}.yaml @@ -21,11 +21,9 @@ get: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' examples: getCaseResponse: $ref: '../components/examples/get_case_response.yaml' diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments.yaml index c8a045267a492..2246ff1d16a9d 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@comments.yaml @@ -12,12 +12,11 @@ post: - $ref: '../components/parameters/case_id.yaml' - $ref: '../components/parameters/space_id.yaml' requestBody: + required: true content: application/json: schema: - oneOf: - - $ref: '../components/schemas/add_alert_comment_request_properties.yaml' - - $ref: '../components/schemas/add_user_comment_request_properties.yaml' + $ref: '../components/schemas/add_case_comment_request.yaml' examples: createCaseCommentRequest: $ref: '../components/examples/add_comment_request.yaml' @@ -25,11 +24,9 @@ post: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' examples: createCaseCommentResponse: $ref: '../components/examples/add_comment_response.yaml' @@ -70,12 +67,11 @@ patch: - $ref: '../components/parameters/case_id.yaml' - $ref: '../components/parameters/space_id.yaml' requestBody: + required: true content: application/json: schema: - oneOf: - - $ref: '../components/schemas/update_alert_comment_request_properties.yaml' - - $ref: '../components/schemas/update_user_comment_request_properties.yaml' + $ref: '../components/schemas/update_case_comment_request.yaml' examples: updateCaseCommentRequest: $ref: '../components/examples/update_comment_request.yaml' @@ -83,11 +79,9 @@ patch: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' examples: updateCaseCommentResponse: $ref: '../components/examples/update_comment_response.yaml' @@ -111,14 +105,10 @@ get: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: array - items: - anyOf: - - $ref: '../components/schemas/alert_comment_response_properties.yaml' - - $ref: '../components/schemas/user_comment_response_properties.yaml' - examples: {} + $ref: '../components/schemas/case_response_properties.yaml' + servers: - url: https://localhost:5601 diff --git a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml index 32caad2bc4086..37587abd760e1 100644 --- a/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml +++ b/x-pack/plugins/cases/docs/openapi/paths/s@{spaceid}@api@cases@{caseid}@connector@{connectorid}@_push.yaml @@ -21,11 +21,9 @@ post: '200': description: Indicates a successful call. content: - application/json; charset=utf-8: + application/json: schema: - type: object - properties: - $ref: '../components/schemas/case_response_properties.yaml' + $ref: '../components/schemas/case_response_properties.yaml' examples: pushCaseResponse: $ref: '../components/examples/push_case_response.yaml' diff --git a/x-pack/plugins/cases/public/common/mock/permissions.ts b/x-pack/plugins/cases/public/common/mock/permissions.ts index 1166dbed8ca88..7395e966037ea 100644 --- a/x-pack/plugins/cases/public/common/mock/permissions.ts +++ b/x-pack/plugins/cases/public/common/mock/permissions.ts @@ -17,6 +17,8 @@ export const noUpdateCasesPermissions = () => buildCasesPermissions({ update: fa export const noPushCasesPermissions = () => buildCasesPermissions({ push: false }); export const noDeleteCasesPermissions = () => buildCasesPermissions({ delete: false }); export const writeCasesPermissions = () => buildCasesPermissions({ read: false }); +export const onlyDeleteCasesPermission = () => + buildCasesPermissions({ read: false, create: false, update: false, delete: true, push: false }); export const buildCasesPermissions = (overrides: Partial> = {}) => { const create = overrides.create ?? true; diff --git a/x-pack/plugins/cases/public/components/actions/delete/translations.ts b/x-pack/plugins/cases/public/components/actions/delete/translations.ts new file mode 100644 index 0000000000000..1ead4dd9f7d17 --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/delete/translations.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +export { DELETED_CASES } from '../../../common/translations'; + +export const BULK_ACTION_DELETE_LABEL = i18n.translate( + 'xpack.cases.caseTable.bulkActions.deleteCases', + { + defaultMessage: 'Delete cases', + } +); + +export const DELETE_ACTION_LABEL = i18n.translate('xpack.cases.caseTable.action.deleteCase', { + defaultMessage: 'Delete case', +}); diff --git a/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.test.tsx b/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.test.tsx new file mode 100644 index 0000000000000..747aa0e84e1d7 --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.test.tsx @@ -0,0 +1,187 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AppMockRenderer, createAppMockRenderer } from '../../../common/mock'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { useDeleteAction } from './use_delete_action'; + +import * as api from '../../../containers/api'; +import { basicCase } from '../../../containers/mock'; + +jest.mock('../../../containers/api'); + +describe('useDeleteAction', () => { + let appMockRender: AppMockRenderer; + const onAction = jest.fn(); + const onActionSuccess = jest.fn(); + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders an action with one case', async () => { + const { result } = renderHook( + () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current.getAction([basicCase])).toMatchInlineSnapshot(` + Object { + "data-test-subj": "cases-bulk-action-delete", + "disabled": false, + "icon": , + "key": "cases-bulk-action-delete", + "name": + Delete case + , + "onClick": [Function], + } + `); + }); + + it('renders an action with multiple cases', async () => { + const { result } = renderHook( + () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current.getAction([basicCase, basicCase])).toMatchInlineSnapshot(` + Object { + "data-test-subj": "cases-bulk-action-delete", + "disabled": false, + "icon": , + "key": "cases-bulk-action-delete", + "name": + Delete cases + , + "onClick": [Function], + } + `); + }); + + it('deletes the selected cases', async () => { + const deleteSpy = jest.spyOn(api, 'deleteCases'); + + const { result, waitFor } = renderHook( + () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const action = result.current.getAction([basicCase]); + + act(() => { + action.onClick(); + }); + + expect(onAction).toHaveBeenCalled(); + expect(result.current.isModalVisible).toBe(true); + + act(() => { + result.current.onConfirmDeletion(); + }); + + await waitFor(() => { + expect(result.current.isModalVisible).toBe(false); + expect(onActionSuccess).toHaveBeenCalled(); + expect(deleteSpy).toHaveBeenCalledWith(['basic-case-id'], expect.anything()); + }); + }); + + it('closes the modal', async () => { + const { result, waitFor } = renderHook( + () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const action = result.current.getAction([basicCase]); + + act(() => { + action.onClick(); + }); + + expect(result.current.isModalVisible).toBe(true); + + act(() => { + result.current.onCloseModal(); + }); + + await waitFor(() => { + expect(result.current.isModalVisible).toBe(false); + }); + }); + + it('shows the success toaster correctly when delete one case', async () => { + const { result, waitFor } = renderHook( + () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const action = result.current.getAction([basicCase]); + + act(() => { + action.onClick(); + }); + + act(() => { + result.current.onConfirmDeletion(); + }); + + await waitFor(() => { + expect(appMockRender.coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( + 'Deleted case' + ); + }); + }); + + it('shows the success toaster correctly when delete multiple case', async () => { + const { result, waitFor } = renderHook( + () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const action = result.current.getAction([basicCase, basicCase]); + + act(() => { + action.onClick(); + }); + + act(() => { + result.current.onConfirmDeletion(); + }); + + await waitFor(() => { + expect(appMockRender.coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( + 'Deleted 2 cases' + ); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx b/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx new file mode 100644 index 0000000000000..92184dbd64648 --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/delete/use_delete_action.tsx @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useState } from 'react'; +import { EuiIcon, EuiTextColor, useEuiTheme } from '@elastic/eui'; +import { Case } from '../../../../common'; +import { useDeleteCases } from '../../../containers/use_delete_cases'; + +import * as i18n from './translations'; +import { UseActionProps } from '../types'; +import { useCasesContext } from '../../cases_context/use_cases_context'; + +const getDeleteActionTitle = (totalCases: number): string => + totalCases > 1 ? i18n.BULK_ACTION_DELETE_LABEL : i18n.DELETE_ACTION_LABEL; + +export const useDeleteAction = ({ onAction, onActionSuccess, isDisabled }: UseActionProps) => { + const euiTheme = useEuiTheme(); + const { permissions } = useCasesContext(); + const [isModalVisible, setIsModalVisible] = useState(false); + const [caseToBeDeleted, setCaseToBeDeleted] = useState([]); + const canDelete = permissions.delete; + const isActionDisabled = isDisabled || !canDelete; + + const onCloseModal = useCallback(() => setIsModalVisible(false), []); + const openModal = useCallback( + (selectedCases: Case[]) => { + onAction(); + setIsModalVisible(true); + setCaseToBeDeleted(selectedCases); + }, + [onAction] + ); + + const { mutate: deleteCases } = useDeleteCases(); + + const onConfirmDeletion = useCallback(() => { + onCloseModal(); + deleteCases( + { + caseIds: caseToBeDeleted.map(({ id }) => id), + successToasterTitle: i18n.DELETED_CASES(caseToBeDeleted.length), + }, + { onSuccess: onActionSuccess } + ); + }, [deleteCases, onActionSuccess, onCloseModal, caseToBeDeleted]); + + const color = isActionDisabled ? euiTheme.euiTheme.colors.disabled : 'danger'; + + const getAction = (selectedCases: Case[]) => { + return { + name: {getDeleteActionTitle(selectedCases.length)}, + onClick: () => openModal(selectedCases), + disabled: isActionDisabled, + 'data-test-subj': 'cases-bulk-action-delete', + icon: , + key: 'cases-bulk-action-delete', + }; + }; + + return { getAction, isModalVisible, onConfirmDeletion, onCloseModal, canDelete }; +}; + +export type UseDeleteAction = ReturnType; diff --git a/x-pack/plugins/cases/public/components/actions/status/translations.ts b/x-pack/plugins/cases/public/components/actions/status/translations.ts new file mode 100644 index 0000000000000..68141c7dc344a --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/status/translations.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +export { MARK_CASE_IN_PROGRESS, OPEN_CASE, CLOSE_CASE } from '../../../common/translations'; + +export const CLOSED_CASES = ({ + totalCases, + caseTitle, +}: { + totalCases: number; + caseTitle?: string; +}) => + i18n.translate('xpack.cases.containers.closedCases', { + values: { caseTitle, totalCases }, + defaultMessage: 'Closed {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', + }); + +export const REOPENED_CASES = ({ + totalCases, + caseTitle, +}: { + totalCases: number; + caseTitle?: string; +}) => + i18n.translate('xpack.cases.containers.reopenedCases', { + values: { caseTitle, totalCases }, + defaultMessage: 'Opened {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', + }); + +export const MARK_IN_PROGRESS_CASES = ({ + totalCases, + caseTitle, +}: { + totalCases: number; + caseTitle?: string; +}) => + i18n.translate('xpack.cases.containers.markInProgressCases', { + values: { caseTitle, totalCases }, + defaultMessage: + 'Marked {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}} as in progress', + }); + +export const BULK_ACTION_STATUS_CLOSE = i18n.translate( + 'xpack.cases.caseTable.bulkActions.status.close', + { + defaultMessage: 'Close selected', + } +); + +export const BULK_ACTION_STATUS_OPEN = i18n.translate( + 'xpack.cases.caseTable.bulkActions.status.open', + { + defaultMessage: 'Open selected', + } +); + +export const BULK_ACTION_STATUS_IN_PROGRESS = i18n.translate( + 'xpack.cases.caseTable.bulkActions.status.inProgress', + { + defaultMessage: 'Mark in progress', + } +); diff --git a/x-pack/plugins/cases/public/components/actions/status/use_status_action.test.tsx b/x-pack/plugins/cases/public/components/actions/status/use_status_action.test.tsx new file mode 100644 index 0000000000000..a0f16dbaa1760 --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/status/use_status_action.test.tsx @@ -0,0 +1,198 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AppMockRenderer, createAppMockRenderer } from '../../../common/mock'; +import { act, renderHook } from '@testing-library/react-hooks'; +import { useStatusAction } from './use_status_action'; + +import * as api from '../../../containers/api'; +import { basicCase } from '../../../containers/mock'; +import { CaseStatuses } from '../../../../common'; + +jest.mock('../../../containers/api'); + +describe('useStatusAction', () => { + let appMockRender: AppMockRenderer; + const onAction = jest.fn(); + const onActionSuccess = jest.fn(); + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders an action', async () => { + const { result } = renderHook( + () => + useStatusAction({ + onAction, + onActionSuccess, + isDisabled: false, + }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current.getActions([basicCase])).toMatchInlineSnapshot(` + Array [ + Object { + "data-test-subj": "cases-bulk-action-status-open", + "disabled": true, + "icon": "empty", + "key": "cases-bulk-action-status-open", + "name": "Open", + "onClick": [Function], + }, + Object { + "data-test-subj": "cases-bulk-action-status-in-progress", + "disabled": false, + "icon": "empty", + "key": "cases-bulk-action-status-in-progress", + "name": "In progress", + "onClick": [Function], + }, + Object { + "data-test-subj": "cases-bulk-action-status-closed", + "disabled": false, + "icon": "empty", + "key": "cases-bulk-status-action", + "name": "Closed", + "onClick": [Function], + }, + ] + `); + }); + + it('update the status cases', async () => { + const updateSpy = jest.spyOn(api, 'updateCases'); + + const { result, waitFor } = renderHook( + () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const actions = result.current.getActions([basicCase]); + + for (const [index, status] of [ + CaseStatuses.open, + CaseStatuses['in-progress'], + CaseStatuses.closed, + ].entries()) { + act(() => { + // @ts-expect-error: onClick expects a MouseEvent argument + actions[index]!.onClick(); + }); + + await waitFor(() => { + expect(onAction).toHaveBeenCalled(); + expect(onActionSuccess).toHaveBeenCalled(); + expect(updateSpy).toHaveBeenCalledWith( + [{ status, id: basicCase.id, version: basicCase.version }], + expect.anything() + ); + }); + } + }); + + const singleCaseTests = [ + [CaseStatuses.open, 0, 'Opened "Another horrible breach!!"'], + [CaseStatuses['in-progress'], 1, 'Marked "Another horrible breach!!" as in progress'], + [CaseStatuses.closed, 2, 'Closed "Another horrible breach!!"'], + ]; + + it.each(singleCaseTests)( + 'shows the success toaster correctly when updating the status of the case: %s', + async (_, index, expectedMessage) => { + const { result, waitFor } = renderHook( + () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const actions = result.current.getActions([basicCase]); + + act(() => { + // @ts-expect-error: onClick expects a MouseEvent argument + actions[index]!.onClick(); + }); + + await waitFor(() => { + expect(appMockRender.coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( + expectedMessage + ); + }); + } + ); + + const multipleCasesTests: Array<[CaseStatuses, number, string]> = [ + [CaseStatuses.open, 0, 'Opened 2 cases'], + [CaseStatuses['in-progress'], 1, 'Marked 2 cases as in progress'], + [CaseStatuses.closed, 2, 'Closed 2 cases'], + ]; + + it.each(multipleCasesTests)( + 'shows the success toaster correctly when updating the status of the case: %s', + async (_, index, expectedMessage) => { + const { result, waitFor } = renderHook( + () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const actions = result.current.getActions([basicCase, basicCase]); + + act(() => { + // @ts-expect-error: onClick expects a MouseEvent argument + actions[index]!.onClick(); + }); + + await waitFor(() => { + expect(appMockRender.coreStart.notifications.toasts.addSuccess).toHaveBeenCalledWith( + expectedMessage + ); + }); + } + ); + + const disabledTests: Array<[CaseStatuses, number]> = [ + [CaseStatuses.open, 0], + [CaseStatuses['in-progress'], 1], + [CaseStatuses.closed, 2], + ]; + + it.each(disabledTests)('disables the status button correctly: %s', async (status, index) => { + const { result } = renderHook( + () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const actions = result.current.getActions([{ ...basicCase, status }]); + expect(actions[index].disabled).toBe(true); + }); + + it.each(disabledTests)( + 'disables the status button correctly if isDisabled=true: %s', + async (status, index) => { + const { result } = renderHook( + () => useStatusAction({ onAction, onActionSuccess, isDisabled: true }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const actions = result.current.getActions([basicCase]); + expect(actions[index].disabled).toBe(true); + } + ); +}); diff --git a/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx b/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx new file mode 100644 index 0000000000000..8f1100aaab90d --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/status/use_status_action.tsx @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; +import { useUpdateCases } from '../../../containers/use_bulk_update_case'; +import { Case, CaseStatuses } from '../../../../common'; + +import * as i18n from './translations'; +import { UseActionProps } from '../types'; +import { statuses } from '../../status'; +import { useCasesContext } from '../../cases_context/use_cases_context'; + +const getStatusToasterMessage = (status: CaseStatuses, cases: Case[]): string => { + const totalCases = cases.length; + const caseTitle = totalCases === 1 ? cases[0].title : ''; + + if (status === CaseStatuses.open) { + return i18n.REOPENED_CASES({ totalCases, caseTitle }); + } else if (status === CaseStatuses['in-progress']) { + return i18n.MARK_IN_PROGRESS_CASES({ totalCases, caseTitle }); + } else if (status === CaseStatuses.closed) { + return i18n.CLOSED_CASES({ totalCases, caseTitle }); + } + + return ''; +}; + +interface UseStatusActionProps extends UseActionProps { + selectedStatus?: CaseStatuses; +} + +const shouldDisableStatus = (cases: Case[], status: CaseStatuses) => + cases.every((theCase) => theCase.status === status); + +export const useStatusAction = ({ + onAction, + onActionSuccess, + isDisabled, + selectedStatus, +}: UseStatusActionProps) => { + const { mutate: updateCases } = useUpdateCases(); + const { permissions } = useCasesContext(); + const canUpdateStatus = permissions.update; + const isActionDisabled = isDisabled || !canUpdateStatus; + + const handleUpdateCaseStatus = useCallback( + (selectedCases: Case[], status: CaseStatuses) => { + onAction(); + const casesToUpdate = selectedCases.map((theCase) => ({ + status, + id: theCase.id, + version: theCase.version, + })); + + updateCases( + { + cases: casesToUpdate, + successToasterTitle: getStatusToasterMessage(status, selectedCases), + }, + { onSuccess: onActionSuccess } + ); + }, + [onAction, updateCases, onActionSuccess] + ); + + const getStatusIcon = (status: CaseStatuses): string => + selectedStatus && selectedStatus === status ? 'check' : 'empty'; + + const getActions = (selectedCases: Case[]): EuiContextMenuPanelItemDescriptor[] => { + return [ + { + name: statuses[CaseStatuses.open].label, + icon: getStatusIcon(CaseStatuses.open), + onClick: () => handleUpdateCaseStatus(selectedCases, CaseStatuses.open), + disabled: isActionDisabled || shouldDisableStatus(selectedCases, CaseStatuses.open), + 'data-test-subj': 'cases-bulk-action-status-open', + key: 'cases-bulk-action-status-open', + }, + { + name: statuses[CaseStatuses['in-progress']].label, + icon: getStatusIcon(CaseStatuses['in-progress']), + onClick: () => handleUpdateCaseStatus(selectedCases, CaseStatuses['in-progress']), + disabled: + isActionDisabled || shouldDisableStatus(selectedCases, CaseStatuses['in-progress']), + 'data-test-subj': 'cases-bulk-action-status-in-progress', + key: 'cases-bulk-action-status-in-progress', + }, + { + name: statuses[CaseStatuses.closed].label, + icon: getStatusIcon(CaseStatuses.closed), + onClick: () => handleUpdateCaseStatus(selectedCases, CaseStatuses.closed), + disabled: isActionDisabled || shouldDisableStatus(selectedCases, CaseStatuses.closed), + 'data-test-subj': 'cases-bulk-action-status-closed', + key: 'cases-bulk-status-action', + }, + ]; + }; + + return { getActions, canUpdateStatus }; +}; + +export type UseStatusAction = ReturnType; diff --git a/x-pack/plugins/cases/public/components/actions/types.ts b/x-pack/plugins/cases/public/components/actions/types.ts new file mode 100644 index 0000000000000..20a566a20c670 --- /dev/null +++ b/x-pack/plugins/cases/public/components/actions/types.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export interface UseActionProps { + onAction: () => void; + onActionSuccess: () => void; + isDisabled: boolean; +} diff --git a/x-pack/plugins/cases/public/components/all_cases/actions.tsx b/x-pack/plugins/cases/public/components/all_cases/actions.tsx deleted file mode 100644 index f978cd1b3f205..0000000000000 --- a/x-pack/plugins/cases/public/components/all_cases/actions.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DefaultItemIconButtonAction } from '@elastic/eui/src/components/basic_table/action_types'; - -import { Case } from '../../containers/types'; -import * as i18n from './translations'; - -interface GetActions { - deleteCaseOnClick: (deleteCase: Case) => void; -} - -export const getActions = ({ - deleteCaseOnClick, -}: GetActions): Array> => [ - { - description: i18n.DELETE_CASE(), - icon: 'trash', - color: 'danger', - name: i18n.DELETE_CASE(), - onClick: deleteCaseOnClick, - type: 'icon', - 'data-test-subj': 'action-delete', - }, -]; diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx index 1cc3a5f0263e5..30a2389b4f307 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx @@ -18,17 +18,18 @@ import { AppMockRenderer, createAppMockRenderer, noDeleteCasesPermissions, + readCasesPermissions, TestProviders, } from '../../common/mock'; import { useGetCasesMockState, connectorsMock } from '../../containers/mock'; import { StatusAll } from '../../../common/ui/types'; -import { CaseSeverity, CaseStatuses } from '../../../common/api'; +import { CaseStatuses } from '../../../common/api'; import { SECURITY_SOLUTION_OWNER } from '../../../common/constants'; import { getEmptyTagValue } from '../empty_value'; import { useKibana } from '../../common/lib/kibana'; import { AllCasesList } from './all_cases_list'; -import { CasesColumns, GetCasesColumn, useCasesColumns } from './columns'; +import { GetCasesColumn, useCasesColumns, UseCasesColumnsReturnValue } from './use_cases_columns'; import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks'; import { registerConnectorsToMockActionRegistry } from '../../common/mock/register_connectors'; import { createStartServicesMock } from '../../common/lib/kibana/kibana_react.mock'; @@ -97,10 +98,6 @@ describe('AllCasesListGeneric', () => { }; const defaultColumnArgs = { - caseDetailsNavigation: { - href: jest.fn(), - onClick: jest.fn(), - }, filterStatus: CaseStatuses.open, handleIsLoading: jest.fn(), isLoadingCases: [], @@ -236,7 +233,7 @@ describe('AllCasesListGeneric', () => { expect(column.find('span').text()).toEqual(emptyTag); }; - const { result } = renderHook( + const { result } = renderHook( () => useCasesColumns(defaultColumnArgs), { wrapper: ({ children }) => {children}, @@ -244,26 +241,12 @@ describe('AllCasesListGeneric', () => { ); await waitFor(() => { - result.current.map( - (i, key) => - i.name != null && - !Object.prototype.hasOwnProperty.call(i, 'actions') && - checkIt(`${i.name}`, key) + result.current.columns.map( + (i, key) => i.name != null && i.name !== 'Actions' && checkIt(`${i.name}`, key) ); }); }); - it('should render delete actions for case', async () => { - const wrapper = mount( - - - - ); - await waitFor(() => { - expect(wrapper.find('[data-test-subj="action-delete"]').first().props().disabled).toBeFalsy(); - }); - }); - it('should tableHeaderSortButton AllCasesList', async () => { const wrapper = mount( @@ -285,27 +268,10 @@ describe('AllCasesListGeneric', () => { }); }); - it('Updates status when status context menu is updated', async () => { - const wrapper = mount( - - - - ); - wrapper.find(`[data-test-subj="case-view-status-dropdown"] button`).first().simulate('click'); - wrapper - .find(`[data-test-subj="case-view-status-dropdown-closed"] button`) - .first() - .simulate('click'); + it('renders the status column', async () => { + const res = appMockRenderer.render(); - await waitFor(() => { - const firstCase = useGetCasesMockState.data.cases[0]; - expect(updateCaseProperty).toHaveBeenCalledWith({ - caseData: firstCase, - updateKey: 'status', - updateValue: CaseStatuses.closed, - onSuccess: expect.anything(), - }); - }); + expect(res.getByTestId('tableHeaderCell_Status_6')).toBeInTheDocument(); }); it('should render the case stats', () => { @@ -317,133 +283,6 @@ describe('AllCasesListGeneric', () => { expect(wrapper.find('[data-test-subj="cases-count-stats"]')).toBeTruthy(); }); - it('Bulk delete', async () => { - const deleteCasesSpy = jest.spyOn(api, 'deleteCases'); - const result = appMockRenderer.render(); - - act(() => { - userEvent.click(result.getByTestId('checkboxSelectAll')); - }); - - act(() => { - userEvent.click(result.getByText('Bulk actions')); - }); - - await waitForEuiPopoverOpen(); - - act(() => { - userEvent.click(result.getByTestId('cases-bulk-delete-button'), undefined, { - skipPointerEventsCheck: true, - }); - }); - - await waitFor(() => { - expect(result.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); - }); - - act(() => { - userEvent.click(result.getByTestId('confirmModalConfirmButton')); - }); - - await waitFor(() => { - expect(deleteCasesSpy).toHaveBeenCalledWith( - [ - 'basic-case-id', - '1', - '2', - '3', - '4', - 'case-with-alerts-id', - 'case-with-alerts-syncoff-id', - 'case-with-registered-attachment', - ], - expect.anything() - ); - }); - }); - - it('Renders only bulk delete on status all', async () => { - const wrapper = mount( - - - - ); - - wrapper.find('[data-test-subj*="checkboxSelectRow-"]').first().simulate('click'); - wrapper.find('[data-test-subj="case-table-bulk-actions"] button').first().simulate('click'); - - await waitFor(() => { - expect(wrapper.find('[data-test-subj="cases-bulk-open-button"]').exists()).toEqual(false); - expect(wrapper.find('[data-test-subj="cases-bulk-in-progress-button"]').exists()).toEqual( - false - ); - expect(wrapper.find('[data-test-subj="cases-bulk-close-button"]').exists()).toEqual(false); - expect( - wrapper.find('[data-test-subj="cases-bulk-delete-button"]').first().props().disabled - ).toEqual(true); - }); - }); - - it('Bulk close status update', async () => { - const updateCasesSpy = jest.spyOn(api, 'updateCases'); - - const result = appMockRenderer.render(); - const theCase = useGetCasesMockState.data.cases[0]; - userEvent.click(result.getByTestId('case-status-filter')); - await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('case-status-filter-in-progress')); - userEvent.click(result.getByTestId(`checkboxSelectRow-${theCase.id}`)); - userEvent.click(result.getByText('Bulk actions')); - await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('cases-bulk-close-button')); - await waitFor(() => {}); - - expect(updateCasesSpy).toBeCalledWith( - [{ id: theCase.id, version: theCase.version, status: CaseStatuses.closed }], - expect.anything() - ); - }); - - it('Bulk open status update', async () => { - const updateCasesSpy = jest.spyOn(api, 'updateCases'); - - const result = appMockRenderer.render(); - const theCase = useGetCasesMockState.data.cases[0]; - userEvent.click(result.getByTestId('case-status-filter')); - await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('case-status-filter-closed')); - userEvent.click(result.getByTestId(`checkboxSelectRow-${theCase.id}`)); - userEvent.click(result.getByText('Bulk actions')); - await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('cases-bulk-open-button')); - await waitFor(() => {}); - - expect(updateCasesSpy).toBeCalledWith( - [{ id: theCase.id, version: theCase.version, status: CaseStatuses.open }], - expect.anything() - ); - }); - - it('Bulk in-progress status update', async () => { - const updateCasesSpy = jest.spyOn(api, 'updateCases'); - - const result = appMockRenderer.render(); - const theCase = useGetCasesMockState.data.cases[0]; - userEvent.click(result.getByTestId('case-status-filter')); - await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('case-status-filter-closed')); - userEvent.click(result.getByTestId(`checkboxSelectRow-${theCase.id}`)); - userEvent.click(result.getByText('Bulk actions')); - await waitForEuiPopoverOpen(); - userEvent.click(result.getByTestId('cases-bulk-in-progress-button')); - await waitFor(() => {}); - - expect(updateCasesSpy).toBeCalledWith( - [{ id: theCase.id, version: theCase.version, status: CaseStatuses['in-progress'] }], - expect.anything() - ); - }); - it('should not render table utility bar when isSelectorView=true', async () => { const wrapper = mount( @@ -522,60 +361,21 @@ describe('AllCasesListGeneric', () => { }); it('should call onRowClick when clicking a case with modal=true', async () => { + const theCase = defaultGetCases.data.cases[0]; + const wrapper = mount( ); - wrapper.find('[data-test-subj="cases-table-row-select-1"]').first().simulate('click'); + wrapper + .find(`[data-test-subj="cases-table-row-select-${theCase.id}"]`) + .first() + .simulate('click'); + await waitFor(() => { - expect(onRowClick).toHaveBeenCalledWith({ - assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }], - closedAt: null, - closedBy: null, - comments: [], - connector: { fields: null, id: '123', name: 'My Connector', type: '.jira' }, - createdAt: '2020-02-19T23:06:33.798Z', - createdBy: { - email: 'leslie.knope@elastic.co', - fullName: 'Leslie Knope', - username: 'lknope', - }, - description: 'Security banana Issue', - severity: CaseSeverity.LOW, - duration: null, - externalService: { - connectorId: '123', - connectorName: 'connector name', - externalId: 'external_id', - externalTitle: 'external title', - externalUrl: 'basicPush.com', - pushedAt: '2020-02-20T15:02:57.995Z', - pushedBy: { - email: 'leslie.knope@elastic.co', - fullName: 'Leslie Knope', - username: 'lknope', - }, - }, - id: '1', - owner: SECURITY_SOLUTION_OWNER, - status: 'open', - tags: ['coke', 'pepsi'], - title: 'Another horrible breach!!', - totalAlerts: 0, - totalComment: 0, - updatedAt: '2020-02-20T15:02:57.995Z', - updatedBy: { - email: 'leslie.knope@elastic.co', - fullName: 'Leslie Knope', - username: 'lknope', - }, - version: 'WzQ3LDFd', - settings: { - syncAlerts: true, - }, - }); + expect(onRowClick).toHaveBeenCalledWith(theCase); }); }); @@ -591,7 +391,7 @@ describe('AllCasesListGeneric', () => { }); }); - it('should change the status to closed', async () => { + it('should filter by status: closed', async () => { const result = appMockRenderer.render(); userEvent.click(result.getByTestId('case-status-filter')); await waitForEuiPopoverOpen(); @@ -610,7 +410,7 @@ describe('AllCasesListGeneric', () => { }); }); - it('should change the status to in-progress', async () => { + it('should filter by status: in-progress', async () => { const result = appMockRenderer.render(); userEvent.click(result.getByTestId('case-status-filter')); await waitForEuiPopoverOpen(); @@ -629,7 +429,7 @@ describe('AllCasesListGeneric', () => { }); }); - it('should change the status to open', async () => { + it('should filter by status: open', async () => { const result = appMockRenderer.render(); userEvent.click(result.getByTestId('case-status-filter')); await waitForEuiPopoverOpen(); @@ -668,34 +468,7 @@ describe('AllCasesListGeneric', () => { }); }); - it('should not render status when isSelectorView=true', async () => { - const wrapper = mount( - - - - ); - - const { result } = renderHook( - () => - useCasesColumns({ - ...defaultColumnArgs, - isSelectorView: true, - }), - { - wrapper: ({ children }) => {children}, - } - ); - - expect(result.current.find((i) => i.name === 'Status')).toBeFalsy(); - - await waitFor(() => { - expect(wrapper.find('[data-test-subj="cases-table"]').exists()).toBeTruthy(); - }); - - expect(wrapper.find('[data-test-subj="case-view-status-dropdown"]').exists()).toBeFalsy(); - }); - - it.skip('renders the first available status when hiddenStatus is given', async () => { + it('renders the first available status when hiddenStatus is given', async () => { const wrapper = mount( @@ -926,6 +699,249 @@ describe('AllCasesListGeneric', () => { }); }); }); + + describe('Actions', () => { + const updateCasesSpy = jest.spyOn(api, 'updateCases'); + const deleteCasesSpy = jest.spyOn(api, 'deleteCases'); + + describe('Bulk actions', () => { + it('Renders bulk action', async () => { + const result = appMockRenderer.render(); + + act(() => { + userEvent.click(result.getByTestId('checkboxSelectAll')); + }); + + act(() => { + userEvent.click(result.getByText('Bulk actions')); + }); + + await waitForEuiPopoverOpen(); + + expect(result.getByTestId('case-bulk-action-status')).toBeInTheDocument(); + expect(result.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + }); + + it.each([[CaseStatuses.open], [CaseStatuses['in-progress']], [CaseStatuses.closed]])( + 'Bulk update status: %s', + async (status) => { + const result = appMockRenderer.render(); + + act(() => { + userEvent.click(result.getByTestId('checkboxSelectAll')); + }); + + act(() => { + userEvent.click(result.getByText('Bulk actions')); + }); + + await waitForEuiPopoverOpen(); + + act(() => { + userEvent.click(result.getByTestId('case-bulk-action-status')); + }); + + await waitFor(() => { + expect(result.getByTestId(`cases-bulk-action-status-${status}`)).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(result.getByTestId(`cases-bulk-action-status-${status}`)); + }); + + await waitForComponentToUpdate(); + + expect(updateCasesSpy).toBeCalledWith( + useGetCasesMockState.data.cases.map(({ id, version }) => ({ + id, + version, + status, + })), + expect.anything() + ); + } + ); + + it('Bulk delete', async () => { + const result = appMockRenderer.render(); + + act(() => { + userEvent.click(result.getByTestId('checkboxSelectAll')); + }); + + act(() => { + userEvent.click(result.getByText('Bulk actions')); + }); + + await waitForEuiPopoverOpen(); + + act(() => { + userEvent.click(result.getByTestId('cases-bulk-action-delete'), undefined, { + skipPointerEventsCheck: true, + }); + }); + + await waitFor(() => { + expect(result.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(result.getByTestId('confirmModalConfirmButton')); + }); + + await waitFor(() => { + expect(deleteCasesSpy).toHaveBeenCalledWith( + [ + 'basic-case-id', + '1', + '2', + '3', + '4', + 'case-with-alerts-id', + 'case-with-alerts-syncoff-id', + 'case-with-registered-attachment', + ], + expect.anything() + ); + }); + }); + + it('should disable the checkboxes when the user has read only permissions', async () => { + appMockRenderer = createAppMockRenderer({ permissions: readCasesPermissions() }); + const res = appMockRenderer.render(); + + expect(res.getByTestId('checkboxSelectAll')).toBeDisabled(); + + await waitFor(() => { + for (const theCase of defaultGetCases.data.cases) { + expect(res.getByTestId(`checkboxSelectRow-${theCase.id}`)).toBeDisabled(); + } + }); + }); + }); + + describe('Row actions', () => { + const statusTests = [ + [CaseStatuses.open], + [CaseStatuses['in-progress']], + [CaseStatuses.closed], + ]; + + it('should render row actions', async () => { + const res = appMockRenderer.render(); + + await waitFor(() => { + for (const theCase of defaultGetCases.data.cases) { + expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeInTheDocument(); + } + }); + }); + + it.each(statusTests)('update the status of a case: %s', async (status) => { + const res = appMockRenderer.render(); + const openCase = useGetCasesMockState.data.cases[0]; + const inProgressCase = useGetCasesMockState.data.cases[1]; + const theCase = status === CaseStatuses.open ? inProgressCase : openCase; + + await waitFor(() => { + expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${theCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId(`case-action-status-panel-${theCase.id}`)).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId(`case-action-status-panel-${theCase.id}`), undefined, { + skipPointerEventsCheck: true, + }); + }); + + await waitFor(() => { + expect(res.getByTestId(`cases-bulk-action-status-${status}`)).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId(`cases-bulk-action-status-${status}`)); + }); + + await waitFor(() => { + expect(updateCasesSpy).toHaveBeenCalledWith( + [{ id: theCase.id, status, version: theCase.version }], + expect.anything() + ); + }); + }); + + it('should delete a case', async () => { + const res = appMockRenderer.render(); + const theCase = defaultGetCases.data.cases[0]; + + await waitFor(() => { + expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${theCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-delete'), undefined, { + skipPointerEventsCheck: true, + }); + }); + + await waitFor(() => { + expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('confirmModalConfirmButton')); + }); + + await waitFor(() => { + expect(deleteCasesSpy).toHaveBeenCalledWith(['basic-case-id'], expect.anything()); + }); + }); + + it('should disable row actions when bulk selecting all cases', async () => { + const res = appMockRenderer.render(); + + act(() => { + userEvent.click(res.getByTestId('checkboxSelectAll')); + }); + + await waitFor(() => { + for (const theCase of defaultGetCases.data.cases) { + expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeDisabled(); + } + }); + }); + + it('should disable row actions when selecting a case', async () => { + const res = appMockRenderer.render(); + const caseToSelect = defaultGetCases.data.cases[0]; + + act(() => { + userEvent.click(res.getByTestId(`checkboxSelectRow-${caseToSelect.id}`)); + }); + + await waitFor(() => { + for (const theCase of defaultGetCases.data.cases) { + expect(res.getByTestId(`case-action-popover-button-${theCase.id}`)).toBeDisabled(); + } + }); + }); + }); + }); }); describe('Assignees', () => { diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx index c7b2d4895f94a..0d2cff95c4919 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx @@ -21,7 +21,7 @@ import { import { CaseStatuses, caseStatuses } from '../../../common/api'; import { useAvailableCasesOwners } from '../app/use_available_owners'; -import { useCasesColumns } from './columns'; +import { useCasesColumns } from './use_cases_columns'; import { CasesTableFilters } from './table_filters'; import { EuiBasicTableOnChange } from './types'; @@ -37,7 +37,7 @@ import { } from '../../containers/use_get_cases'; import { useBulkGetUserProfiles } from '../../containers/user_profiles/use_bulk_get_user_profiles'; import { useGetCurrentUserProfile } from '../../containers/user_profiles/use_get_current_user_profile'; -import { getAllPermissionsExceptFrom } from '../../utils/permissions'; +import { getAllPermissionsExceptFrom, isReadOnlyPermissions } from '../../utils/permissions'; import { useIsLoadingCases } from './use_is_loading_cases'; const ProgressLoader = styled(EuiProgress)` @@ -196,13 +196,7 @@ export const AllCasesList = React.memo( [deselectCases, hasOwner, availableSolutions, owner] ); - /** - * At the time of changing this from all to delete the only bulk action we have is to delete. When we add more - * actions we'll need to revisit this to allow more granular checks around the bulk actions. - */ - const showActions = permissions.delete && !isSelectorView; - - const columns = useCasesColumns({ + const { columns } = useCasesColumns({ filterStatus: filterOptions.status ?? StatusAll, userProfiles: userProfiles ?? new Map(), currentUserProfile, @@ -210,6 +204,7 @@ export const AllCasesList = React.memo( connectors, onRowClick, showSolutionColumn: !hasOwner && availableSolutions.length > 1, + disableActions: selectedCases.length > 0, }); const pagination = useMemo( @@ -226,8 +221,9 @@ export const AllCasesList = React.memo( () => ({ onSelectionChange: setSelectedCases, initialSelected: selectedCases, + selectable: () => !isReadOnlyPermissions(permissions), }), - [selectedCases, setSelectedCases] + [permissions, selectedCases] ); const isDataEmpty = useMemo(() => data.total === 0, [data]); @@ -272,7 +268,6 @@ export const AllCasesList = React.memo( ( pagination={pagination} selectedCases={selectedCases} selection={euiBasicTableSelectionProps} - showActions={showActions} sorting={sorting} tableRef={tableRef} tableRowProps={tableRowProps} diff --git a/x-pack/plugins/cases/public/components/all_cases/columns.test.tsx b/x-pack/plugins/cases/public/components/all_cases/columns.test.tsx deleted file mode 100644 index 7dec0d7937913..0000000000000 --- a/x-pack/plugins/cases/public/components/all_cases/columns.test.tsx +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mount } from 'enzyme'; - -import '../../common/mock/match_media'; -import { ExternalServiceColumn } from './columns'; -import { useGetCasesMockState } from '../../containers/mock'; -import { connectors } from '../configure_cases/__mock__'; -import { AppMockRenderer, createAppMockRenderer, TestProviders } from '../../common/mock'; - -describe('ExternalServiceColumn ', () => { - let appMockRender: AppMockRenderer; - - beforeEach(() => { - jest.clearAllMocks(); - appMockRender = createAppMockRenderer(); - }); - - it('Not pushed render', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="case-table-column-external-notPushed"]`).last().exists() - ).toBeTruthy(); - }); - - it('Up to date', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="case-table-column-external-upToDate"]`).last().exists() - ).toBeTruthy(); - }); - - it('Needs update', () => { - const wrapper = mount( - - - - ); - - expect( - wrapper.find(`[data-test-subj="case-table-column-external-requiresUpdate"]`).last().exists() - ).toBeTruthy(); - }); - - it('it does not throw when accessing the icon if the connector type is not registered', () => { - // If the component throws the test will fail - expect(() => - mount( - - - - ) - ).not.toThrowError(); - }); - - it('shows the connectors icon if the user has read access to actions', async () => { - const result = appMockRender.render( - - ); - - expect(result.getByTestId('cases-table-connector-icon')).toBeInTheDocument(); - }); - - it('hides the connectors icon if the user does not have read access to actions', async () => { - appMockRender.coreStart.application.capabilities = { - ...appMockRender.coreStart.application.capabilities, - actions: { save: false, show: false }, - }; - - const result = appMockRender.render( - - ); - - expect(result.queryByTestId('cases-table-connector-icon')).toBe(null); - }); -}); diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx index 98c89215aac21..e26831266d65f 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx @@ -6,13 +6,14 @@ */ import React from 'react'; -import { mount } from 'enzyme'; import { AllCasesSelectorModal } from '.'; -import { TestProviders } from '../../../common/mock'; -import { AllCasesList } from '../all_cases_list'; +import { AppMockRenderer, createAppMockRenderer } from '../../../common/mock'; +import userEvent from '@testing-library/user-event'; +import { act, waitFor } from '@testing-library/react'; -jest.mock('../all_cases_list', () => ({ AllCasesList: jest.fn().mockReturnValue(<>) })); +jest.mock('../../../containers/api'); +jest.mock('../../../containers/user_profiles/api'); const onRowClick = jest.fn(); const defaultProps = { @@ -20,48 +21,73 @@ const defaultProps = { }; describe('AllCasesSelectorModal', () => { + let appMockRenderer: AppMockRenderer; + beforeEach(() => { jest.clearAllMocks(); + appMockRenderer = createAppMockRenderer(); }); it('renders', () => { - const wrapper = mount( - - - - ); + const res = appMockRenderer.render(); + + expect(res.getByTestId('all-cases-modal')).toBeInTheDocument(); + }); + + it('Closing modal when pressing the x icon', () => { + const res = appMockRenderer.render(); + + act(() => { + userEvent.click(res.getByLabelText('Closes this modal window')); + }); + + expect(res.queryByTestId('all-cases-modal')).toBeFalsy(); + }); + + it('Closing modal when pressing the cancel button', () => { + const res = appMockRenderer.render(); - expect(wrapper.find(`[data-test-subj='all-cases-modal']`).exists()).toBeTruthy(); + act(() => { + userEvent.click(res.getByTestId('all-cases-modal-cancel-button')); + }); + + expect(res.queryByTestId('all-cases-modal')).toBeFalsy(); + }); + + it('should not show bulk actions and row actions on the modal', async () => { + const res = appMockRenderer.render(); + await waitFor(() => { + expect(res.getByTestId('cases-table')).toBeInTheDocument(); + }); + + expect(res.queryByTestId('case-table-bulk-actions-link-icon')).toBeFalsy(); + expect(res.queryByText('Actions')).toBeFalsy(); }); - it('Closing modal calls onCloseCaseModal', () => { - const wrapper = mount( - - - - ); + it('should show the select button', async () => { + const res = appMockRenderer.render(); + await waitFor(() => { + expect(res.getByTestId('cases-table')).toBeInTheDocument(); + }); - wrapper.find('.euiModal__closeIcon').first().simulate('click'); - expect(wrapper.find(`[data-test-subj='all-cases-modal']`).exists()).toBeFalsy(); + expect(res.getAllByTestId(/cases-table-row-select/).length).toBeGreaterThan(0); }); - it('pass the correct props to getAllCases method', () => { - const fullProps = { - ...defaultProps, - hiddenStatuses: [], - }; - - mount( - - - - ); - - expect((AllCasesList as unknown as jest.Mock).mock.calls[0][0]).toEqual( - expect.objectContaining({ - hiddenStatuses: fullProps.hiddenStatuses, - isSelectorView: true, - }) - ); + it('should hide the metrics', async () => { + const res = appMockRenderer.render(); + await waitFor(() => { + expect(res.getByTestId('cases-table')).toBeInTheDocument(); + }); + + expect(res.queryByTestId('cases-metrics-stats')).toBeFalsy(); + }); + + it('should show the create case button', async () => { + const res = appMockRenderer.render(); + await waitFor(() => { + expect(res.getByTestId('cases-table')).toBeInTheDocument(); + }); + + expect(res.getByTestId('cases-table-add-case-filter-bar')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx index fccdf76abd2c4..f5007fcd5a092 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx @@ -68,7 +68,11 @@ export const AllCasesSelectorModal = React.memo( /> - + {i18n.CANCEL} diff --git a/x-pack/plugins/cases/public/components/all_cases/table.tsx b/x-pack/plugins/cases/public/components/all_cases/table.tsx index 208c26e47648c..1f7382351e802 100644 --- a/x-pack/plugins/cases/public/components/all_cases/table.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/table.tsx @@ -19,7 +19,7 @@ import styled from 'styled-components'; import { CasesTableUtilityBar } from './utility_bar'; import { LinkButton } from '../links'; -import { Cases, Case, FilterOptions } from '../../../common/ui/types'; +import { Cases, Case } from '../../../common/ui/types'; import * as i18n from './translations'; import { useCreateCaseNavigation } from '../../common/navigation'; import { useCasesContext } from '../cases_context/use_cases_context'; @@ -27,7 +27,6 @@ import { useCasesContext } from '../cases_context/use_cases_context'; interface CasesTableProps { columns: EuiBasicTableProps['columns']; data: Cases; - filterOptions: FilterOptions; goToCreateCase?: () => void; isCasesLoading: boolean; isCommentUpdating: boolean; @@ -37,7 +36,6 @@ interface CasesTableProps { pagination: Pagination; selectedCases: Case[]; selection: EuiTableSelectionType; - showActions: boolean; sorting: EuiBasicTableProps['sorting']; tableRef: MutableRefObject; tableRowProps: EuiBasicTableProps['rowProps']; @@ -51,7 +49,6 @@ const Div = styled.div` export const CasesTable: FunctionComponent = ({ columns, data, - filterOptions, goToCreateCase, isCasesLoading, isCommentUpdating, @@ -61,7 +58,6 @@ export const CasesTable: FunctionComponent = ({ pagination, selectedCases, selection, - showActions, sorting, tableRef, tableRowProps, @@ -86,11 +82,10 @@ export const CasesTable: FunctionComponent = ({ ) : ( -
+ <> @@ -98,7 +93,7 @@ export const CasesTable: FunctionComponent = ({ className={classnames({ isSelectorView })} columns={columns} data-test-subj="cases-table" - isSelectable={showActions} + isSelectable={!isSelectorView} itemId="id" items={data.cases} loading={isCommentUpdating} @@ -128,10 +123,11 @@ export const CasesTable: FunctionComponent = ({ pagination={pagination} ref={tableRef} rowProps={tableRowProps} - selection={showActions ? selection : undefined} + selection={!isSelectorView ? selection : undefined} sorting={sorting} + hasActions={false} /> -
+ ); }; CasesTable.displayName = 'CasesTable'; diff --git a/x-pack/plugins/cases/public/components/all_cases/translations.ts b/x-pack/plugins/cases/public/components/all_cases/translations.ts index 96a683aee5077..332c0d493101b 100644 --- a/x-pack/plugins/cases/public/components/all_cases/translations.ts +++ b/x-pack/plugins/cases/public/components/all_cases/translations.ts @@ -130,40 +130,3 @@ export const TOTAL_ASSIGNEES_FILTERED = (total: number) => defaultMessage: '{total, plural, one {# assignee} other {# assignees}} filtered', values: { total }, }); - -export const CLOSED_CASES = ({ - totalCases, - caseTitle, -}: { - totalCases: number; - caseTitle?: string; -}) => - i18n.translate('xpack.cases.containers.closedCases', { - values: { caseTitle, totalCases }, - defaultMessage: 'Closed {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', - }); - -export const REOPENED_CASES = ({ - totalCases, - caseTitle, -}: { - totalCases: number; - caseTitle?: string; -}) => - i18n.translate('xpack.cases.containers.reopenedCases', { - values: { caseTitle, totalCases }, - defaultMessage: 'Opened {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}}', - }); - -export const MARK_IN_PROGRESS_CASES = ({ - totalCases, - caseTitle, -}: { - totalCases: number; - caseTitle?: string; -}) => - i18n.translate('xpack.cases.containers.markInProgressCases', { - values: { caseTitle, totalCases }, - defaultMessage: - 'Marked {totalCases, plural, =1 {"{caseTitle}"} other {{totalCases} cases}} as in progress', - }); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx new file mode 100644 index 0000000000000..0d8bfab2a7a33 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/use_actions.test.tsx @@ -0,0 +1,275 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import userEvent from '@testing-library/user-event'; +import { waitFor } from '@testing-library/dom'; +import { act, renderHook } from '@testing-library/react-hooks'; + +import { useActions } from './use_actions'; +import { basicCase } from '../../containers/mock'; +import * as api from '../../containers/api'; +import { + AppMockRenderer, + createAppMockRenderer, + noDeleteCasesPermissions, + onlyDeleteCasesPermission, + allCasesPermissions, + readCasesPermissions, +} from '../../common/mock'; + +jest.mock('../../containers/api'); + +describe('useActions', () => { + let appMockRender: AppMockRenderer; + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + it('renders column actions', async () => { + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "actions": Object { + "align": "right", + "name": "Actions", + "render": [Function], + }, + } + `); + }); + + it('renders the popover', async () => { + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + expect(res.getByTestId(`case-action-popover-${basicCase.id}`)).toBeInTheDocument(); + }); + + it('open the action popover', async () => { + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByText('Actions')).toBeInTheDocument(); + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + }); + }); + + it('change the status of the case', async () => { + const updateCasesSpy = jest.spyOn(api, 'updateCases'); + + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId(`case-action-status-panel-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId('cases-bulk-action-status-open')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-status-in-progress')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-status-closed')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-status-in-progress')); + }); + + await waitFor(() => { + expect(updateCasesSpy).toHaveBeenCalled(); + }); + }); + + describe('Modals', () => { + it('delete a case', async () => { + const deleteSpy = jest.spyOn(api, 'deleteCases'); + + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-delete'), undefined, { + skipPointerEventsCheck: true, + }); + }); + + await waitFor(() => { + expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('confirmModalConfirmButton')); + }); + + await waitFor(() => { + expect(deleteSpy).toHaveBeenCalled(); + }); + }); + + it('closes the modal', async () => { + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-delete'), undefined, { + skipPointerEventsCheck: true, + }); + }); + + await waitFor(() => { + expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('confirmModalCancelButton'), undefined, { + skipPointerEventsCheck: true, + }); + }); + + expect(res.queryByTestId('confirm-delete-case-modal')).toBeFalsy(); + }); + }); + + describe('Permissions', () => { + it('shows the correct actions with all permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: allCasesPermissions() }); + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.getByTestId(`actions-separator-${basicCase.id}`)).toBeInTheDocument(); + }); + }); + + it('shows the correct actions with no delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: noDeleteCasesPermissions() }); + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.queryByTestId('cases-bulk-action-delete')).toBeFalsy(); + expect(res.queryByTestId(`actions-separator-${basicCase.id}`)).toBeFalsy(); + }); + }); + + it('shows the correct actions with only delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + act(() => { + userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + }); + + await waitFor(() => { + expect(res.queryByTestId(`case-action-status-panel-${basicCase.id}`)).toBeFalsy(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.queryByTestId(`actions-separator-${basicCase.id}`)).toBeFalsy(); + }); + }); + + it('returns null if the user does not have update or delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: readCasesPermissions() }); + const { result } = renderHook(() => useActions({ disableActions: false }), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current.actions).toBe(null); + }); + + it('disables the action correctly', async () => { + appMockRender = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const { result } = renderHook(() => useActions({ disableActions: true }), { + wrapper: appMockRender.AppWrapper, + }); + + const comp = result.current.actions!.render(basicCase) as React.ReactElement; + const res = appMockRender.render(comp); + + await waitFor(() => { + expect(res.getByTestId(`case-action-popover-button-${basicCase.id}`)).toBeDisabled(); + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx b/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx new file mode 100644 index 0000000000000..c397047ee98bf --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/use_actions.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo, useState } from 'react'; +import { + EuiButtonIcon, + EuiContextMenu, + EuiContextMenuPanelDescriptor, + EuiContextMenuPanelItemDescriptor, + EuiPopover, + EuiTableComputedColumnType, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { Case } from '../../containers/types'; +import { useDeleteAction } from '../actions/delete/use_delete_action'; +import { ConfirmDeleteCaseModal } from '../confirm_delete_case'; +import { useStatusAction } from '../actions/status/use_status_action'; +import { useRefreshCases } from './use_on_refresh_cases'; +import * as i18n from './translations'; +import { statuses } from '../status'; +import { useCasesContext } from '../cases_context/use_cases_context'; + +const ActionColumnComponent: React.FC<{ theCase: Case; disableActions: boolean }> = ({ + theCase, + disableActions, +}) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const tooglePopover = useCallback(() => setIsPopoverOpen(!isPopoverOpen), [isPopoverOpen]); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + const refreshCases = useRefreshCases(); + + const deleteAction = useDeleteAction({ + isDisabled: false, + onAction: closePopover, + onActionSuccess: refreshCases, + }); + + const statusAction = useStatusAction({ + isDisabled: false, + onAction: closePopover, + onActionSuccess: refreshCases, + selectedStatus: theCase.status, + }); + + const canDelete = deleteAction.canDelete; + const canUpdate = statusAction.canUpdateStatus; + + const panels = useMemo((): EuiContextMenuPanelDescriptor[] => { + const mainPanelItems: EuiContextMenuPanelItemDescriptor[] = []; + const panelsToBuild: EuiContextMenuPanelDescriptor[] = [ + { id: 0, items: mainPanelItems, title: i18n.ACTIONS }, + ]; + + if (canUpdate) { + mainPanelItems.push({ + name: ( + {statuses[theCase.status]?.label ?? '-'} }} + /> + ), + panel: 1, + disabled: !canUpdate, + key: `case-action-status-panel-${theCase.id}`, + 'data-test-subj': `case-action-status-panel-${theCase.id}`, + }); + } + + /** + * A separator is added if a) there is one item above + * and b) there is an item below. For this to happen the + * user has to have delete and update permissions + */ + if (canUpdate && canDelete) { + mainPanelItems.push({ + isSeparator: true, + key: `actions-separator-${theCase.id}`, + 'data-test-subj': `actions-separator-${theCase.id}`, + }); + } + + if (canDelete) { + mainPanelItems.push(deleteAction.getAction([theCase])); + } + + if (canUpdate) { + panelsToBuild.push({ + id: 1, + title: i18n.STATUS, + items: statusAction.getActions([theCase]), + }); + } + + return panelsToBuild; + }, [canDelete, canUpdate, deleteAction, statusAction, theCase]); + + return ( + <> + + } + isOpen={isPopoverOpen} + closePopover={closePopover} + panelPaddingSize="none" + anchorPosition="downLeft" + > + + + {deleteAction.isModalVisible ? ( + + ) : null} + + ); +}; + +ActionColumnComponent.displayName = 'ActionColumnComponent'; + +const ActionColumn = React.memo(ActionColumnComponent); + +interface UseBulkActionsReturnValue { + actions: EuiTableComputedColumnType | null; +} + +interface UseBulkActionsProps { + disableActions: boolean; +} + +export const useActions = ({ disableActions }: UseBulkActionsProps): UseBulkActionsReturnValue => { + const { permissions } = useCasesContext(); + const shouldShowActions = permissions.update || permissions.delete; + + return { + actions: shouldShowActions + ? { + name: i18n.ACTIONS, + align: 'right', + render: (theCase: Case) => { + return ( + + ); + }, + } + : null, + }; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.test.tsx new file mode 100644 index 0000000000000..88d596af41fdf --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.test.tsx @@ -0,0 +1,334 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiContextMenu } from '@elastic/eui'; +import userEvent from '@testing-library/user-event'; +import { waitFor } from '@testing-library/react'; +import { act, renderHook } from '@testing-library/react-hooks'; + +import { + allCasesPermissions, + AppMockRenderer, + createAppMockRenderer, + noDeleteCasesPermissions, + onlyDeleteCasesPermission, +} from '../../common/mock'; +import { useBulkActions } from './use_bulk_actions'; +import * as api from '../../containers/api'; +import { basicCase } from '../../containers/mock'; + +jest.mock('../../containers/api'); + +describe('useBulkActions', () => { + let appMockRender: AppMockRenderer; + const onAction = jest.fn(); + const onActionSuccess = jest.fn(); + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + jest.clearAllMocks(); + }); + + describe('Panels', () => { + it('renders bulk actions', async () => { + const { result } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "modals": , + "panels": Array [ + Object { + "id": 0, + "items": Array [ + Object { + "data-test-subj": "case-bulk-action-status", + "disabled": false, + "key": "case-bulk-action-status", + "name": "Status", + "panel": 1, + }, + Object { + "data-test-subj": "bulk-actions-separator", + "isSeparator": true, + "key": "bulk-actions-separator", + }, + Object { + "data-test-subj": "cases-bulk-action-delete", + "disabled": false, + "icon": , + "key": "cases-bulk-action-delete", + "name": + Delete case + , + "onClick": [Function], + }, + ], + "title": "Actions", + }, + Object { + "id": 1, + "items": Array [ + Object { + "data-test-subj": "cases-bulk-action-status-open", + "disabled": true, + "icon": "empty", + "key": "cases-bulk-action-status-open", + "name": "Open", + "onClick": [Function], + }, + Object { + "data-test-subj": "cases-bulk-action-status-in-progress", + "disabled": false, + "icon": "empty", + "key": "cases-bulk-action-status-in-progress", + "name": "In progress", + "onClick": [Function], + }, + Object { + "data-test-subj": "cases-bulk-action-status-closed", + "disabled": false, + "icon": "empty", + "key": "cases-bulk-status-action", + "name": "Closed", + "onClick": [Function], + }, + ], + "title": "Status", + }, + ], + } + `); + }); + + it('change the status of cases', async () => { + const updateCasesSpy = jest.spyOn(api, 'updateCases'); + + const { result, waitFor: waitForHook } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const modals = result.current.modals; + const panels = result.current.panels; + + const res = appMockRender.render( + <> + + {modals} + + ); + + act(() => { + userEvent.click(res.getByTestId('case-bulk-action-status')); + }); + + await waitFor(() => { + expect(res.getByTestId('cases-bulk-action-status-open')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-status-in-progress')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-status-closed')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-status-in-progress')); + }); + + await waitForHook(() => { + expect(updateCasesSpy).toHaveBeenCalled(); + }); + }); + + describe('Modals', () => { + it('delete a case', async () => { + const deleteSpy = jest.spyOn(api, 'deleteCases'); + + const { result, waitFor: waitForHook } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + let modals = result.current.modals; + const panels = result.current.panels; + + const res = appMockRender.render( + <> + + {modals} + + ); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-delete')); + }); + + modals = result.current.modals; + res.rerender( + <> + + {modals} + + ); + + await waitFor(() => { + expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('confirmModalConfirmButton')); + }); + + await waitForHook(() => { + expect(deleteSpy).toHaveBeenCalled(); + }); + }); + + it('closes the modal', async () => { + const { result } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + let modals = result.current.modals; + const panels = result.current.panels; + + const res = appMockRender.render( + <> + + {modals} + + ); + + act(() => { + userEvent.click(res.getByTestId('cases-bulk-action-delete')); + }); + + modals = result.current.modals; + res.rerender( + <> + + {modals} + + ); + + await waitFor(() => { + expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); + }); + + act(() => { + userEvent.click(res.getByTestId('confirmModalCancelButton')); + }); + + modals = result.current.modals; + res.rerender( + <> + + {modals} + + ); + + expect(res.queryByTestId('confirm-delete-case-modal')).toBeFalsy(); + }); + }); + }); + + describe('Permissions', () => { + it('shows the correct actions with all permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: allCasesPermissions() }); + const { result, waitFor: waitForHook } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const modals = result.current.modals; + const panels = result.current.panels; + + const res = appMockRender.render( + <> + + {modals} + + ); + + await waitForHook(() => { + expect(res.getByTestId('case-bulk-action-status')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.getByTestId('bulk-actions-separator')).toBeInTheDocument(); + }); + }); + + it('shows the correct actions with no delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: noDeleteCasesPermissions() }); + const { result, waitFor: waitForHook } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const modals = result.current.modals; + const panels = result.current.panels; + + const res = appMockRender.render( + <> + + {modals} + + ); + + await waitForHook(() => { + expect(res.getByTestId('case-bulk-action-status')).toBeInTheDocument(); + expect(res.queryByTestId('cases-bulk-action-delete')).toBeFalsy(); + expect(res.queryByTestId('bulk-actions-separator')).toBeFalsy(); + }); + }); + + it('shows the correct actions with only delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const { result, waitFor: waitForHook } = renderHook( + () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + const modals = result.current.modals; + const panels = result.current.panels; + + const res = appMockRender.render( + <> + + {modals} + + ); + + await waitForHook(() => { + expect(res.queryByTestId('case-bulk-action-status')).toBeFalsy(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.queryByTestId('bulk-actions-separator')).toBeFalsy(); + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx b/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx new file mode 100644 index 0000000000000..bef085ce6d8a0 --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/use_bulk_actions.tsx @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiContextMenuPanelDescriptor, EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; +import React, { useMemo } from 'react'; + +import { Case } from '../../containers/types'; +import { useDeleteAction } from '../actions/delete/use_delete_action'; +import { useStatusAction } from '../actions/status/use_status_action'; +import { ConfirmDeleteCaseModal } from '../confirm_delete_case'; +import * as i18n from './translations'; + +interface UseBulkActionsProps { + selectedCases: Case[]; + onAction: () => void; + onActionSuccess: () => void; +} + +interface UseBulkActionsReturnValue { + panels: EuiContextMenuPanelDescriptor[]; + modals: JSX.Element; +} + +export const useBulkActions = ({ + selectedCases, + onAction, + onActionSuccess, +}: UseBulkActionsProps): UseBulkActionsReturnValue => { + const isDisabled = selectedCases.length === 0; + + const deleteAction = useDeleteAction({ + isDisabled, + onAction, + onActionSuccess, + }); + + const statusAction = useStatusAction({ + isDisabled, + onAction, + onActionSuccess, + }); + + const canDelete = deleteAction.canDelete; + const canUpdate = statusAction.canUpdateStatus; + + const panels = useMemo((): EuiContextMenuPanelDescriptor[] => { + const mainPanelItems: EuiContextMenuPanelItemDescriptor[] = []; + const panelsToBuild: EuiContextMenuPanelDescriptor[] = [ + { id: 0, items: mainPanelItems, title: i18n.ACTIONS }, + ]; + + if (canUpdate) { + mainPanelItems.push({ + name: i18n.STATUS, + panel: 1, + disabled: isDisabled, + 'data-test-subj': 'case-bulk-action-status', + key: 'case-bulk-action-status', + }); + } + + /** + * A separator is added if a) there is one item above + * and b) there is an item below. For this to happen the + * user has to have delete and update permissions + */ + if (canUpdate && canDelete) { + mainPanelItems.push({ + isSeparator: true as const, + key: 'bulk-actions-separator', + 'data-test-subj': 'bulk-actions-separator', + }); + } + + if (canDelete) { + mainPanelItems.push(deleteAction.getAction(selectedCases)); + } + + if (canUpdate) { + panelsToBuild.push({ + id: 1, + title: i18n.STATUS, + items: statusAction.getActions(selectedCases), + }); + } + + return panelsToBuild; + }, [canDelete, canUpdate, deleteAction, isDisabled, selectedCases, statusAction]); + + return { + modals: ( + <> + {deleteAction.isModalVisible ? ( + + ) : null} + + ), + panels, + }; +}; diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx new file mode 100644 index 0000000000000..85caa0b0348dc --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.test.tsx @@ -0,0 +1,679 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { mount } from 'enzyme'; +import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; + +import '../../common/mock/match_media'; +import { ExternalServiceColumn, GetCasesColumn, useCasesColumns } from './use_cases_columns'; +import { useGetCasesMockState } from '../../containers/mock'; +import { connectors } from '../configure_cases/__mock__'; +import { + AppMockRenderer, + createAppMockRenderer, + readCasesPermissions, + TestProviders, +} from '../../common/mock'; +import { renderHook } from '@testing-library/react-hooks'; +import { CaseStatuses } from '../../../common'; +import { userProfilesMap, userProfiles } from '../../containers/user_profiles/api.mock'; + +describe('useCasesColumns ', () => { + let appMockRender: AppMockRenderer; + const useCasesColumnsProps: GetCasesColumn = { + filterStatus: CaseStatuses.open, + userProfiles: userProfilesMap, + currentUserProfile: userProfiles[0], + isSelectorView: false, + showSolutionColumn: true, + }; + + beforeEach(() => { + jest.clearAllMocks(); + appMockRender = createAppMockRenderer(); + }); + + it('return all columns correctly', async () => { + const license = licensingMock.createLicense({ + license: { type: 'platinum' }, + }); + + appMockRender = createAppMockRenderer({ license }); + + const { result } = renderHook(() => useCasesColumns(useCasesColumnsProps), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "assignees", + "name": "Assignees", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "name": "Actions", + "render": [Function], + }, + ], + } + `); + }); + + it('does not render the solution columns', async () => { + const license = licensingMock.createLicense({ + license: { type: 'platinum' }, + }); + + appMockRender = createAppMockRenderer({ license }); + + const { result } = renderHook( + () => useCasesColumns({ ...useCasesColumnsProps, showSolutionColumn: false }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "assignees", + "name": "Assignees", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "name": "Actions", + "render": [Function], + }, + ], + } + `); + }); + + it('does not return the alerts column', async () => { + const license = licensingMock.createLicense({ + license: { type: 'platinum' }, + }); + + appMockRender = createAppMockRenderer({ license, features: { alerts: { enabled: false } } }); + + const { result } = renderHook(() => useCasesColumns(useCasesColumnsProps), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "assignees", + "name": "Assignees", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "name": "Actions", + "render": [Function], + }, + ], + } + `); + }); + + it('does not return the assignees column', async () => { + const { result } = renderHook(() => useCasesColumns(useCasesColumnsProps), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "name": "Actions", + "render": [Function], + }, + ], + } + `); + }); + + it('shows the closedAt column if the filterStatus=closed', async () => { + appMockRender = createAppMockRenderer(); + + const { result } = renderHook( + () => useCasesColumns({ ...useCasesColumnsProps, filterStatus: CaseStatuses.closed }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "closedAt", + "name": "Closed on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "name": "Actions", + "render": [Function], + }, + ], + } + `); + }); + + it('shows the select button if isSelectorView=true', async () => { + const { result } = renderHook( + () => useCasesColumns({ ...useCasesColumnsProps, isSelectorView: true }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "render": [Function], + }, + ], + } + `); + }); + + it('does not shows the actions if isSelectorView=true', async () => { + const { result } = renderHook( + () => useCasesColumns({ ...useCasesColumnsProps, isSelectorView: true }), + { + wrapper: appMockRender.AppWrapper, + } + ); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + Object { + "align": "right", + "render": [Function], + }, + ], + } + `); + }); + + it('does not shows the actions if the user does not have the right permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: readCasesPermissions() }); + + const { result } = renderHook(() => useCasesColumns(useCasesColumnsProps), { + wrapper: appMockRender.AppWrapper, + }); + + expect(result.current).toMatchInlineSnapshot(` + Object { + "columns": Array [ + Object { + "name": "Name", + "render": [Function], + }, + Object { + "field": "tags", + "name": "Tags", + "render": [Function], + "truncateText": true, + }, + Object { + "align": "right", + "field": "totalAlerts", + "name": "Alerts", + "render": [Function], + }, + Object { + "align": "right", + "field": "owner", + "name": "Solution", + "render": [Function], + }, + Object { + "align": "right", + "field": "totalComment", + "name": "Comments", + "render": [Function], + }, + Object { + "field": "createdAt", + "name": "Created on", + "render": [Function], + "sortable": true, + }, + Object { + "name": "External Incident", + "render": [Function], + }, + Object { + "name": "Status", + "render": [Function], + }, + Object { + "name": "Severity", + "render": [Function], + }, + ], + } + `); + }); + + describe('ExternalServiceColumn ', () => { + it('Not pushed render', () => { + const wrapper = mount( + + + + ); + + expect( + wrapper.find(`[data-test-subj="case-table-column-external-notPushed"]`).last().exists() + ).toBeTruthy(); + }); + + it('Up to date', () => { + const wrapper = mount( + + + + ); + + expect( + wrapper.find(`[data-test-subj="case-table-column-external-upToDate"]`).last().exists() + ).toBeTruthy(); + }); + + it('Needs update', () => { + const wrapper = mount( + + + + ); + + expect( + wrapper.find(`[data-test-subj="case-table-column-external-requiresUpdate"]`).last().exists() + ).toBeTruthy(); + }); + + it('it does not throw when accessing the icon if the connector type is not registered', () => { + // If the component throws the test will fail + expect(() => + mount( + + + + ) + ).not.toThrowError(); + }); + + it('shows the connectors icon if the user has read access to actions', async () => { + const result = appMockRender.render( + + ); + + expect(result.getByTestId('cases-table-connector-icon')).toBeInTheDocument(); + }); + + it('hides the connectors icon if the user does not have read access to actions', async () => { + appMockRender.coreStart.application.capabilities = { + ...appMockRender.coreStart.application.capabilities, + actions: { save: false, show: false }, + }; + + const result = appMockRender.render( + + ); + + expect(result.queryByTestId('cases-table-connector-icon')).toBe(null); + }); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/columns.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx similarity index 51% rename from x-pack/plugins/cases/public/components/all_cases/columns.tsx rename to x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx index 948abdbbcd2f3..b996e219c17e7 100644 --- a/x-pack/plugins/cases/public/components/all_cases/columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback } from 'react'; import { EuiBadgeGroup, EuiBadge, @@ -24,7 +24,7 @@ import { RIGHT_ALIGNMENT } from '@elastic/eui/lib/services'; import styled from 'styled-components'; import { UserProfileWithAvatar } from '@kbn/user-profile-components'; -import { Case, UpdateByKey } from '../../../common/ui/types'; +import { Case } from '../../../common/ui/types'; import { CaseStatuses, ActionConnector, CaseSeverity } from '../../../common/api'; import { OWNER_INFO } from '../../../common/constants'; import { getEmptyTagValue } from '../empty_value'; @@ -32,26 +32,21 @@ import { FormattedRelativePreferenceDate } from '../formatted_date'; import { CaseDetailsLink } from '../links'; import * as i18n from './translations'; import { ALERTS } from '../../common/translations'; -import { getActions } from './actions'; -import { useDeleteCases } from '../../containers/use_delete_cases'; -import { ConfirmDeleteCaseModal } from '../confirm_delete_case'; +import { useActions } from './use_actions'; import { useApplicationCapabilities, useKibana } from '../../common/lib/kibana'; -import { StatusContextMenu } from '../case_action_bar/status_context_menu'; import { TruncatedText } from '../truncated_text'; import { getConnectorIcon } from '../utils'; import type { CasesOwners } from '../../client/helpers/can_use_cases'; import { severities } from '../severity/config'; -import { useUpdateCase } from '../../containers/use_update_case'; -import { useCasesContext } from '../cases_context/use_cases_context'; import { UserToolTip } from '../user_profiles/user_tooltip'; import { useAssignees } from '../../containers/user_profiles/use_assignees'; import { getUsernameDataTestSubj } from '../user_profiles/data_test_subject'; import { CurrentUserProfile } from '../types'; import { SmallUserAvatar } from '../user_profiles/small_user_avatar'; import { useCasesFeatures } from '../../common/use_cases_features'; -import { useRefreshCases } from './use_on_refresh_cases'; +import { Status } from '../status'; -export type CasesColumns = +type CasesColumns = | EuiTableActionsColumnType | EuiTableComputedColumnType | EuiTableFieldDataColumnType; @@ -107,9 +102,14 @@ export interface GetCasesColumn { isSelectorView: boolean; connectors?: ActionConnector[]; onRowClick?: (theCase: Case) => void; - showSolutionColumn?: boolean; + disableActions?: boolean; +} + +export interface UseCasesColumnsReturnValue { + columns: CasesColumns[]; } + export const useCasesColumns = ({ filterStatus, userProfiles, @@ -118,57 +118,10 @@ export const useCasesColumns = ({ connectors = [], onRowClick, showSolutionColumn, -}: GetCasesColumn): CasesColumns[] => { - const [isModalVisible, setIsModalVisible] = useState(false); - const { mutate: deleteCases } = useDeleteCases(); - const refreshCases = useRefreshCases(); + disableActions = false, +}: GetCasesColumn): UseCasesColumnsReturnValue => { const { isAlertsEnabled, caseAssignmentAuthorized } = useCasesFeatures(); - const { permissions } = useCasesContext(); - const [caseToBeDeleted, setCaseToBeDeleted] = useState(); - const { updateCaseProperty, isLoading: isLoadingUpdateCase } = useUpdateCase(); - - const closeModal = useCallback(() => setIsModalVisible(false), []); - const openModal = useCallback(() => setIsModalVisible(true), []); - - const onDeleteAction = useCallback( - (theCase: Case) => { - openModal(); - setCaseToBeDeleted(theCase.id); - }, - [openModal] - ); - - const onConfirmDeletion = useCallback(() => { - closeModal(); - if (caseToBeDeleted) { - deleteCases({ - caseIds: [caseToBeDeleted], - successToasterTitle: i18n.DELETED_CASES(1), - }); - } - }, [caseToBeDeleted, closeModal, deleteCases]); - - const handleDispatchUpdate = useCallback( - ({ updateKey, updateValue, caseData }: UpdateByKey) => { - updateCaseProperty({ - updateKey, - updateValue, - caseData, - onSuccess: () => { - refreshCases(); - }, - }); - }, - [refreshCases, updateCaseProperty] - ); - - const actions = useMemo( - () => - getActions({ - deleteCaseOnClick: onDeleteAction, - }), - [onDeleteAction] - ); + const { actions } = useActions({ disableActions }); const assignCaseAction = useCallback( async (theCase: Case) => { @@ -179,7 +132,7 @@ export const useCasesColumns = ({ [onRowClick] ); - return [ + const columns: CasesColumns[] = [ { name: i18n.NAME, render: (theCase: Case) => { @@ -205,129 +158,134 @@ export const useCasesColumns = ({ return getEmptyTagValue(); }, }, - ...(caseAssignmentAuthorized - ? [ - { - field: 'assignees', - name: i18n.ASSIGNEES, - render: (assignees: Case['assignees']) => ( - - ), - }, - ] - : []), - { - field: 'tags', - name: i18n.TAGS, - render: (tags: Case['tags']) => { - if (tags != null && tags.length > 0) { - const badges = ( - - {tags.map((tag: string, i: number) => ( - - {tag} - - ))} - - ); + ]; + + if (caseAssignmentAuthorized) { + columns.push({ + field: 'assignees', + name: i18n.ASSIGNEES, + render: (assignees: Case['assignees']) => ( + + ), + }); + } + + columns.push({ + field: 'tags', + name: i18n.TAGS, + render: (tags: Case['tags']) => { + if (tags != null && tags.length > 0) { + const badges = ( + + {tags.map((tag: string, i: number) => ( + + {tag} + + ))} + + ); + + return ( + + {badges} + + ); + } + return getEmptyTagValue(); + }, + truncateText: true, + }); + + if (isAlertsEnabled) { + columns.push({ + align: RIGHT_ALIGNMENT, + field: 'totalAlerts', + name: ALERTS, + render: (totalAlerts: Case['totalAlerts']) => + totalAlerts != null + ? renderStringField(`${totalAlerts}`, `case-table-column-alertsCount`) + : getEmptyTagValue(), + }); + } + + if (showSolutionColumn) { + columns.push({ + align: RIGHT_ALIGNMENT, + field: 'owner', + name: i18n.SOLUTION, + render: (caseOwner: CasesOwners) => { + const ownerInfo = OWNER_INFO[caseOwner]; + return ownerInfo ? ( + + ) : ( + getEmptyTagValue() + ); + }, + }); + } + + columns.push({ + align: RIGHT_ALIGNMENT, + field: 'totalComment', + name: i18n.COMMENTS, + render: (totalComment: Case['totalComment']) => + totalComment != null + ? renderStringField(`${totalComment}`, `case-table-column-commentCount`) + : getEmptyTagValue(), + }); + if (filterStatus === CaseStatuses.closed) { + columns.push({ + field: 'closedAt', + name: i18n.CLOSED_ON, + sortable: true, + render: (closedAt: Case['closedAt']) => { + if (closedAt != null) { return ( - - {badges} - + + + ); } return getEmptyTagValue(); }, - truncateText: true, - }, - ...(isAlertsEnabled - ? [ - { - align: RIGHT_ALIGNMENT, - field: 'totalAlerts', - name: ALERTS, - render: (totalAlerts: Case['totalAlerts']) => - totalAlerts != null - ? renderStringField(`${totalAlerts}`, `case-table-column-alertsCount`) - : getEmptyTagValue(), - }, - ] - : []), - ...(showSolutionColumn - ? [ - { - align: RIGHT_ALIGNMENT, - field: 'owner', - name: i18n.SOLUTION, - render: (caseOwner: CasesOwners) => { - const ownerInfo = OWNER_INFO[caseOwner]; - return ownerInfo ? ( - - ) : ( - getEmptyTagValue() - ); - }, - }, - ] - : []), - { - align: RIGHT_ALIGNMENT, - field: 'totalComment', - name: i18n.COMMENTS, - render: (totalComment: Case['totalComment']) => - totalComment != null - ? renderStringField(`${totalComment}`, `case-table-column-commentCount`) - : getEmptyTagValue(), - }, - filterStatus === CaseStatuses.closed - ? { - field: 'closedAt', - name: i18n.CLOSED_ON, - sortable: true, - render: (closedAt: Case['closedAt']) => { - if (closedAt != null) { - return ( - - - - ); - } - return getEmptyTagValue(); - }, + }); + } else { + columns.push({ + field: 'createdAt', + name: i18n.CREATED_ON, + sortable: true, + render: (createdAt: Case['createdAt']) => { + if (createdAt != null) { + return ( + + + + ); } - : { - field: 'createdAt', - name: i18n.CREATED_ON, - sortable: true, - render: (createdAt: Case['createdAt']) => { - if (createdAt != null) { - return ( - - - - ); - } - return getEmptyTagValue(); - }, - }, + return getEmptyTagValue(); + }, + }); + } + + columns.push( { name: i18n.EXTERNAL_INCIDENT, render: (theCase: Case) => { @@ -337,32 +295,16 @@ export const useCasesColumns = ({ return getEmptyTagValue(); }, }, - ...(!isSelectorView - ? [ - { - name: i18n.STATUS, - render: (theCase: Case) => { - if (theCase.status === null || theCase.status === undefined) { - return getEmptyTagValue(); - } - - return ( - - handleDispatchUpdate({ - updateKey: 'status', - updateValue: status, - caseData: theCase, - }) - } - /> - ); - }, - }, - ] - : []), + { + name: i18n.STATUS, + render: (theCase: Case) => { + if (theCase.status === null || theCase.status === undefined) { + return getEmptyTagValue(); + } + + return ; + }, + }, { name: i18n.SEVERITY, render: (theCase: Case) => { @@ -376,52 +318,37 @@ export const useCasesColumns = ({ } return getEmptyTagValue(); }, - }, + } + ); - ...(isSelectorView - ? [ - { - align: RIGHT_ALIGNMENT, - render: (theCase: Case) => { - if (theCase.id != null) { - return ( - { - assignCaseAction(theCase); - }} - size="s" - fill={true} - > - {i18n.SELECT} - - ); - } - return getEmptyTagValue(); - }, - }, - ] - : []), - ...(permissions.delete && !isSelectorView - ? [ - { - name: ( - <> - {i18n.ACTIONS} - {isModalVisible ? ( - - ) : null} - - ), - actions, - }, - ] - : []), - ]; + if (isSelectorView) { + columns.push({ + align: RIGHT_ALIGNMENT, + render: (theCase: Case) => { + if (theCase.id != null) { + return ( + { + assignCaseAction(theCase); + }} + size="s" + fill={true} + > + {i18n.SELECT} + + ); + } + return getEmptyTagValue(); + }, + }); + } + + if (!isSelectorView && actions) { + columns.push(actions); + } + + return { columns }; }; interface Props { diff --git a/x-pack/plugins/cases/public/components/all_cases/utility_bar.test.tsx b/x-pack/plugins/cases/public/components/all_cases/utility_bar.test.tsx new file mode 100644 index 0000000000000..3a8769460656d --- /dev/null +++ b/x-pack/plugins/cases/public/components/all_cases/utility_bar.test.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { + noCasesPermissions, + onlyDeleteCasesPermission, + AppMockRenderer, + createAppMockRenderer, + writeCasesPermissions, +} from '../../common/mock'; +import { casesQueriesKeys } from '../../containers/constants'; +import { basicCase } from '../../containers/mock'; +import { CasesTableUtilityBar } from './utility_bar'; + +describe('Severity form field', () => { + let appMockRender: AppMockRenderer; + const deselectCases = jest.fn(); + + const props = { + totalCases: 5, + selectedCases: [basicCase], + deselectCases, + }; + + beforeEach(() => { + appMockRender = createAppMockRenderer(); + }); + + it('renders', async () => { + const result = appMockRender.render(); + expect(result.getByText('Showing 5 cases')).toBeInTheDocument(); + expect(result.getByText('Selected 1 case')).toBeInTheDocument(); + expect(result.getByTestId('case-table-bulk-actions-link-icon')).toBeInTheDocument(); + expect(result.getByTestId('all-cases-refresh-link-icon')).toBeInTheDocument(); + }); + + it('opens the bulk actions correctly', async () => { + const result = appMockRender.render(); + + act(() => { + userEvent.click(result.getByTestId('case-table-bulk-actions-link-icon')); + }); + + await waitFor(() => { + expect(result.getByTestId('case-table-bulk-actions-context-menu')); + }); + }); + + it('closes the bulk actions correctly', async () => { + const result = appMockRender.render(); + + act(() => { + userEvent.click(result.getByTestId('case-table-bulk-actions-link-icon')); + }); + + await waitFor(() => { + expect(result.getByTestId('case-table-bulk-actions-context-menu')); + }); + + act(() => { + userEvent.click(result.getByTestId('case-table-bulk-actions-link-icon')); + }); + + await waitFor(() => { + expect(result.queryByTestId('case-table-bulk-actions-context-menu')).toBeFalsy(); + }); + }); + + it('refresh correctly', async () => { + const result = appMockRender.render(); + const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); + + act(() => { + userEvent.click(result.getByTestId('all-cases-refresh-link-icon')); + }); + + await waitFor(() => { + expect(deselectCases).toHaveBeenCalled(); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + }); + }); + + it('does not show the bulk actions without update & delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: noCasesPermissions() }); + const result = appMockRender.render(); + + expect(result.queryByTestId('case-table-bulk-actions-link-icon')).toBeFalsy(); + }); + + it('does show the bulk actions with only delete permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); + const result = appMockRender.render(); + + expect(result.getByTestId('case-table-bulk-actions-link-icon')).toBeInTheDocument(); + }); + + it('does show the bulk actions with update permissions', async () => { + appMockRender = createAppMockRenderer({ permissions: writeCasesPermissions() }); + const result = appMockRender.render(); + + expect(result.getByTestId('case-table-bulk-actions-link-icon')).toBeInTheDocument(); + }); + + it('does not show the bulk actions if there are not selected cases', async () => { + const result = appMockRender.render(); + + expect(result.queryByTestId('case-table-bulk-actions-link-icon')).toBeFalsy(); + expect(result.queryByText('Showing 0 cases')).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx b/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx index fdfcdc17d472c..6daf9cb665116 100644 --- a/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/utility_bar.tsx @@ -6,152 +6,137 @@ */ import React, { FunctionComponent, useCallback, useState } from 'react'; -import { EuiContextMenuPanel } from '@elastic/eui'; -import { CaseStatuses } from '../../../common'; import { - UtilityBar, - UtilityBarAction, - UtilityBarGroup, - UtilityBarSection, - UtilityBarText, -} from '../utility_bar'; + EuiButtonEmpty, + EuiContextMenu, + EuiFlexGroup, + EuiFlexItem, + EuiPopover, + EuiText, + useEuiTheme, +} from '@elastic/eui'; import * as i18n from './translations'; -import { Cases, Case, FilterOptions } from '../../../common/ui/types'; -import { getBulkItems } from '../bulk_actions'; -import { useDeleteCases } from '../../containers/use_delete_cases'; -import { ConfirmDeleteCaseModal } from '../confirm_delete_case'; -import { useUpdateCases } from '../../containers/use_bulk_update_case'; +import { Case } from '../../../common/ui/types'; import { useRefreshCases } from './use_on_refresh_cases'; +import { useBulkActions } from './use_bulk_actions'; +import { useCasesContext } from '../cases_context/use_cases_context'; interface Props { - data: Cases; - enableBulkActions: boolean; - filterOptions: FilterOptions; + isSelectorView?: boolean; + totalCases: number; selectedCases: Case[]; deselectCases: () => void; } -export const getStatusToasterMessage = (status: CaseStatuses, cases: Case[]): string => { - const totalCases = cases.length; - const caseTitle = totalCases === 1 ? cases[0].title : ''; +export const CasesTableUtilityBar: FunctionComponent = React.memo( + ({ isSelectorView, totalCases, selectedCases, deselectCases }) => { + const { euiTheme } = useEuiTheme(); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const togglePopover = useCallback(() => setIsPopoverOpen(!isPopoverOpen), [isPopoverOpen]); + const closePopover = useCallback(() => setIsPopoverOpen(false), []); + const refreshCases = useRefreshCases(); + const { permissions } = useCasesContext(); - if (status === CaseStatuses.open) { - return i18n.REOPENED_CASES({ totalCases, caseTitle }); - } else if (status === CaseStatuses['in-progress']) { - return i18n.MARK_IN_PROGRESS_CASES({ totalCases, caseTitle }); - } else if (status === CaseStatuses.closed) { - return i18n.CLOSED_CASES({ totalCases, caseTitle }); - } - - return ''; -}; - -export const CasesTableUtilityBar: FunctionComponent = ({ - data, - enableBulkActions = false, - filterOptions, - selectedCases, - deselectCases, -}) => { - const [isModalVisible, setIsModalVisible] = useState(false); - const onCloseModal = useCallback(() => setIsModalVisible(false), []); - const refreshCases = useRefreshCases(); - - const { mutate: deleteCases } = useDeleteCases(); - const { mutate: updateCases } = useUpdateCases(); - - const toggleBulkDeleteModal = useCallback((cases: Case[]) => { - setIsModalVisible(true); - }, []); - - const handleUpdateCaseStatus = useCallback( - (status: CaseStatuses) => { - const casesToUpdate = selectedCases.map((theCase) => ({ - status, - id: theCase.id, - version: theCase.version, - })); + const onRefresh = useCallback(() => { + deselectCases(); + refreshCases(); + }, [deselectCases, refreshCases]); - updateCases({ - cases: casesToUpdate, - successToasterTitle: getStatusToasterMessage(status, selectedCases), - }); - }, - [selectedCases, updateCases] - ); - - const getBulkItemsPopoverContent = useCallback( - (closePopover: () => void) => ( - - ), - [selectedCases, filterOptions.status, toggleBulkDeleteModal, handleUpdateCaseStatus] - ); - - const onConfirmDeletion = useCallback(() => { - setIsModalVisible(false); - deleteCases({ - caseIds: selectedCases.map(({ id }) => id), - successToasterTitle: i18n.DELETED_CASES(selectedCases.length), + const { panels, modals } = useBulkActions({ + selectedCases, + onAction: closePopover, + onActionSuccess: onRefresh, }); - }, [deleteCases, selectedCases]); - - const onRefresh = useCallback(() => { - deselectCases(); - refreshCases(); - }, [deselectCases, refreshCases]); - return ( - - - - - {i18n.SHOWING_CASES(data.total ?? 0)} - - - - {enableBulkActions && ( - <> - - {i18n.SHOWING_SELECTED_CASES(selectedCases.length)} - + /** + * At least update or delete permissions needed to show bulk actions. + * Granular permission check for each action is performed + * in the useBulkActions hook. + */ + const showBulkActions = (permissions.update || permissions.delete) && selectedCases.length > 0; - - {i18n.BULK_ACTIONS} - - - )} - + + - {i18n.REFRESH} - - - - {isModalVisible ? ( - - ) : null} - - ); -}; + + {i18n.SHOWING_CASES(totalCases)} + +
+ + + {!isSelectorView && showBulkActions && ( + <> + + + {i18n.SHOWING_SELECTED_CASES(selectedCases.length)} + + + + + {i18n.BULK_ACTIONS} + + } + > + + + + + )} + + + {i18n.REFRESH} + + + + +
+ {modals} + + ); + } +); + CasesTableUtilityBar.displayName = 'CasesTableUtilityBar'; diff --git a/x-pack/plugins/cases/public/components/bulk_actions/index.tsx b/x-pack/plugins/cases/public/components/bulk_actions/index.tsx deleted file mode 100644 index fcf2002f8882c..0000000000000 --- a/x-pack/plugins/cases/public/components/bulk_actions/index.tsx +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiContextMenuItem } from '@elastic/eui'; - -import { CaseStatusWithAllStatus } from '../../../common/ui/types'; -import { CaseStatuses } from '../../../common/api'; -import { statuses } from '../status'; -import * as i18n from './translations'; -import { Case } from '../../containers/types'; - -interface GetBulkItems { - caseStatus: CaseStatusWithAllStatus; - closePopover: () => void; - deleteCasesAction: (cases: Case[]) => void; - selectedCases: Case[]; - updateCaseStatus: (status: CaseStatuses) => void; -} - -export const getBulkItems = ({ - caseStatus, - closePopover, - deleteCasesAction, - selectedCases, - updateCaseStatus, -}: GetBulkItems) => { - let statusMenuItems: JSX.Element[] = []; - - const openMenuItem = ( - { - closePopover(); - updateCaseStatus(CaseStatuses.open); - }} - > - {statuses[CaseStatuses.open].actions.bulk.title} - - ); - - const inProgressMenuItem = ( - { - closePopover(); - updateCaseStatus(CaseStatuses['in-progress']); - }} - > - {statuses[CaseStatuses['in-progress']].actions.bulk.title} - - ); - - const closeMenuItem = ( - { - closePopover(); - updateCaseStatus(CaseStatuses.closed); - }} - > - {statuses[CaseStatuses.closed].actions.bulk.title} - - ); - - switch (caseStatus) { - case CaseStatuses.open: - statusMenuItems = [inProgressMenuItem, closeMenuItem]; - break; - - case CaseStatuses['in-progress']: - statusMenuItems = [openMenuItem, closeMenuItem]; - break; - - case CaseStatuses.closed: - statusMenuItems = [openMenuItem, inProgressMenuItem]; - break; - - default: - break; - } - - return [ - ...statusMenuItems, - { - closePopover(); - deleteCasesAction(selectedCases); - }} - > - {i18n.BULK_ACTION_DELETE_SELECTED} - , - ]; -}; diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx index f492240a8f9b8..0bd582e1cef62 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.tsx @@ -28,6 +28,7 @@ export const CaseViewAlerts = ({ caseData }: CaseViewAlertsProps) => { }), [caseData.comments] ); + const alertRegistrationContexts = useMemo( () => getRegistrationContextFromAlerts(caseData.comments), [caseData.comments] diff --git a/x-pack/plugins/cases/public/components/link_icon/index.tsx b/x-pack/plugins/cases/public/components/link_icon/index.tsx index b33529399db90..6285eceed0dd4 100644 --- a/x-pack/plugins/cases/public/components/link_icon/index.tsx +++ b/x-pack/plugins/cases/public/components/link_icon/index.tsx @@ -79,6 +79,7 @@ export const LinkIcon = React.memo( } return theChild != null && Object.keys(theChild).length > 0 ? (theChild as string) : ''; }, []); + const aria = useMemo(() => { if (ariaLabel) { return ariaLabel; diff --git a/x-pack/plugins/cases/public/components/status/config.ts b/x-pack/plugins/cases/public/components/status/config.ts index 6c5ff18ad977a..520759991605b 100644 --- a/x-pack/plugins/cases/public/components/status/config.ts +++ b/x-pack/plugins/cases/public/components/status/config.ts @@ -19,9 +19,6 @@ export const statuses: Statuses = { label: i18n.OPEN, icon: 'folderOpen' as const, actions: { - bulk: { - title: i18n.BULK_ACTION_OPEN_SELECTED, - }, single: { title: i18n.OPEN_CASE, }, @@ -41,9 +38,6 @@ export const statuses: Statuses = { label: i18n.IN_PROGRESS, icon: 'folderExclamation' as const, actions: { - bulk: { - title: i18n.BULK_ACTION_MARK_IN_PROGRESS, - }, single: { title: i18n.MARK_CASE_IN_PROGRESS, }, @@ -63,9 +57,6 @@ export const statuses: Statuses = { label: i18n.CLOSED, icon: 'folderCheck' as const, actions: { - bulk: { - title: i18n.BULK_ACTION_CLOSE_SELECTED, - }, single: { title: i18n.CLOSE_CASE, }, diff --git a/x-pack/plugins/cases/public/components/status/translations.ts b/x-pack/plugins/cases/public/components/status/translations.ts index 4fe75bbcfac7a..9401209c51c08 100644 --- a/x-pack/plugins/cases/public/components/status/translations.ts +++ b/x-pack/plugins/cases/public/components/status/translations.ts @@ -40,30 +40,9 @@ export const CASE_CLOSED = i18n.translate('xpack.cases.caseView.caseClosed', { defaultMessage: 'Case closed', }); -export const BULK_ACTION_CLOSE_SELECTED = i18n.translate( - 'xpack.cases.caseTable.bulkActions.closeSelectedTitle', - { - defaultMessage: 'Close selected', - } -); - -export const BULK_ACTION_OPEN_SELECTED = i18n.translate( - 'xpack.cases.caseTable.bulkActions.openSelectedTitle', - { - defaultMessage: 'Open selected', - } -); - export const BULK_ACTION_DELETE_SELECTED = i18n.translate( 'xpack.cases.caseTable.bulkActions.deleteSelectedTitle', { defaultMessage: 'Delete selected', } ); - -export const BULK_ACTION_MARK_IN_PROGRESS = i18n.translate( - 'xpack.cases.caseTable.bulkActions.markInProgressTitle', - { - defaultMessage: 'Mark in progress', - } -); diff --git a/x-pack/plugins/cases/public/components/status/types.ts b/x-pack/plugins/cases/public/components/status/types.ts index 0b4a1184633e1..1df8eb781ecc0 100644 --- a/x-pack/plugins/cases/public/components/status/types.ts +++ b/x-pack/plugins/cases/public/components/status/types.ts @@ -18,9 +18,6 @@ export type Statuses = Record< label: string; icon: EuiIconType; actions: { - bulk: { - title: string; - }; single: { title: string; description?: string; diff --git a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar.test.tsx.snap b/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar.test.tsx.snap deleted file mode 100644 index f082dc4023e7a..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar.test.tsx.snap +++ /dev/null @@ -1,30 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UtilityBar it renders 1`] = ` - - - - - Test text - - - - - Test action - - - - - - - Test action - - - - -`; diff --git a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_action.test.tsx.snap b/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_action.test.tsx.snap deleted file mode 100644 index eb20ac217b300..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_action.test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UtilityBarAction it renders 1`] = ` - - Test action - -`; diff --git a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_group.test.tsx.snap b/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_group.test.tsx.snap deleted file mode 100644 index 8ef7ee1cfe842..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_group.test.tsx.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UtilityBarGroup it renders 1`] = ` - - - Test text - - -`; diff --git a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_section.test.tsx.snap b/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_section.test.tsx.snap deleted file mode 100644 index 2fe3b8ac5c7aa..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_section.test.tsx.snap +++ /dev/null @@ -1,11 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UtilityBarSection it renders 1`] = ` - - - - Test text - - - -`; diff --git a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_text.test.tsx.snap b/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_text.test.tsx.snap deleted file mode 100644 index cf635ffa49c4c..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/__snapshots__/utility_bar_text.test.tsx.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`UtilityBarText it renders 1`] = ` - - Test text - -`; diff --git a/x-pack/plugins/cases/public/components/utility_bar/index.ts b/x-pack/plugins/cases/public/components/utility_bar/index.ts deleted file mode 100644 index 830f3cb043ba9..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { UtilityBar } from './utility_bar'; -export { UtilityBarAction } from './utility_bar_action'; -export { UtilityBarGroup } from './utility_bar_group'; -export { UtilityBarSection } from './utility_bar_section'; -export { UtilityBarSpacer } from './utility_bar_spacer'; -export { UtilityBarText } from './utility_bar_text'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/styles.tsx b/x-pack/plugins/cases/public/components/utility_bar/styles.tsx deleted file mode 100644 index 4c4427ba23471..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/styles.tsx +++ /dev/null @@ -1,144 +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 styled, { css } from 'styled-components'; - -/** - * UTILITY BAR - */ - -export interface BarProps { - border?: boolean; -} - -export interface BarSectionProps { - grow?: boolean; -} - -export interface BarGroupProps { - grow?: boolean; -} - -export const Bar = styled.aside.attrs({ - className: 'casesUtilityBar', -})` - ${({ border, theme }) => css` - ${border && - css` - border-bottom: ${theme.eui.euiBorderThin}; - padding-bottom: ${theme.eui.euiSizeS}; - `} - - @media only screen and (min-width: ${theme.eui.euiBreakpoints.l}) { - display: flex; - justify-content: space-between; - } - `} -`; -Bar.displayName = 'Bar'; - -export const BarSection = styled.div.attrs({ - className: 'casesUtilityBar__section', -})` - ${({ grow, theme }) => css` - & + & { - margin-top: ${theme.eui.euiSizeS}; - } - - @media only screen and (min-width: ${theme.eui.euiBreakpoints.m}) { - display: flex; - flex-wrap: wrap; - } - - @media only screen and (min-width: ${theme.eui.euiBreakpoints.l}) { - & + & { - margin-top: 0; - margin-left: ${theme.eui.euiSize}; - } - } - ${grow && - css` - flex: 1; - `} - `} -`; -BarSection.displayName = 'BarSection'; - -export const BarGroup = styled.div.attrs({ - className: 'casesUtilityBar__group', -})` - ${({ grow, theme }) => css` - align-items: flex-start; - display: flex; - flex-wrap: wrap; - - & + & { - margin-top: ${theme.eui.euiSizeS}; - } - - @media only screen and (min-width: ${theme.eui.euiBreakpoints.m}) { - border-right: ${theme.eui.euiBorderThin}; - flex-wrap: nowrap; - margin-right: ${theme.eui.euiSizeM}; - padding-right: ${theme.eui.euiSizeM}; - - & + & { - margin-top: 0; - } - - &:last-child { - border-right: none; - margin-right: 0; - padding-right: 0; - } - } - - & > * { - margin-right: ${theme.eui.euiSize}; - - &:last-child { - margin-right: 0; - } - } - ${grow && - css` - flex: 1; - `} - `} -`; -BarGroup.displayName = 'BarGroup'; - -export const BarText = styled.p.attrs({ - className: 'casesUtilityBar__text', -})` - ${({ theme }) => css` - color: ${theme.eui.euiTextSubduedColor}; - font-size: ${theme.eui.euiFontSizeXS}; - line-height: ${theme.eui.euiLineHeight}; - white-space: nowrap; - `} -`; -BarText.displayName = 'BarText'; - -export const BarAction = styled.div.attrs({ - className: 'casesUtilityBar__action', -})` - ${({ theme }) => css` - font-size: ${theme.eui.euiFontSizeXS}; - line-height: ${theme.eui.euiLineHeight}; - `} -`; -BarAction.displayName = 'BarAction'; - -export const BarSpacer = styled.div.attrs({ - className: 'casesUtilityBar__spacer', -})` - ${() => css` - flex: 1; - `} -`; -BarSpacer.displayName = 'BarSpacer'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx deleted file mode 100644 index 62988a7a9dd76..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.test.tsx +++ /dev/null @@ -1,109 +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 { euiDarkVars } from '@kbn/ui-theme'; -import { mount, shallow } from 'enzyme'; -import React from 'react'; -import { TestProviders } from '../../common/mock'; - -import { - UtilityBar, - UtilityBarAction, - UtilityBarGroup, - UtilityBarSection, - UtilityBarText, -} from '.'; - -describe('UtilityBar', () => { - test('it renders', () => { - const wrapper = shallow( - - - - - {'Test text'} - - - -

{'Test popover'}

}> - {'Test action'} -
-
-
- - - - {'Test action'} - - -
-
- ); - - expect(wrapper.find('UtilityBar')).toMatchSnapshot(); - }); - - test('it applies border styles when border is true', () => { - const wrapper = mount( - - - - - {'Test text'} - - - -

{'Test popover'}

}> - {'Test action'} -
-
-
- - - - {'Test action'} - - -
-
- ); - const casesUtilityBar = wrapper.find('.casesUtilityBar').first(); - - expect(casesUtilityBar).toHaveStyleRule('border-bottom', euiDarkVars.euiBorderThin); - expect(casesUtilityBar).toHaveStyleRule('padding-bottom', euiDarkVars.euiSizeS); - }); - - test('it DOES NOT apply border styles when border is false', () => { - const wrapper = mount( - - - - - {'Test text'} - - - -

{'Test popover'}

}> - {'Test action'} -
-
-
- - - - {'Test action'} - - -
-
- ); - const casesUtilityBar = wrapper.find('.casesUtilityBar').first(); - - expect(casesUtilityBar).not.toHaveStyleRule('border-bottom', euiDarkVars.euiBorderThin); - expect(casesUtilityBar).not.toHaveStyleRule('padding-bottom', euiDarkVars.euiSizeS); - }); -}); diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar.tsx deleted file mode 100644 index ff47459d437be..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { Bar, BarProps } from './styles'; - -interface UtilityBarProps extends BarProps { - children: React.ReactNode; -} - -export const UtilityBar = React.memo(({ border, children }) => ( - {children} -)); - -UtilityBar.displayName = 'UtilityBar'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_action.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_action.test.tsx deleted file mode 100644 index 88977fa9bc587..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_action.test.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { mount, shallow } from 'enzyme'; -import React from 'react'; - -import { TestProviders } from '../../common/mock'; -import { UtilityBarAction } from '.'; - -describe('UtilityBarAction', () => { - test('it renders', () => { - const wrapper = shallow( - - {'Test action'} - - ); - - expect(wrapper.find('UtilityBarAction')).toMatchSnapshot(); - }); - - test('it renders a popover', () => { - const wrapper = mount( - -

{'Test popover'}

}> - {'Test action'} -
-
- ); - - expect(wrapper.find('.euiPopover').first().exists()).toBe(true); - }); -}); diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_action.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_action.tsx deleted file mode 100644 index e5bed87021491..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_action.tsx +++ /dev/null @@ -1,97 +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 { EuiPopover } from '@elastic/eui'; -import React, { useCallback, useState } from 'react'; - -import { LinkIcon, LinkIconProps } from '../link_icon'; -import { BarAction } from './styles'; - -const Popover = React.memo( - ({ children, color, iconSide, iconSize, iconType, popoverContent, disabled, ownFocus }) => { - const [popoverState, setPopoverState] = useState(false); - - const closePopover = useCallback(() => setPopoverState(false), [setPopoverState]); - - return ( - setPopoverState(!popoverState)} - disabled={disabled} - > - {children} - - } - closePopover={() => setPopoverState(false)} - isOpen={popoverState} - repositionOnScroll - > - {popoverContent?.(closePopover)} - - ); - } -); - -Popover.displayName = 'Popover'; - -export interface UtilityBarActionProps extends LinkIconProps { - popoverContent?: (closePopover: () => void) => React.ReactNode; - ownFocus?: boolean; - dataTestSubj?: string; -} - -export const UtilityBarAction = React.memo( - ({ - dataTestSubj, - children, - color, - disabled, - href, - iconSide, - iconSize, - iconType, - ownFocus, - onClick, - popoverContent, - }) => ( - - {popoverContent ? ( - - {children} - - ) : ( - - {children} - - )} - - ) -); - -UtilityBarAction.displayName = 'UtilityBarAction'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_group.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_group.test.tsx deleted file mode 100644 index bf7bb34ab5b64..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_group.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { shallow } from 'enzyme'; -import React from 'react'; - -import { TestProviders } from '../../common/mock'; -import { UtilityBarGroup, UtilityBarText } from '.'; - -describe('UtilityBarGroup', () => { - test('it renders', () => { - const wrapper = shallow( - - - {'Test text'} - - - ); - - expect(wrapper.find('UtilityBarGroup')).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_group.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_group.tsx deleted file mode 100644 index ef83d6effc8a3..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_group.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { BarGroup, BarGroupProps } from './styles'; - -export interface UtilityBarGroupProps extends BarGroupProps { - children: React.ReactNode; -} - -export const UtilityBarGroup = React.memo(({ grow, children }) => ( - {children} -)); - -UtilityBarGroup.displayName = 'UtilityBarGroup'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_section.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_section.test.tsx deleted file mode 100644 index 142cca8fc9e32..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_section.test.tsx +++ /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 { shallow } from 'enzyme'; -import React from 'react'; - -import { TestProviders } from '../../common/mock'; -import { UtilityBarGroup, UtilityBarSection, UtilityBarText } from '.'; - -describe('UtilityBarSection', () => { - test('it renders', () => { - const wrapper = shallow( - - - - {'Test text'} - - - - ); - - expect(wrapper.find('UtilityBarSection')).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_section.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_section.tsx deleted file mode 100644 index c84219cc63488..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_section.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { BarSection, BarSectionProps } from './styles'; - -export interface UtilityBarSectionProps extends BarSectionProps { - children: React.ReactNode; -} - -export const UtilityBarSection = React.memo(({ grow, children }) => ( - {children} -)); - -UtilityBarSection.displayName = 'UtilityBarSection'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_spacer.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_spacer.tsx deleted file mode 100644 index 11b3be8d656e4..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_spacer.tsx +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { BarSpacer } from './styles'; - -export interface UtilityBarSpacerProps { - dataTestSubj?: string; -} - -export const UtilityBarSpacer = React.memo(({ dataTestSubj }) => ( - -)); - -UtilityBarSpacer.displayName = 'UtilityBarSpacer'; diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_text.test.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_text.test.tsx deleted file mode 100644 index afeae82a19e85..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_text.test.tsx +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { shallow } from 'enzyme'; -import React from 'react'; - -import { TestProviders } from '../../common/mock'; -import { UtilityBarText } from '.'; - -describe('UtilityBarText', () => { - test('it renders', () => { - const wrapper = shallow( - - {'Test text'} - - ); - - expect(wrapper.find('UtilityBarText')).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_text.tsx b/x-pack/plugins/cases/public/components/utility_bar/utility_bar_text.tsx deleted file mode 100644 index c0be3cbfbe202..0000000000000 --- a/x-pack/plugins/cases/public/components/utility_bar/utility_bar_text.tsx +++ /dev/null @@ -1,21 +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 { BarText } from './styles'; - -export interface UtilityBarTextProps { - children: string | JSX.Element; - dataTestSubj?: string; -} - -export const UtilityBarText = React.memo(({ children, dataTestSubj }) => ( - {children} -)); - -UtilityBarText.displayName = 'UtilityBarText'; diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts index 2c0ee9bdc2b03..7f90187cd6075 100644 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ b/x-pack/plugins/cases/public/containers/mock.ts @@ -399,7 +399,7 @@ const basicAction = { export const cases: Case[] = [ basicCase, - { ...pushedCase, id: '1', totalComment: 0, comments: [] }, + { ...pushedCase, id: '1', totalComment: 0, comments: [], status: CaseStatuses['in-progress'] }, { ...pushedCase, updatedAt: laterTime, id: '2', totalComment: 0, comments: [] }, { ...basicCase, id: '3', totalComment: 0, comments: [] }, { ...basicCase, id: '4', totalComment: 0, comments: [] }, @@ -557,7 +557,13 @@ export const pushedCaseSnake = { export const casesSnake: CasesResponse = [ basicCaseSnake, - { ...pushedCaseSnake, id: '1', totalComment: 0, comments: [] }, + { + ...pushedCaseSnake, + id: '1', + totalComment: 0, + comments: [], + status: CaseStatuses['in-progress'], + }, { ...pushedCaseSnake, updated_at: laterTime, id: '2', totalComment: 0, comments: [] }, { ...basicCaseSnake, id: '3', totalComment: 0, comments: [] }, { ...basicCaseSnake, id: '4', totalComment: 0, comments: [] }, diff --git a/x-pack/plugins/cases/public/mocks.ts b/x-pack/plugins/cases/public/mocks.ts index 57eead3b80b10..10a4c1f6fd059 100644 --- a/x-pack/plugins/cases/public/mocks.ts +++ b/x-pack/plugins/cases/public/mocks.ts @@ -21,9 +21,13 @@ const uiMock: jest.Mocked = { getRecentCases: jest.fn(), }; +export const openAddToExistingCaseModalMock = jest.fn(); + const hooksMock: jest.Mocked = { getUseCasesAddToNewCaseFlyout: jest.fn(), - getUseCasesAddToExistingCaseModal: jest.fn(), + getUseCasesAddToExistingCaseModal: jest.fn().mockImplementation(() => ({ + open: openAddToExistingCaseModalMock, + })), }; const helpersMock: jest.Mocked = { diff --git a/x-pack/plugins/cases/server/client/cases/types.ts b/x-pack/plugins/cases/server/client/cases/types.ts index c14cc66210614..6d56fa28dca59 100644 --- a/x-pack/plugins/cases/server/client/cases/types.ts +++ b/x-pack/plugins/cases/server/client/cases/types.ts @@ -17,7 +17,7 @@ import { PushToServiceApiParamsITSM as ServiceNowITSMPushToServiceApiParams, PushToServiceApiParamsSIR as ServiceNowSIRPushToServiceApiParams, ServiceNowITSMIncident, -} from '@kbn/stack-connectors-plugin/server/connector_types/cases/servicenow/types'; +} from '@kbn/stack-connectors-plugin/server/connector_types/lib/servicenow/types'; import { UserProfile } from '@kbn/security-plugin/common'; import { CaseResponse, ConnectorMappingsAttributes } from '../../../common/api'; diff --git a/x-pack/plugins/cloud/common/constants.ts b/x-pack/plugins/cloud/common/constants.ts index 09333e3773fe9..fc37906299d14 100644 --- a/x-pack/plugins/cloud/common/constants.ts +++ b/x-pack/plugins/cloud/common/constants.ts @@ -6,7 +6,6 @@ */ export const ELASTIC_SUPPORT_LINK = 'https://cloud.elastic.co/support'; -export const GET_CHAT_USER_DATA_ROUTE_PATH = '/internal/cloud/chat_user'; /** * This is the page for managing your snapshots on Cloud. diff --git a/x-pack/plugins/cloud/kibana.json b/x-pack/plugins/cloud/kibana.json index 51df5d20d81b9..85434abc87ede 100644 --- a/x-pack/plugins/cloud/kibana.json +++ b/x-pack/plugins/cloud/kibana.json @@ -7,7 +7,7 @@ "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["xpack", "cloud"], - "optionalPlugins": ["cloudExperiments", "usageCollection", "home", "security"], + "optionalPlugins": ["usageCollection"], "server": true, "ui": true } diff --git a/x-pack/plugins/cloud/public/index.ts b/x-pack/plugins/cloud/public/index.ts index d50798cb15cd2..ee37f85dfb6a7 100644 --- a/x-pack/plugins/cloud/public/index.ts +++ b/x-pack/plugins/cloud/public/index.ts @@ -13,5 +13,3 @@ export type { CloudSetup, CloudConfigType, CloudStart } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { return new CloudPlugin(initializerContext); } - -export { Chat } from './components'; diff --git a/x-pack/plugins/cloud/public/mocks.tsx b/x-pack/plugins/cloud/public/mocks.tsx index f31596f3930f5..608e826657b73 100644 --- a/x-pack/plugins/cloud/public/mocks.tsx +++ b/x-pack/plugins/cloud/public/mocks.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { CloudStart } from '.'; -import { ServicesProvider } from './services'; function createSetupMock() { return { @@ -19,28 +18,22 @@ function createSetupMock() { deploymentUrl: 'deployment-url', profileUrl: 'profile-url', organizationUrl: 'organization-url', + registerCloudService: jest.fn(), }; } -const config = { - chat: { - enabled: true, - chatURL: 'chat-url', - user: { - id: 'user-id', - email: 'test-user@elastic.co', - jwt: 'identity-jwt', - }, - }, -}; - const getContextProvider: () => React.FC = () => ({ children }) => - {children}; + <>{children}; const createStartMock = (): jest.Mocked => ({ CloudContextProvider: jest.fn(getContextProvider()), + cloudId: 'mock-cloud-id', + isCloudEnabled: true, + deploymentUrl: 'deployment-url', + profileUrl: 'profile-url', + organizationUrl: 'organization-url', }); export const cloudMock = { diff --git a/x-pack/plugins/cloud/public/plugin.test.ts b/x-pack/plugins/cloud/public/plugin.test.ts index 599dee5e707b7..efb566761e22a 100644 --- a/x-pack/plugins/cloud/public/plugin.test.ts +++ b/x-pack/plugins/cloud/public/plugin.test.ts @@ -5,308 +5,18 @@ * 2.0. */ -import { firstValueFrom } from 'rxjs'; -import { Sha256 } from '@kbn/crypto-browser'; -import { nextTick } from '@kbn/test-jest-helpers'; import { coreMock } from '@kbn/core/public/mocks'; -import { homePluginMock } from '@kbn/home-plugin/public/mocks'; -import { securityMock } from '@kbn/security-plugin/public/mocks'; -import { CloudPlugin, type CloudConfigType } from './plugin'; -import { CloudExperimentsPluginSetup } from '@kbn/cloud-experiments-plugin/common'; -import { cloudExperimentsMock } from '@kbn/cloud-experiments-plugin/common/mocks'; +import { CloudPlugin } from './plugin'; const baseConfig = { base_url: 'https://cloud.elastic.co', deployment_url: '/abc123', profile_url: '/user/settings/', organization_url: '/account/', - full_story: { - enabled: false, - }, - chat: { - enabled: false, - }, }; describe('Cloud Plugin', () => { describe('#setup', () => { - describe('setupFullStory', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - const setupPlugin = async ({ config = {} }: { config?: Partial }) => { - const initContext = coreMock.createPluginInitializerContext({ - ...baseConfig, - id: 'cloudId', - ...config, - }); - - const plugin = new CloudPlugin(initContext); - - const coreSetup = coreMock.createSetup(); - - const setup = plugin.setup(coreSetup, {}); - - // Wait for FullStory dynamic import to resolve - await new Promise((r) => setImmediate(r)); - - return { initContext, plugin, setup, coreSetup }; - }; - - test('register the shipper FullStory with correct args when enabled and org_id are set', async () => { - const { coreSetup } = await setupPlugin({ - config: { full_story: { enabled: true, org_id: 'foo' } }, - }); - - expect(coreSetup.analytics.registerShipper).toHaveBeenCalled(); - expect(coreSetup.analytics.registerShipper).toHaveBeenCalledWith(expect.anything(), { - fullStoryOrgId: 'foo', - scriptUrl: '/internal/cloud/100/fullstory.js', - namespace: 'FSKibana', - }); - }); - - it('does not call initializeFullStory when enabled=false', async () => { - const { coreSetup } = await setupPlugin({ - config: { full_story: { enabled: false, org_id: 'foo' } }, - }); - expect(coreSetup.analytics.registerShipper).not.toHaveBeenCalled(); - }); - - it('does not call initializeFullStory when org_id is undefined', async () => { - const { coreSetup } = await setupPlugin({ config: { full_story: { enabled: true } } }); - expect(coreSetup.analytics.registerShipper).not.toHaveBeenCalled(); - }); - }); - - describe('setupTelemetryContext', () => { - const username = '1234'; - const expectedHashedPlainUsername = new Sha256().update(username, 'utf8').digest('hex'); - - beforeEach(() => { - jest.clearAllMocks(); - }); - - const setupPlugin = async ({ - config = {}, - securityEnabled = true, - currentUserProps = {}, - }: { - config?: Partial; - securityEnabled?: boolean; - currentUserProps?: Record | Error; - }) => { - const initContext = coreMock.createPluginInitializerContext({ - ...baseConfig, - ...config, - }); - - const plugin = new CloudPlugin(initContext); - - const coreSetup = coreMock.createSetup(); - const securitySetup = securityMock.createSetup(); - if (currentUserProps instanceof Error) { - securitySetup.authc.getCurrentUser.mockRejectedValue(currentUserProps); - } else { - securitySetup.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser(currentUserProps) - ); - } - - const setup = plugin.setup(coreSetup, securityEnabled ? { security: securitySetup } : {}); - - return { initContext, plugin, setup, coreSetup }; - }; - - test('register the context provider for the cloud user with hashed user ID when security is available', async () => { - const { coreSetup } = await setupPlugin({ - config: { id: 'cloudId' }, - currentUserProps: { username }, - }); - - expect(coreSetup.analytics.registerContextProvider).toHaveBeenCalled(); - - const [{ context$ }] = coreSetup.analytics.registerContextProvider.mock.calls.find( - ([{ name }]) => name === 'cloud_user_id' - )!; - - await expect(firstValueFrom(context$)).resolves.toEqual({ - userId: '5ef112cfdae3dea57097bc276e275b2816e73ef2a398dc0ffaf5b6b4e3af2041', - isElasticCloudUser: false, - }); - }); - - it('user hash includes cloud id', async () => { - const { coreSetup: coreSetup1 } = await setupPlugin({ - config: { id: 'esOrg1' }, - currentUserProps: { username }, - }); - - const [{ context$: context1$ }] = - coreSetup1.analytics.registerContextProvider.mock.calls.find( - ([{ name }]) => name === 'cloud_user_id' - )!; - - const { userId: hashId1 } = (await firstValueFrom(context1$)) as { userId: string }; - expect(hashId1).not.toEqual(expectedHashedPlainUsername); - - const { coreSetup: coreSetup2 } = await setupPlugin({ - config: { full_story: { enabled: true, org_id: 'foo' }, id: 'esOrg2' }, - currentUserProps: { username }, - }); - - const [{ context$: context2$ }] = - coreSetup2.analytics.registerContextProvider.mock.calls.find( - ([{ name }]) => name === 'cloud_user_id' - )!; - - const { userId: hashId2 } = (await firstValueFrom(context2$)) as { userId: string }; - expect(hashId2).not.toEqual(expectedHashedPlainUsername); - - expect(hashId1).not.toEqual(hashId2); - }); - - test('user hash does not include cloudId when user is an Elastic Cloud user', async () => { - const { coreSetup } = await setupPlugin({ - config: { id: 'cloudDeploymentId' }, - currentUserProps: { username, elastic_cloud_user: true }, - }); - - expect(coreSetup.analytics.registerContextProvider).toHaveBeenCalled(); - - const [{ context$ }] = coreSetup.analytics.registerContextProvider.mock.calls.find( - ([{ name }]) => name === 'cloud_user_id' - )!; - - await expect(firstValueFrom(context$)).resolves.toEqual({ - userId: expectedHashedPlainUsername, - isElasticCloudUser: true, - }); - }); - - test('user hash does not include cloudId when not provided', async () => { - const { coreSetup } = await setupPlugin({ - config: {}, - currentUserProps: { username }, - }); - - expect(coreSetup.analytics.registerContextProvider).toHaveBeenCalled(); - - const [{ context$ }] = coreSetup.analytics.registerContextProvider.mock.calls.find( - ([{ name }]) => name === 'cloud_user_id' - )!; - - await expect(firstValueFrom(context$)).resolves.toEqual({ - userId: expectedHashedPlainUsername, - isElasticCloudUser: false, - }); - }); - - test('user hash is undefined when failed to fetch a user', async () => { - const { coreSetup } = await setupPlugin({ - currentUserProps: new Error('failed to fetch a user'), - }); - - expect(coreSetup.analytics.registerContextProvider).toHaveBeenCalled(); - - const [{ context$ }] = coreSetup.analytics.registerContextProvider.mock.calls.find( - ([{ name }]) => name === 'cloud_user_id' - )!; - - await expect(firstValueFrom(context$)).resolves.toEqual({ - userId: undefined, - isElasticCloudUser: false, - }); - }); - }); - - describe('setupChat', () => { - let consoleMock: jest.SpyInstance; - - beforeEach(() => { - consoleMock = jest.spyOn(console, 'debug').mockImplementation(() => {}); - }); - - afterEach(() => { - consoleMock.mockRestore(); - }); - - const setupPlugin = async ({ - config = {}, - securityEnabled = true, - currentUserProps = {}, - isCloudEnabled = true, - failHttp = false, - }: { - config?: Partial; - securityEnabled?: boolean; - currentUserProps?: Record; - isCloudEnabled?: boolean; - failHttp?: boolean; - }) => { - const initContext = coreMock.createPluginInitializerContext({ - ...baseConfig, - id: isCloudEnabled ? 'cloud-id' : null, - ...config, - }); - - const plugin = new CloudPlugin(initContext); - - const coreSetup = coreMock.createSetup(); - const coreStart = coreMock.createStart(); - - if (failHttp) { - coreSetup.http.get.mockImplementation(() => { - throw new Error('HTTP request failed'); - }); - } - - coreSetup.getStartServices.mockResolvedValue([coreStart, {}, undefined]); - - const securitySetup = securityMock.createSetup(); - securitySetup.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser(currentUserProps) - ); - - const setup = plugin.setup(coreSetup, securityEnabled ? { security: securitySetup } : {}); - - return { initContext, plugin, setup, coreSetup }; - }; - - it('chatConfig is not retrieved if cloud is not enabled', async () => { - const { coreSetup } = await setupPlugin({ isCloudEnabled: false }); - expect(coreSetup.http.get).not.toHaveBeenCalled(); - }); - - it('chatConfig is not retrieved if security is not enabled', async () => { - const { coreSetup } = await setupPlugin({ securityEnabled: false }); - expect(coreSetup.http.get).not.toHaveBeenCalled(); - }); - - it('chatConfig is not retrieved if chat is enabled but url is not provided', async () => { - // @ts-expect-error 2741 - const { coreSetup } = await setupPlugin({ config: { chat: { enabled: true } } }); - expect(coreSetup.http.get).not.toHaveBeenCalled(); - }); - - it('chatConfig is not retrieved if internal API fails', async () => { - const { coreSetup } = await setupPlugin({ - config: { chat: { enabled: true, chatURL: 'http://chat.elastic.co' } }, - failHttp: true, - }); - expect(coreSetup.http.get).toHaveBeenCalled(); - expect(consoleMock).toHaveBeenCalled(); - }); - - it('chatConfig is retrieved if chat is enabled and url is provided', async () => { - const { coreSetup } = await setupPlugin({ - config: { chat: { enabled: true, chatURL: 'http://chat.elastic.co' } }, - }); - expect(coreSetup.http.get).toHaveBeenCalled(); - }); - }); - describe('interface', () => { const setupPlugin = () => { const initContext = coreMock.createPluginInitializerContext({ @@ -317,7 +27,7 @@ describe('Cloud Plugin', () => { const plugin = new CloudPlugin(initContext); const coreSetup = coreMock.createSetup(); - const setup = plugin.setup(coreSetup, {}); + const setup = plugin.setup(coreSetup); return { setup }; }; @@ -361,49 +71,10 @@ describe('Cloud Plugin', () => { const { setup } = setupPlugin(); expect(setup.cname).toBe('cloud.elastic.co'); }); - }); - - describe('Set up cloudExperiments', () => { - describe('when cloud ID is not provided in the config', () => { - let cloudExperiments: jest.Mocked; - beforeEach(() => { - const plugin = new CloudPlugin(coreMock.createPluginInitializerContext(baseConfig)); - cloudExperiments = cloudExperimentsMock.createSetupMock(); - plugin.setup(coreMock.createSetup(), { cloudExperiments }); - }); - test('does not call cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser).not.toHaveBeenCalled(); - }); - }); - - describe('when cloud ID is provided in the config', () => { - let cloudExperiments: jest.Mocked; - beforeEach(() => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext({ ...baseConfig, id: 'cloud test' }) - ); - cloudExperiments = cloudExperimentsMock.createSetupMock(); - plugin.setup(coreMock.createSetup(), { cloudExperiments }); - }); - - test('calls cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser).toHaveBeenCalledTimes(1); - }); - - test('the cloud ID is hashed when calling cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser.mock.calls[0][0]).toEqual( - '1acb4a1cc1c3d672a8d826055d897c2623ceb1d4fb07e46d97986751a36b06cf' - ); - }); - - test('specifies the Kibana version when calling cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser.mock.calls[0][1]).toEqual( - expect.objectContaining({ - kibanaVersion: 'version', - }) - ); - }); + it('exposes registerCloudService', () => { + const { setup } = setupPlugin(); + expect(setup.registerCloudService).toBeDefined(); }); }); }); @@ -426,9 +97,8 @@ describe('Cloud Plugin', () => { }) ); const coreSetup = coreMock.createSetup(); - const homeSetup = homePluginMock.createSetupContract(); - plugin.setup(coreSetup, { home: homeSetup }); + plugin.setup(coreSetup); return { coreSetup, plugin }; }; @@ -437,8 +107,7 @@ describe('Cloud Plugin', () => { const { plugin } = startPlugin(); const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - plugin.start(coreStart, { security: securityStart }); + plugin.start(coreStart); expect(coreStart.chrome.setHelpSupportUrl).toHaveBeenCalledTimes(1); expect(coreStart.chrome.setHelpSupportUrl.mock.calls[0]).toMatchInlineSnapshot(` @@ -447,177 +116,5 @@ describe('Cloud Plugin', () => { ] `); }); - - it('does not register custom nav links on anonymous pages', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - coreStart.http.anonymousPaths.isAnonymous.mockReturnValue(true); - - const securityStart = securityMock.createStart(); - securityStart.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser({ - elastic_cloud_user: true, - }) - ); - - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(coreStart.chrome.setCustomNavLink).not.toHaveBeenCalled(); - expect(securityStart.authc.getCurrentUser).not.toHaveBeenCalled(); - }); - - it('registers a custom nav link for cloud users', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - - securityStart.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser({ - elastic_cloud_user: true, - }) - ); - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(coreStart.chrome.setCustomNavLink).toHaveBeenCalledTimes(1); - expect(coreStart.chrome.setCustomNavLink.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "euiIconType": "logoCloud", - "href": "https://cloud.elastic.co/abc123", - "title": "Manage this deployment", - }, - ] - `); - }); - - it('registers a custom nav link when there is an error retrieving the current user', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - securityStart.authc.getCurrentUser.mockRejectedValue(new Error('something happened')); - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(coreStart.chrome.setCustomNavLink).toHaveBeenCalledTimes(1); - expect(coreStart.chrome.setCustomNavLink.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Object { - "euiIconType": "logoCloud", - "href": "https://cloud.elastic.co/abc123", - "title": "Manage this deployment", - }, - ] - `); - }); - - it('does not register a custom nav link for non-cloud users', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - securityStart.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser({ - elastic_cloud_user: false, - }) - ); - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(coreStart.chrome.setCustomNavLink).not.toHaveBeenCalled(); - }); - - it('registers user profile links for cloud users', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - securityStart.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser({ - elastic_cloud_user: true, - }) - ); - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(securityStart.navControlService.addUserMenuLinks).toHaveBeenCalledTimes(1); - expect(securityStart.navControlService.addUserMenuLinks.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "href": "https://cloud.elastic.co/profile/alice", - "iconType": "user", - "label": "Edit profile", - "order": 100, - "setAsProfile": true, - }, - Object { - "href": "https://cloud.elastic.co/org/myOrg", - "iconType": "gear", - "label": "Account & Billing", - "order": 200, - }, - ], - ] - `); - }); - - it('registers profile links when there is an error retrieving the current user', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - securityStart.authc.getCurrentUser.mockRejectedValue(new Error('something happened')); - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(securityStart.navControlService.addUserMenuLinks).toHaveBeenCalledTimes(1); - expect(securityStart.navControlService.addUserMenuLinks.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "href": "https://cloud.elastic.co/profile/alice", - "iconType": "user", - "label": "Edit profile", - "order": 100, - "setAsProfile": true, - }, - Object { - "href": "https://cloud.elastic.co/org/myOrg", - "iconType": "gear", - "label": "Account & Billing", - "order": 200, - }, - ], - ] - `); - }); - - it('does not register profile links for non-cloud users', async () => { - const { plugin } = startPlugin(); - - const coreStart = coreMock.createStart(); - const securityStart = securityMock.createStart(); - securityStart.authc.getCurrentUser.mockResolvedValue( - securityMock.createMockAuthenticatedUser({ - elastic_cloud_user: false, - }) - ); - plugin.start(coreStart, { security: securityStart }); - - await nextTick(); - - expect(securityStart.navControlService.addUserMenuLinks).not.toHaveBeenCalled(); - }); }); }); diff --git a/x-pack/plugins/cloud/public/plugin.tsx b/x-pack/plugins/cloud/public/plugin.tsx index c27668feb09bd..f50f41f3c79cd 100644 --- a/x-pack/plugins/cloud/public/plugin.tsx +++ b/x-pack/plugins/cloud/public/plugin.tsx @@ -6,34 +6,12 @@ */ import React, { FC } from 'react'; -import type { - CoreSetup, - CoreStart, - Plugin, - PluginInitializerContext, - HttpStart, - IBasePath, - AnalyticsServiceSetup, -} from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import useObservable from 'react-use/lib/useObservable'; -import { BehaviorSubject, catchError, from, map, of } from 'rxjs'; +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; -import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; -import { HomePublicPluginSetup } from '@kbn/home-plugin/public'; -import { Sha256 } from '@kbn/crypto-browser'; -import type { CloudExperimentsPluginSetup } from '@kbn/cloud-experiments-plugin/common'; import { registerCloudDeploymentIdAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; -import { - ELASTIC_SUPPORT_LINK, - CLOUD_SNAPSHOTS_PATH, - GET_CHAT_USER_DATA_ROUTE_PATH, -} from '../common/constants'; -import type { GetChatUserDataResponseBody } from '../common/types'; -import { createUserMenuLinks } from './user_menu_links'; +import { ELASTIC_SUPPORT_LINK, CLOUD_SNAPSHOTS_PATH } from '../common/constants'; import { getFullCloudUrl } from './utils'; -import { ChatConfig, ServicesProvider } from './services'; export interface CloudConfigType { id?: string; @@ -47,23 +25,6 @@ export interface CloudConfigType { org_id?: string; eventTypesAllowlist?: string[]; }; - /** Configuration to enable live chat in Cloud-enabled instances of Kibana. */ - chat: { - /** Determines if chat is enabled. */ - enabled: boolean; - /** The URL to the remotely-hosted chat application. */ - chatURL: string; - }; -} - -interface CloudSetupDependencies { - home?: HomePublicPluginSetup; - security?: Pick; - cloudExperiments?: CloudExperimentsPluginSetup; -} - -interface CloudStartDependencies { - security?: SecurityPluginStart; } export interface CloudStart { @@ -71,6 +32,26 @@ export interface CloudStart { * A React component that provides a pre-wired `React.Context` which connects components to Cloud services. */ CloudContextProvider: FC<{}>; + /** + * `true` when Kibana is running on Elastic Cloud. + */ + isCloudEnabled: boolean; + /** + * Cloud ID. Undefined if not running on Cloud. + */ + cloudId?: string; + /** + * The full URL to the deployment management page on Elastic Cloud. Undefined if not running on Cloud. + */ + deploymentUrl?: string; + /** + * The full URL to the user profile page on Elastic Cloud. Undefined if not running on Cloud. + */ + profileUrl?: string; + /** + * The full URL to the organization management page on Elastic Cloud. Undefined if not running on Cloud. + */ + organizationUrl?: string; } export interface CloudSetup { @@ -82,268 +63,93 @@ export interface CloudSetup { organizationUrl?: string; snapshotsUrl?: string; isCloudEnabled: boolean; + registerCloudService: (contextProvider: FC) => void; } -interface SetupFullStoryDeps { - analytics: AnalyticsServiceSetup; - basePath: IBasePath; -} - -interface SetupChatDeps extends Pick { - http: CoreSetup['http']; +interface CloudUrls { + deploymentUrl?: string; + profileUrl?: string; + organizationUrl?: string; + snapshotsUrl?: string; } export class CloudPlugin implements Plugin { private readonly config: CloudConfigType; private readonly isCloudEnabled: boolean; - private chatConfig$ = new BehaviorSubject({ enabled: false }); + private readonly contextProviders: FC[] = []; constructor(private readonly initializerContext: PluginInitializerContext) { this.config = this.initializerContext.config.get(); this.isCloudEnabled = getIsCloudEnabled(this.config.id); } - public setup(core: CoreSetup, { cloudExperiments, home, security }: CloudSetupDependencies) { - this.setupTelemetryContext(core.analytics, security, this.config.id); - - this.setupFullStory({ analytics: core.analytics, basePath: core.http.basePath }).catch((e) => - // eslint-disable-next-line no-console - console.debug(`Error setting up FullStory: ${e.toString()}`) - ); + public setup(core: CoreSetup): CloudSetup { + registerCloudDeploymentIdAnalyticsContext(core.analytics, this.config.id); - const { - id, - cname, - profile_url: profileUrl, - organization_url: organizationUrl, - deployment_url: deploymentUrl, - base_url: baseUrl, - } = this.config; - - if (this.isCloudEnabled && id) { - // We use the Hashed Cloud Deployment ID as the userId in the Cloud Experiments - cloudExperiments?.identifyUser(sha256(id), { - kibanaVersion: this.initializerContext.env.packageInfo.version, - }); - } - - this.setupChat({ http: core.http, security }).catch((e) => - // eslint-disable-next-line no-console - console.debug(`Error setting up Chat: ${e.toString()}`) - ); - - if (home) { - home.environment.update({ cloud: this.isCloudEnabled }); - if (this.isCloudEnabled) { - home.tutorials.setVariable('cloud', { id, baseUrl, profileUrl, deploymentUrl }); - } - } - - const fullCloudDeploymentUrl = getFullCloudUrl(baseUrl, deploymentUrl); - const fullCloudProfileUrl = getFullCloudUrl(baseUrl, profileUrl); - const fullCloudOrganizationUrl = getFullCloudUrl(baseUrl, organizationUrl); - const fullCloudSnapshotsUrl = `${fullCloudDeploymentUrl}/${CLOUD_SNAPSHOTS_PATH}`; + const { id, cname, base_url: baseUrl } = this.config; return { cloudId: id, cname, baseUrl, - deploymentUrl: fullCloudDeploymentUrl, - profileUrl: fullCloudProfileUrl, - organizationUrl: fullCloudOrganizationUrl, - snapshotsUrl: fullCloudSnapshotsUrl, + ...this.getCloudUrls(), isCloudEnabled: this.isCloudEnabled, + registerCloudService: (contextProvider) => { + this.contextProviders.push(contextProvider); + }, }; } - public start(coreStart: CoreStart, { security }: CloudStartDependencies): CloudStart { - const { deployment_url: deploymentUrl, base_url: baseUrl } = this.config; + public start(coreStart: CoreStart): CloudStart { coreStart.chrome.setHelpSupportUrl(ELASTIC_SUPPORT_LINK); - const setLinks = (authorized: boolean) => { - if (!authorized) return; - - if (baseUrl && deploymentUrl) { - coreStart.chrome.setCustomNavLink({ - title: i18n.translate('xpack.cloud.deploymentLinkLabel', { - defaultMessage: 'Manage this deployment', - }), - euiIconType: 'logoCloud', - href: getFullCloudUrl(baseUrl, deploymentUrl), - }); - } - - if (security && this.isCloudEnabled) { - const userMenuLinks = createUserMenuLinks(this.config); - security.navControlService.addUserMenuLinks(userMenuLinks); - } - }; - - this.checkIfAuthorizedForLinks({ http: coreStart.http, security }) - .then(setLinks) - // In the event of an unexpected error, fail *open*. - // Cloud admin console will always perform the actual authorization checks. - .catch(() => setLinks(true)); - - // There's a risk that the request for chat config will take too much time to complete, and the provider - // will maintain a stale value. To avoid this, we'll use an Observable. + // Nest all the registered context providers under the Cloud Services Provider. + // This way, plugins only need to require Cloud's context provider to have all the enriched Cloud services. const CloudContextProvider: FC = ({ children }) => { - const chatConfig = useObservable(this.chatConfig$, { enabled: false }); - return {children}; + return ( + <> + {this.contextProviders.reduce( + (acc, ContextProvider) => ( + {acc} + ), + children + )} + + ); }; + const { deploymentUrl, profileUrl, organizationUrl } = this.getCloudUrls(); + return { CloudContextProvider, + isCloudEnabled: this.isCloudEnabled, + cloudId: this.config.id, + deploymentUrl, + profileUrl, + organizationUrl, }; } public stop() {} - /** - * Determines if the current user should see links back to Cloud. - * This isn't a true authorization check, but rather a heuristic to - * see if the current user is *likely* a cloud deployment administrator. - * - * At this point, we do not have enough information to reliably make this determination, - * but we do know that all cloud deployment admins are superusers by default. - */ - private async checkIfAuthorizedForLinks({ - http, - security, - }: { - http: HttpStart; - security?: SecurityPluginStart; - }) { - if (http.anonymousPaths.isAnonymous(window.location.pathname)) { - return false; - } - // Security plugin is disabled - if (!security) return true; - - // Otherwise check if user is a cloud user. - // If user is not defined due to an unexpected error, then fail *open*. - // Cloud admin console will always perform the actual authorization checks. - const user = await security.authc.getCurrentUser().catch(() => null); - return user?.elastic_cloud_user ?? true; - } - - /** - * If the right config is provided, register the FullStory shipper to the analytics client. - * @param analytics Core's Analytics service's setup contract. - * @param basePath Core's http.basePath helper. - * @private - */ - private async setupFullStory({ analytics, basePath }: SetupFullStoryDeps) { - const { enabled, org_id: fullStoryOrgId, eventTypesAllowlist } = this.config.full_story; - if (!enabled || !fullStoryOrgId) { - return; // do not load any FullStory code in the browser if not enabled - } - - // Keep this import async so that we do not load any FullStory code into the browser when it is disabled. - const { FullStoryShipper } = await import('@kbn/analytics-shippers-fullstory'); - analytics.registerShipper(FullStoryShipper, { - eventTypesAllowlist, - fullStoryOrgId, - // Load an Elastic-internally audited script. Ideally, it should be hosted on a CDN. - scriptUrl: basePath.prepend( - `/internal/cloud/${this.initializerContext.env.packageInfo.buildNum}/fullstory.js` - ), - namespace: 'FSKibana', - }); - } - - /** - * Set up the Analytics context providers. - * @param analytics Core's Analytics service. The Setup contract. - * @param security The security plugin. - * @param cloudId The Cloud Org ID. - * @private - */ - private setupTelemetryContext( - analytics: AnalyticsServiceSetup, - security?: Pick, - cloudId?: string - ) { - registerCloudDeploymentIdAnalyticsContext(analytics, cloudId); - - if (security) { - analytics.registerContextProvider({ - name: 'cloud_user_id', - context$: from(security.authc.getCurrentUser()).pipe( - map((user) => { - if (user.elastic_cloud_user) { - // If the user is managed by ESS, use the plain username as the user ID: - // The username is expected to be unique for these users, - // and it matches how users are identified in the Cloud UI, so it allows us to correlate them. - return { userId: user.username, isElasticCloudUser: true }; - } - - return { - // For the rest of the authentication providers, we want to add the cloud deployment ID to make it unique. - // Especially in the case of Elasticsearch-backed authentication, where users are commonly repeated - // across multiple deployments (i.e.: `elastic` superuser). - userId: cloudId ? `${cloudId}:${user.username}` : user.username, - isElasticCloudUser: false, - }; - }), - // The hashing here is to keep it at clear as possible in our source code that we do not send literal user IDs - map(({ userId, isElasticCloudUser }) => ({ userId: sha256(userId), isElasticCloudUser })), - catchError(() => of({ userId: undefined, isElasticCloudUser: false })) - ), - schema: { - userId: { - type: 'keyword', - _meta: { description: 'The user id scoped as seen by Cloud (hashed)' }, - }, - isElasticCloudUser: { - type: 'boolean', - _meta: { - description: '`true` if the user is managed by ESS.', - }, - }, - }, - }); - } - } - - private async setupChat({ http, security }: SetupChatDeps) { - if (!this.isCloudEnabled) { - return; - } - - const { enabled, chatURL } = this.config.chat; - - if (!security || !enabled || !chatURL) { - return; - } - - try { - const { - email, - id, - token: jwt, - } = await http.get(GET_CHAT_USER_DATA_ROUTE_PATH); + private getCloudUrls(): CloudUrls { + const { + profile_url: profileUrl, + organization_url: organizationUrl, + deployment_url: deploymentUrl, + base_url: baseUrl, + } = this.config; - if (!email || !id || !jwt) { - return; - } + const fullCloudDeploymentUrl = getFullCloudUrl(baseUrl, deploymentUrl); + const fullCloudProfileUrl = getFullCloudUrl(baseUrl, profileUrl); + const fullCloudOrganizationUrl = getFullCloudUrl(baseUrl, organizationUrl); + const fullCloudSnapshotsUrl = `${fullCloudDeploymentUrl}/${CLOUD_SNAPSHOTS_PATH}`; - this.chatConfig$.next({ - enabled, - chatURL, - user: { - email, - id, - jwt, - }, - }); - } catch (e) { - // eslint-disable-next-line no-console - console.debug(`[cloud.chat] Could not retrieve chat config: ${e.res.status} ${e.message}`, e); - } + return { + deploymentUrl: fullCloudDeploymentUrl, + profileUrl: fullCloudProfileUrl, + organizationUrl: fullCloudOrganizationUrl, + snapshotsUrl: fullCloudSnapshotsUrl, + }; } } - -function sha256(str: string) { - return new Sha256().update(str, 'utf8').digest('hex'); -} diff --git a/x-pack/plugins/cloud/server/config.ts b/x-pack/plugins/cloud/server/config.ts index aebbc65e50f18..512542c756798 100644 --- a/x-pack/plugins/cloud/server/config.ts +++ b/x-pack/plugins/cloud/server/config.ts @@ -18,32 +18,11 @@ const apmConfigSchema = schema.object({ ), }); -const fullStoryConfigSchema = schema.object({ - enabled: schema.boolean({ defaultValue: false }), - org_id: schema.conditional( - schema.siblingRef('enabled'), - true, - schema.string({ minLength: 1 }), - schema.maybe(schema.string()) - ), - eventTypesAllowlist: schema.arrayOf(schema.string(), { - defaultValue: ['Loaded Kibana'], - }), -}); - -const chatConfigSchema = schema.object({ - enabled: schema.boolean({ defaultValue: false }), - chatURL: schema.maybe(schema.string()), -}); - const configSchema = schema.object({ apm: schema.maybe(apmConfigSchema), base_url: schema.maybe(schema.string()), - chat: chatConfigSchema, - chatIdentitySecret: schema.maybe(schema.string()), cname: schema.maybe(schema.string()), deployment_url: schema.maybe(schema.string()), - full_story: fullStoryConfigSchema, id: schema.maybe(schema.string()), organization_url: schema.maybe(schema.string()), profile_url: schema.maybe(schema.string()), @@ -54,10 +33,8 @@ export type CloudConfigType = TypeOf; export const config: PluginConfigDescriptor = { exposeToBrowser: { base_url: true, - chat: true, cname: true, deployment_url: true, - full_story: true, id: true, organization_url: true, profile_url: true, diff --git a/x-pack/plugins/cloud/server/mocks.ts b/x-pack/plugins/cloud/server/mocks.ts new file mode 100644 index 0000000000000..557e64edf6cc1 --- /dev/null +++ b/x-pack/plugins/cloud/server/mocks.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 { CloudSetup } from '.'; + +function createSetupMock(): jest.Mocked { + return { + cloudId: 'mock-cloud-id', + instanceSizeMb: 1234, + deploymentId: 'deployment-id', + isCloudEnabled: true, + apm: { + url: undefined, + secretToken: undefined, + }, + }; +} + +export const cloudMock = { + createSetup: createSetupMock, +}; diff --git a/x-pack/plugins/cloud/server/plugin.test.ts b/x-pack/plugins/cloud/server/plugin.test.ts index 05109a4c54816..55be923e98cf8 100644 --- a/x-pack/plugins/cloud/server/plugin.test.ts +++ b/x-pack/plugins/cloud/server/plugin.test.ts @@ -7,111 +7,54 @@ import { coreMock } from '@kbn/core/server/mocks'; import { CloudPlugin } from './plugin'; -import { config } from './config'; -import { securityMock } from '@kbn/security-plugin/server/mocks'; -import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; -import { cloudExperimentsMock } from '@kbn/cloud-experiments-plugin/common/mocks'; -import { CloudExperimentsPluginSetup } from '@kbn/cloud-experiments-plugin/common'; + +const baseConfig = { + base_url: 'https://cloud.elastic.co', + deployment_url: '/abc123', + profile_url: '/user/settings/', + organization_url: '/account/', +}; describe('Cloud Plugin', () => { describe('#setup', () => { - describe('setupSecurity', () => { - it('properly handles missing optional Security dependency if Cloud ID is NOT set.', async () => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext(config.schema.validate({})) - ); + describe('interface', () => { + const setupPlugin = () => { + const initContext = coreMock.createPluginInitializerContext({ + ...baseConfig, + id: 'cloudId', + cname: 'cloud.elastic.co', + }); + const plugin = new CloudPlugin(initContext); - expect(() => - plugin.setup(coreMock.createSetup(), { - usageCollection: usageCollectionPluginMock.createSetupContract(), - }) - ).not.toThrow(); - }); + const coreSetup = coreMock.createSetup(); + const setup = plugin.setup(coreSetup, {}); - it('properly handles missing optional Security dependency if Cloud ID is set.', async () => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext(config.schema.validate({ id: 'my-cloud' })) - ); + return { setup }; + }; - expect(() => - plugin.setup(coreMock.createSetup(), { - usageCollection: usageCollectionPluginMock.createSetupContract(), - }) - ).not.toThrow(); + it('exposes isCloudEnabled', () => { + const { setup } = setupPlugin(); + expect(setup.isCloudEnabled).toBe(true); }); - it('does not notify Security plugin about Cloud environment if Cloud ID is NOT set.', async () => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext(config.schema.validate({})) - ); - - const securityDependencyMock = securityMock.createSetup(); - plugin.setup(coreMock.createSetup(), { - security: securityDependencyMock, - usageCollection: usageCollectionPluginMock.createSetupContract(), - }); - - expect(securityDependencyMock.setIsElasticCloudDeployment).not.toHaveBeenCalled(); + it('exposes cloudId', () => { + const { setup } = setupPlugin(); + expect(setup.cloudId).toBe('cloudId'); }); - it('properly notifies Security plugin about Cloud environment if Cloud ID is set.', async () => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext(config.schema.validate({ id: 'my-cloud' })) - ); - - const securityDependencyMock = securityMock.createSetup(); - plugin.setup(coreMock.createSetup(), { - security: securityDependencyMock, - usageCollection: usageCollectionPluginMock.createSetupContract(), - }); - - expect(securityDependencyMock.setIsElasticCloudDeployment).toHaveBeenCalledTimes(1); + it('exposes instanceSizeMb', () => { + const { setup } = setupPlugin(); + expect(setup.instanceSizeMb).toBeUndefined(); }); - }); - describe('Set up cloudExperiments', () => { - describe('when cloud ID is not provided in the config', () => { - let cloudExperiments: jest.Mocked; - beforeEach(() => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext(config.schema.validate({})) - ); - cloudExperiments = cloudExperimentsMock.createSetupMock(); - plugin.setup(coreMock.createSetup(), { cloudExperiments }); - }); - - test('does not call cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser).not.toHaveBeenCalled(); - }); + it('exposes deploymentId', () => { + const { setup } = setupPlugin(); + expect(setup.deploymentId).toBe('abc123'); }); - describe('when cloud ID is provided in the config', () => { - let cloudExperiments: jest.Mocked; - beforeEach(() => { - const plugin = new CloudPlugin( - coreMock.createPluginInitializerContext(config.schema.validate({ id: 'cloud test' })) - ); - cloudExperiments = cloudExperimentsMock.createSetupMock(); - plugin.setup(coreMock.createSetup(), { cloudExperiments }); - }); - - test('calls cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser).toHaveBeenCalledTimes(1); - }); - - test('the cloud ID is hashed when calling cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser.mock.calls[0][0]).toEqual( - '1acb4a1cc1c3d672a8d826055d897c2623ceb1d4fb07e46d97986751a36b06cf' - ); - }); - - test('specifies the Kibana version when calling cloudExperiments.identifyUser', async () => { - expect(cloudExperiments.identifyUser.mock.calls[0][1]).toEqual( - expect.objectContaining({ - kibanaVersion: 'version', - }) - ); - }); + it('exposes apm', () => { + const { setup } = setupPlugin(); + expect(setup.apm).toStrictEqual({ url: undefined, secretToken: undefined }); }); }); }); diff --git a/x-pack/plugins/cloud/server/plugin.ts b/x-pack/plugins/cloud/server/plugin.ts index d38a57a4d3bab..9cf1a308800a0 100644 --- a/x-pack/plugins/cloud/server/plugin.ts +++ b/x-pack/plugins/cloud/server/plugin.ts @@ -5,24 +5,17 @@ * 2.0. */ -import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; -import { CoreSetup, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; -import type { SecurityPluginSetup } from '@kbn/security-plugin/server'; -import type { CloudExperimentsPluginSetup } from '@kbn/cloud-experiments-plugin/common'; -import { createSHA256Hash } from '@kbn/crypto'; +import type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { registerCloudDeploymentIdAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context'; -import { CloudConfigType } from './config'; +import type { CloudConfigType } from './config'; import { registerCloudUsageCollector } from './collectors'; import { getIsCloudEnabled } from '../common/is_cloud_enabled'; import { parseDeploymentIdFromDeploymentUrl } from './utils'; -import { registerFullstoryRoute } from './routes/fullstory'; -import { registerChatRoute } from './routes/chat'; import { readInstanceSizeMb } from './env'; interface PluginsSetup { usageCollection?: UsageCollectionSetup; - security?: SecurityPluginSetup; - cloudExperiments?: CloudExperimentsPluginSetup; } export interface CloudSetup { @@ -37,52 +30,17 @@ export interface CloudSetup { } export class CloudPlugin implements Plugin { - private readonly logger: Logger; private readonly config: CloudConfigType; - private readonly isDev: boolean; constructor(private readonly context: PluginInitializerContext) { - this.logger = this.context.logger.get(); this.config = this.context.config.get(); - this.isDev = this.context.env.mode.dev; } - public setup( - core: CoreSetup, - { cloudExperiments, usageCollection, security }: PluginsSetup - ): CloudSetup { - this.logger.debug('Setting up Cloud plugin'); + public setup(core: CoreSetup, { usageCollection }: PluginsSetup): CloudSetup { const isCloudEnabled = getIsCloudEnabled(this.config.id); registerCloudDeploymentIdAnalyticsContext(core.analytics, this.config.id); registerCloudUsageCollector(usageCollection, { isCloudEnabled }); - if (isCloudEnabled) { - security?.setIsElasticCloudDeployment(); - } - - if (isCloudEnabled && this.config.id) { - // We use the Cloud ID as the userId in the Cloud Experiments - cloudExperiments?.identifyUser(createSHA256Hash(this.config.id), { - kibanaVersion: this.context.env.packageInfo.version, - }); - } - - if (this.config.full_story.enabled) { - registerFullstoryRoute({ - httpResources: core.http.resources, - packageInfo: this.context.env.packageInfo, - }); - } - - if (this.config.chat.enabled && this.config.chatIdentitySecret) { - registerChatRoute({ - router: core.http.createRouter(), - chatIdentitySecret: this.config.chatIdentitySecret, - security, - isDev: this.isDev, - }); - } - return { cloudId: this.config.id, instanceSizeMb: readInstanceSizeMb(), diff --git a/x-pack/plugins/cloud/tsconfig.json b/x-pack/plugins/cloud/tsconfig.json index d8c8a5c8eca44..ca9ba32ed10b0 100644 --- a/x-pack/plugins/cloud/tsconfig.json +++ b/x-pack/plugins/cloud/tsconfig.json @@ -16,8 +16,5 @@ "references": [ { "path": "../../../src/core/tsconfig.json" }, { "path": "../../../src/plugins/usage_collection/tsconfig.json" }, - { "path": "../../../src/plugins/home/tsconfig.json" }, - { "path": "../cloud_integrations/cloud_experiments/tsconfig.json" }, - { "path": "../security/tsconfig.json" }, ] } diff --git a/x-pack/plugins/cloud/.storybook/decorator.tsx b/x-pack/plugins/cloud_integrations/cloud_chat/.storybook/decorator.tsx similarity index 89% rename from x-pack/plugins/cloud/.storybook/decorator.tsx rename to x-pack/plugins/cloud_integrations/cloud_chat/.storybook/decorator.tsx index 4489b58f75759..3af8d04a598eb 100644 --- a/x-pack/plugins/cloud/.storybook/decorator.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_chat/.storybook/decorator.tsx @@ -7,12 +7,11 @@ import React from 'react'; import { DecoratorFn } from '@storybook/react'; -import { ServicesProvider, CloudServices } from '../public/services'; +import { ServicesProvider, CloudChatServices } from '../public/services'; // TODO: move to a storybook implementation of the service using parameters. -const services: CloudServices = { +const services: CloudChatServices = { chat: { - enabled: true, chatURL: 'https://elasticcloud-production-chat-us-east-1.s3.amazonaws.com/drift-iframe.html', user: { id: 'user-id', diff --git a/x-pack/plugins/cloud/.storybook/index.ts b/x-pack/plugins/cloud_integrations/cloud_chat/.storybook/index.ts similarity index 100% rename from x-pack/plugins/cloud/.storybook/index.ts rename to x-pack/plugins/cloud_integrations/cloud_chat/.storybook/index.ts diff --git a/x-pack/plugins/cloud/.storybook/main.ts b/x-pack/plugins/cloud_integrations/cloud_chat/.storybook/main.ts similarity index 100% rename from x-pack/plugins/cloud/.storybook/main.ts rename to x-pack/plugins/cloud_integrations/cloud_chat/.storybook/main.ts diff --git a/x-pack/plugins/cloud/.storybook/manager.ts b/x-pack/plugins/cloud_integrations/cloud_chat/.storybook/manager.ts similarity index 100% rename from x-pack/plugins/cloud/.storybook/manager.ts rename to x-pack/plugins/cloud_integrations/cloud_chat/.storybook/manager.ts diff --git a/x-pack/plugins/cloud/.storybook/preview.ts b/x-pack/plugins/cloud_integrations/cloud_chat/.storybook/preview.ts similarity index 100% rename from x-pack/plugins/cloud/.storybook/preview.ts rename to x-pack/plugins/cloud_integrations/cloud_chat/.storybook/preview.ts diff --git a/x-pack/plugins/cloud_integrations/cloud_chat/README.md b/x-pack/plugins/cloud_integrations/cloud_chat/README.md new file mode 100755 index 0000000000000..cee3d9f5a6671 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_chat/README.md @@ -0,0 +1,3 @@ +# Cloud Chat + +Integrates with DriftChat in order to provide live support to our Elastic Cloud users. This plugin should only run on Elastic Cloud. diff --git a/x-pack/plugins/cloud_integrations/cloud_chat/common/constants.ts b/x-pack/plugins/cloud_integrations/cloud_chat/common/constants.ts new file mode 100755 index 0000000000000..d7bd133e5b4f9 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_chat/common/constants.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const GET_CHAT_USER_DATA_ROUTE_PATH = '/internal/cloud/chat_user'; diff --git a/x-pack/plugins/cloud/common/types.ts b/x-pack/plugins/cloud_integrations/cloud_chat/common/types.ts similarity index 100% rename from x-pack/plugins/cloud/common/types.ts rename to x-pack/plugins/cloud_integrations/cloud_chat/common/types.ts diff --git a/x-pack/plugins/cloud_integrations/cloud_chat/jest.config.js b/x-pack/plugins/cloud_integrations/cloud_chat/jest.config.js new file mode 100644 index 0000000000000..44f6f241d44d0 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_chat/jest.config.js @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../', + roots: ['/x-pack/plugins/cloud_integrations/cloud_chat'], + coverageDirectory: + '/target/kibana-coverage/jest/x-pack/plugins/cloud_integrations/cloud_chat', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '/x-pack/plugins/cloud_integrations/cloud_chat/{common,public,server}/**/*.{ts,tsx}', + ], +}; diff --git a/x-pack/plugins/cloud_integrations/cloud_chat/kibana.json b/x-pack/plugins/cloud_integrations/cloud_chat/kibana.json new file mode 100755 index 0000000000000..76f7e34e71e56 --- /dev/null +++ b/x-pack/plugins/cloud_integrations/cloud_chat/kibana.json @@ -0,0 +1,15 @@ +{ + "id": "cloudChat", + "version": "1.0.0", + "kibanaVersion": "kibana", + "owner": { + "name": "Kibana Core", + "githubTeam": "kibana-core" + }, + "description": "Chat available on Elastic Cloud deployments for quicker assistance.", + "server": true, + "ui": true, + "configPath": ["xpack", "cloud_integrations", "chat"], + "requiredPlugins": ["cloud"], + "optionalPlugins": ["security"] +} diff --git a/x-pack/plugins/cloud/public/components/chat/chat.stories.tsx b/x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.stories.tsx similarity index 99% rename from x-pack/plugins/cloud/public/components/chat/chat.stories.tsx rename to x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.stories.tsx index 7e673e341cec7..295750ee43039 100644 --- a/x-pack/plugins/cloud/public/components/chat/chat.stories.tsx +++ b/x-pack/plugins/cloud_integrations/cloud_chat/public/components/chat/chat.stories.tsx @@ -68,7 +68,6 @@ export const Component = ({ id, email, chatURL, jwt }: Params) => { return ( {}, onReady, onResize }: Props) => { }} size="xs" > - {i18n.translate('xpack.cloud.chat.hideChatButtonLabel', { + {i18n.translate('xpack.cloudChat.hideChatButtonLabel', { defaultMessage: 'Hide chat', })} @@ -80,7 +80,7 @@ export const Chat = ({ onHide = () => {}, onReady, onResize }: Props) => { {button}